milan jurkulák 2 سال پیش
والد
کامیت
a3f4adfd2a
45فایلهای تغییر یافته به همراه368 افزوده شده و 644 حذف شده
  1. 5 7
      app/src/main/kotlin/org/mjdev/tvapp/ui/pages/AboutPage.kt
  2. 5 7
      app/src/main/kotlin/org/mjdev/tvapp/ui/pages/PluginsPage.kt
  3. 5 7
      app/src/main/kotlin/org/mjdev/tvapp/ui/pages/SubscriptionPage.kt
  4. 0 1
      app/src/main/kotlin/org/mjdev/tvapp/ui/screens/LoadingScreen.kt
  5. 0 5
      buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/AppPlugin.kt
  6. 0 4
      buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/LibPlugin.kt
  7. 2 1
      documentation/release-notes-1.3.1.md
  8. 9 9
      gradle/libs.versions.toml
  9. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/application/TvApplication.kt
  10. 0 2
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ComposeExt.kt
  11. 17 0
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/colors/DynamicColors.kt
  12. 0 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/NavHostControllerEx.kt
  13. 0 2
      tvlib/src/main/kotlin/org/mjdev/tvlib/screen/Screen.kt
  14. 3 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/button/Button.kt
  15. 0 4
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/button/ShareButton.kt
  16. 1 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/Card.kt
  17. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/CardContent.kt
  18. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/ItemCard.kt
  19. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PhotoCard.kt
  20. 232 236
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PreviewCard.kt
  21. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/carousel/BigCarousel.kt
  22. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/carousel/CarouselCard.kt
  23. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/complex/FocusableBox.kt
  24. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/complex/FocusableCard.kt
  25. 4 8
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/gallery/ImmersiveInnerList.kt
  26. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/gridview/TvGridView.kt
  27. 3 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/icon/ConversationReceiptIcon.kt
  28. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/icon/IconAny.kt
  29. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/DrawerSheet.kt
  30. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/NavDrawerContent.kt
  31. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/NavigationRow.kt
  32. 0 189
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/scroll/VerticalScrollbar.kt
  33. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/text/AutoHideEmptyText.kt
  34. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/text/CircleText.kt
  35. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/text/TextAny.kt
  36. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/text/TextWithShadow.kt
  37. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/AppsRow.kt
  38. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/CategoryRow.kt
  39. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/CursorRow.kt
  40. 4 8
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/ErrorMessage.kt
  41. 53 55
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/Loading.kt
  42. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/Tabs.kt
  43. 1 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/UserPic.kt
  44. 2 4
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/dialog/BlurDialog.kt
  45. 1 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/theme/ThemeHelper.kt

+ 5 - 7
app/src/main/kotlin/org/mjdev/tvapp/ui/pages/AboutPage.kt

@@ -1,9 +1,9 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
 package org.mjdev.tvapp.ui.pages
@@ -24,7 +24,6 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardDefaults
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvapp.R
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.ui.components.card.Card
@@ -38,7 +37,6 @@ class AboutPage : Page() {
     override val title: Int = R.string.title_about
     override val icon: ImageVector = Icons.Default.Info
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     @Previews
     @Composable
     override fun Content() {

+ 5 - 7
app/src/main/kotlin/org/mjdev/tvapp/ui/pages/PluginsPage.kt

@@ -1,9 +1,9 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
 package org.mjdev.tvapp.ui.pages
@@ -23,7 +23,6 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardDefaults
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvapp.R
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.ui.components.card.CardContent
@@ -35,7 +34,6 @@ class PluginsPage : Page() {
     override val title: Int = R.string.title_plugins
     override val icon: ImageVector = Icons.Default.SettingsInputComponent
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     @Previews
     @Composable
     override fun Content() {

+ 5 - 7
app/src/main/kotlin/org/mjdev/tvapp/ui/pages/SubscriptionPage.kt

@@ -1,9 +1,9 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
 package org.mjdev.tvapp.ui.pages
@@ -23,7 +23,6 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardDefaults
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvapp.R
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.ui.components.card.Card
@@ -36,7 +35,6 @@ class SubscriptionPage : Page() {
     override val title: Int = R.string.title_subscription
     override val icon: ImageVector = Icons.Default.ShoppingCart
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     @Previews
     @Composable
     override fun Content() {

+ 0 - 1
app/src/main/kotlin/org/mjdev/tvapp/ui/screens/LoadingScreen.kt

@@ -29,7 +29,6 @@ class LoadingScreen : Screen() {
     override val immersive: Boolean = true
     override val showOnce: Boolean = true
 
-//    @OptIn(ExperimentalTvMaterial3Api::class)
     @Previews
     @Composable
     override fun Content() {

+ 0 - 5
buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/AppPlugin.kt

@@ -56,7 +56,6 @@ import org.mjdev.gradle.tasks.CleanProjectTask
 import org.kordamp.gradle.plugin.markdown.MarkdownPlugin
 import org.mjdev.gradle.extensions.assembleTasks
 import org.mjdev.gradle.extensions.cleanProjectTask
-import org.mjdev.gradle.extensions.isAndroidStudio
 import org.mjdev.gradle.extensions.markDownToHtmlTask
 import org.mjdev.gradle.extensions.variants
 import org.mjdev.gradle.extensions.zipReleaseCreateTask
@@ -325,8 +324,6 @@ class AppPlugin : BasePlugin() {
             implementation(libs.androidx.compose.lifecycle.viewmodel)
             // navigation
             implementation(libs.androidx.compose.navigation)
-            // todo remove, dynamic background & colors
-            implementation(libs.androidx.material3)
             // previews
             debugImplementation(libs.androidx.customview.poolingcontainer)
             // foundation
@@ -400,8 +397,6 @@ class AppPlugin : BasePlugin() {
             implementation(libs.jsoup)
             // dm
             implementation(libs.dailymotion.sdk.android)
-            // dynamic theme
-            implementation(libs.android.material)
             // widget
             implementation(libs.androidx.glance.appwidget)
             implementation(libs.androidx.glance.material)

+ 0 - 4
buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/LibPlugin.kt

@@ -189,8 +189,6 @@ class LibPlugin : BasePlugin() {
             implementation(libs.androidx.compose.lifecycle.viewmodel)
             // navigation
             implementation(libs.androidx.compose.navigation)
-            // todo remove, dynamic background & colors
-            implementation(libs.androidx.material3)
             // previews
             debugImplementation(libs.androidx.customview.poolingcontainer)
             // foundation
@@ -264,8 +262,6 @@ class LibPlugin : BasePlugin() {
             implementation(libs.jsoup)
             // dm
             implementation(libs.dailymotion.sdk.android)
-            // dynamic theme
-            implementation(libs.android.material)
             // widget
             implementation(libs.androidx.glance.appwidget)
             implementation(libs.androidx.glance.material)

+ 2 - 1
documentation/release-notes-1.3.1.md

@@ -1,7 +1,8 @@
-## Release notes 1.0.0 - 13. 6. 2024, 11:27:13
+## Release notes 1.0.0 - 14. 6. 2024, 9:32:29
 
 * 13.06.2024
 
+* [milan jurkulák] : tv lib update 
 * [milan jurkulák] : dagger removal, kodein pre-implementation  
 
 * 22.05.2024

+ 9 - 9
gradle/libs.versions.toml

@@ -3,21 +3,21 @@
 #
 accompanist-permissions = "0.34.0"
 aescrypt = "0.0.1"
-android-material = "1.12.0"
+#android-material = "1.12.0"
 androidsvg-aar = "1.4"
 #
 androidx-activity-compose = "1.9.0"
-androidx-compose-bom = "2024.05.00"
+androidx-compose-bom = "2024.06.00"
 androidx-customview-poolingcontainer = "1.0.0"
 androidx-espresso-core = "3.5.1"
 androidx-exifinterface = "1.3.7"
-androidx-foundation = "1.6.7"
-androidx-glance-appwidget = "1.0.0"
+androidx-foundation = "1.6.8"
+androidx-glance-appwidget = "1.1.0"
 androidx-junit = "1.1.5"
 androidx-ktx = "1.13.1"
-androidx-lifecycle-viewmodel-compose = "2.8.1"
-androidx-material-icons-extended = "1.6.7"
-androidx-material3 = "1.2.1"
+androidx-lifecycle-viewmodel-compose = "2.8.2"
+androidx-material-icons-extended = "1.6.8"
+#androidx-material3 = "1.2.1"
 androidx-media3 = "1.3.1"
 androidx-navigation-compose = "2.7.7"
 androidx-palette-ktx = "1.0.0"
@@ -84,7 +84,7 @@ accompanist-permissions = { module = "com.google.accompanist:accompanist-permiss
 aescrypt = { module = "com.scottyab:aescrypt", version.ref = "aescrypt" }
 #android-jwtdecode = { module = "com.auth0.android:jwtdecode", version.ref = "jwtdecode" }
 # material
-android-material = { module = "com.google.android.material:material", version.ref = "android-material" }
+#android-material = { module = "com.google.android.material:material", version.ref = "android-material" }
 androidsvg-aar = { module = "com.caverock:androidsvg-aar", version.ref = "androidsvg-aar" }
 androidx-compose-activity = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" }
 # compose
@@ -104,7 +104,7 @@ androidx-glance-material3 = { module = "androidx.glance:glance-material3", versi
 androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" }
 androidx-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-ktx" }
 androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "androidx-material-icons-extended" }
-androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "androidx-material3" }
+#androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "androidx-material3" }
 # media
 androidx-media3-cast = { module = "androidx.media3:media3-cast", version.ref = "androidx-media3" }
 androidx-media3-common = { module = "androidx.media3:media3-common", version.ref = "androidx-media3" }

+ 1 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/application/TvApplication.kt

@@ -11,8 +11,8 @@
 package org.mjdev.tvlib.application
 
 import android.app.Application
-import com.google.android.material.color.DynamicColors
 import org.mjdev.tvlib.events.EventBusInitializer
+import org.mjdev.tvlib.helpers.colors.DynamicColors
 
 open class TvApplication : Application() {
     override fun onCreate() {

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

@@ -190,11 +190,9 @@ object ComposeExt {
         else -> Exception(this.toString())
     }
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     val DrawerState.isOpen: Boolean
         get() = currentValue == DrawerValue.Open
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     val DrawerState.isClosed: Boolean
         get() = currentValue == DrawerValue.Closed
 

+ 17 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/colors/DynamicColors.kt

@@ -0,0 +1,17 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.helpers.colors
+
+import android.app.Application
+
+// todo
+object DynamicColors {
+    fun applyToActivitiesIfAvailable(application: Application) {
+    }
+}

+ 0 - 7
tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/NavHostControllerEx.kt

@@ -32,7 +32,6 @@ import androidx.lifecycle.LifecycleRegistry
 import androidx.navigation.NavHostController
 import androidx.tv.material3.DrawerState
 import androidx.tv.material3.DrawerValue
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.extensions.ListExt.addUnique
 import java.io.Serializable
 
@@ -44,10 +43,8 @@ class NavHostControllerEx(
     context
 ), LifecycleOwner, DefaultLifecycleObserver {
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     val settingsDrawerState: DrawerState = DrawerState(DrawerValue.Closed)
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     val menuDrawerState: DrawerState = DrawerState(DrawerValue.Closed)
 
     val menuState: MutableState<Boolean> = mutableStateOf(true)
@@ -122,22 +119,18 @@ class NavHostControllerEx(
         }
     }
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     fun openSettings() {
         settingsDrawerState.setValue(DrawerValue.Open)
     }
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     fun closeSettings() {
         settingsDrawerState.setValue(DrawerValue.Closed)
     }
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     fun openMenu() {
         menuDrawerState.setValue(DrawerValue.Open)
     }
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     fun closeMenu() {
         menuDrawerState.setValue(DrawerValue.Closed)
     }

+ 0 - 2
tvlib/src/main/kotlin/org/mjdev/tvlib/screen/Screen.kt

@@ -29,7 +29,6 @@ import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.unit.sp
 import androidx.navigation.NamedNavArgument
 import androidx.navigation.NavBackStackEntry
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Text
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ModifierExt.onlyPortrait
@@ -80,7 +79,6 @@ open class Screen {
         }
     }
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     @Composable
     open fun Content() {
         Column(

+ 3 - 7
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/button/Button.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -31,7 +31,6 @@ import androidx.tv.material3.Button
 import androidx.tv.material3.ButtonDefaults
 import androidx.tv.material3.ButtonGlow
 import androidx.tv.material3.ButtonScale
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Glow
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusState
@@ -39,7 +38,6 @@ import org.mjdev.tvlib.ui.components.text.TextAny
 
 @Suppress("UNUSED_PARAMETER", "PreviewShouldNotBeCalledRecursively")
 @SuppressLint("ModifierParameter")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun Button(
@@ -57,6 +55,7 @@ fun Button(
     glow: ButtonGlow = ButtonDefaults.NO_GLOW,
     scale: ButtonScale = ButtonDefaults.NO_SCALE,
     focusState: MutableState<FocusState> = rememberFocusState(),
+    onClick: (() -> Unit)? = null,
     content: @Composable RowScope.() -> Unit = {
         TextAny(
             text = text,
@@ -64,8 +63,7 @@ fun Button(
             textAlign = TextAlign.Center,
             maxLines = 1
         )
-    },
-    onClick: (() -> Unit)? = null,
+    }
 ) = Button(
     modifier = modifier
         .border(BorderStroke(borderSize, borderColor), shape)
@@ -79,7 +77,6 @@ fun Button(
     content = content
 )
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 val ButtonDefaults.NO_GLOW
     get() = glow(
         glow = Glow.None,
@@ -87,7 +84,6 @@ val ButtonDefaults.NO_GLOW
         pressedGlow = Glow.None
     )
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 val ButtonDefaults.NO_SCALE
     get() = scale(
         scale = 1f,

+ 0 - 4
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/button/ShareButton.kt

@@ -10,10 +10,8 @@ package org.mjdev.tvlib.ui.components.button
 
 import android.content.Intent
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Share
 import androidx.compose.runtime.Composable
@@ -22,13 +20,11 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.unit.dp
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Icon
 import androidx.tv.material3.Text
 import org.mjdev.tvlib.annotations.Previews
 
 @Previews
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 fun ShareButton(
     modifier: Modifier = Modifier,

+ 1 - 7
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/Card.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -34,7 +34,6 @@ import androidx.tv.material3.CardDefaults
 import androidx.tv.material3.CardGlow
 import androidx.tv.material3.CardScale
 import androidx.tv.material3.CardShape
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Glow
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.rememberMutableInteractionSource
@@ -42,7 +41,6 @@ import org.mjdev.tvlib.extensions.ModifierExt.conditional
 import org.mjdev.tvlib.extensions.ModifierExt.tvAspectRatio
 
 @SuppressLint("ModifierParameter")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun Card(
@@ -84,7 +82,6 @@ fun Card(
     )
 }
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 val CardDefaults.NO_BORDER: CardBorder
     @Composable
     get() = border(
@@ -94,7 +91,6 @@ val CardDefaults.NO_BORDER: CardBorder
     )
 
 @Suppress("unused")
-@OptIn(ExperimentalTvMaterial3Api::class)
 val CardDefaults.NO_GLOW: CardGlow
     @Composable
     get() = glow(
@@ -103,7 +99,6 @@ val CardDefaults.NO_GLOW: CardGlow
         pressedGlow = Glow.None
     )
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 fun CardDefaults.colorFocusGlow(
     focusColor: Color = Color.Green,
@@ -125,7 +120,6 @@ fun CardDefaults.colorFocusGlow(
 )
 
 @Suppress("UNUSED_PARAMETER")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 fun CardDefaults.colorFocusBorder(
     colorFocused: Color = Color.Green,

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/CardContent.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -13,13 +13,11 @@ import androidx.compose.foundation.layout.Column
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.graphicsLayer
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.MaterialTheme
 import androidx.tv.material3.ProvideTextStyle
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.ui.components.text.AutoHideEmptyText
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun CardContent(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/ItemCard.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -28,7 +28,6 @@ import androidx.tv.material3.CardDefaults
 import androidx.tv.material3.CardGlow
 import androidx.tv.material3.CardScale
 import androidx.tv.material3.CardShape
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.R
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.computeCardWidth
@@ -41,7 +40,6 @@ import org.mjdev.tvlib.ui.components.complex.FocusableCard
 import org.mjdev.tvlib.ui.components.image.ImageAny
 
 @SuppressLint("ModifierParameter")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun ItemCard(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PhotoCard.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -24,7 +24,6 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardDefaults
 import androidx.tv.material3.CardScale
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.R
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.computeCardWidth
@@ -38,7 +37,6 @@ import org.mjdev.tvlib.ui.components.image.ImageAny
 import org.mjdev.tvlib.ui.components.image.PhotoImage
 
 @SuppressLint("ModifierParameter")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun PhotoCard(

+ 232 - 236
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PreviewCard.kt

@@ -1,238 +1,234 @@
-///*
-// * 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.card
-//
-//import android.graphics.Bitmap
-//import android.media.MediaMetadataRetriever
-//import androidx.compose.animation.Crossfade
-//import androidx.compose.animation.core.tween
-//import androidx.compose.foundation.Image
-//import androidx.compose.foundation.background
-//import androidx.compose.foundation.border
-//import androidx.compose.foundation.layout.Box
-//import androidx.compose.foundation.layout.fillMaxSize
-//import androidx.compose.material3.CircularProgressIndicator
-//import androidx.compose.runtime.*
-//import androidx.compose.runtime.saveable.rememberSaveable
-//import androidx.compose.ui.Alignment
-//import androidx.compose.ui.Modifier
-//import androidx.compose.ui.graphics.Color
-//import androidx.compose.ui.layout.ContentScale
-//import androidx.compose.ui.platform.LocalContext
-//import androidx.compose.ui.platform.LocalLifecycleOwner
-//import androidx.compose.ui.unit.dp
-//import androidx.compose.ui.viewinterop.AndroidView
-//import androidx.lifecycle.Lifecycle
-//import androidx.lifecycle.LifecycleEventObserver
-//import androidx.media3.common.C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
-//import androidx.media3.common.MediaItem
-//import androidx.media3.common.Player
-//import androidx.media3.common.Player.Listener
-//import androidx.media3.common.Player.REPEAT_MODE_ONE
-//import androidx.media3.common.util.UnstableApi
-//import androidx.media3.datasource.DataSource
-//import androidx.media3.datasource.DefaultHttpDataSource
-//import androidx.media3.exoplayer.ExoPlayer
-//import androidx.media3.exoplayer.source.ClippingMediaSource
-//import androidx.media3.exoplayer.source.MediaSource
-//import androidx.media3.exoplayer.source.ProgressiveMediaSource
-//import androidx.media3.ui.AspectRatioFrameLayout
-//import androidx.media3.ui.PlayerView
-//import androidx.tv.material3.ExperimentalTvMaterial3Api
-//import coil.compose.AsyncImage
-//import coil.compose.rememberAsyncImagePainter
-//import kotlinx.coroutines.Dispatchers
-//import kotlinx.coroutines.withContext
-//import org.mjdev.tvlib.annotations.Previews
-//import org.mjdev.tvlib.extensions.ModifierExt.tvAspectRatio
-//
-//// todo
-//@OptIn(ExperimentalTvMaterial3Api::class)
-//@Suppress("unused")
-//@UnstableApi
-//@Previews
-//@Composable
-//fun PreviewCard(
-//    modifier: Modifier = Modifier,
-//    videoUrl: String = "",
-//    aspectRatio: Float? = 16f / 9f,
-//    hasFocus: Boolean = false,
-//    clipStartPosition: Long = 2000000,
-//    clipEndPosition: Long = 8000000,
-//    thumbnailFrame: Long = 5000000,
-//    thumbnailUrl: String? = null
-//) {
-//    Card(
-//        modifier = modifier.tvAspectRatio(aspectRatio)
-//    ) {
-//        val context = LocalContext.current
-//        var currentlyPlaying by remember(videoUrl) { mutableStateOf(false) }
-//        var isBuffering by remember(videoUrl) { mutableStateOf(true) }
-//        var thumbnailBitmap by rememberSaveable(videoUrl) {
-//            mutableStateOf<Bitmap?>(null)
-//        }
-//        val exoPlayer = remember(videoUrl) {
-//            ExoPlayer.Builder(context).build().apply {
-//                repeatMode = REPEAT_MODE_ONE
-//                volume = 0f
-//                videoScalingMode = VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
-//            }
-//        }
-//        exoPlayer.addListener(object : Listener {
-//            override fun onPlaybackStateChanged(playbackState: Int) {
-//                super.onPlaybackStateChanged(playbackState)
-//                currentlyPlaying = playbackState == Player.STATE_READY
-//            }
-//        })
-//        LaunchedEffect(key1 = videoUrl) {
-//            val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
-//            val mediaSource: MediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
-//                .createMediaSource(MediaItem.fromUri(videoUrl))
-//            val clip = ClippingMediaSource(mediaSource, clipStartPosition, clipEndPosition)
-//            exoPlayer.setMediaSource(clip)
-//            exoPlayer.prepare()
-//            exoPlayer.playWhenReady = true
-//            exoPlayer.addListener(object : Listener {
-//                override fun onPlaybackStateChanged(playbackState: Int) {
-//                    super.onPlaybackStateChanged(playbackState)
-//                    isBuffering = playbackState == Player.STATE_BUFFERING
-//                }
-//            })
-//        }
-//        val lifecycleOwner by rememberUpdatedState(LocalLifecycleOwner.current)
-//        DisposableEffect(lifecycleOwner) {
-//            val lifecycle = lifecycleOwner.lifecycle
-//            val observer = LifecycleEventObserver { _, event ->
-//                when (event) {
-//                    Lifecycle.Event.ON_PAUSE -> {
-//                        exoPlayer.playWhenReady = false
-//                    }
-//
-//                    Lifecycle.Event.ON_RESUME -> {
-//                        exoPlayer.playWhenReady = true
-//                    }
-//
-//                    Lifecycle.Event.ON_DESTROY -> {
-//                        exoPlayer.run {
-//                            stop()
-//                            release()
-//                        }
-//                    }
-//
-//                    else -> {}
-//                }
-//            }
-//            lifecycle.addObserver(observer)
-//            onDispose {
-//                lifecycle.removeObserver(observer)
-//            }
-//        }
-//        Crossfade(targetState = hasFocus, animationSpec = tween(durationMillis = 700),
-//            label = ""
-//        ) { focused ->
-//            if (focused) {
-//                Box {
-//                    AndroidView(
-//                        modifier = Modifier
-//                            .fillMaxSize(),
-//                        factory = {
-//                            PlayerView(context).apply {
-//                                player = exoPlayer
-//                                useController = false
-//                                resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
-//                                controllerAutoShow = false
-//                                setKeepContentOnPlayerReset(true)
-//                                setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
-//                            }
-//                        }
-//                    )
-//                    if (isBuffering) {
-//                        PreviewThumbnail(
-//                            thumbnailUrl,
-//                            thumbnailBitmap,
-//                            thumbnailFrame,
-//                            videoUrl,
-//                            true
-//                        ) {
-//                            thumbnailBitmap = it
-//                        }
-//                    }
-//                }
-//            } else {
-//                PreviewThumbnail(thumbnailUrl, thumbnailBitmap, thumbnailFrame, videoUrl, false) {
-//                    thumbnailBitmap = it
-//                }
-//            }
-//        }
-//    }
-//}
-//
-//@Previews
-//@Composable
-//fun PreviewThumbnail(
-//    thumbnail: String? = "",
-//    thumbnailBitmap: Bitmap? = null,
-//    thumbnailFrame: Long = 0,
-//    videoUrl: String = "",
-//    isLoadingVideo: Boolean = false,
-//    onBitmapLoaded: (bitmap: Bitmap?) -> Unit = {}
-//) {
-//    if (thumbnail == null && thumbnailBitmap == null) {
-//        LaunchedEffect(videoUrl) {
-//            withContext(Dispatchers.IO) {
-//                MediaMetadataRetriever().apply {
-//                    setDataSource(videoUrl, HashMap())
-//                }.also {
-//                    val result = it.getFrameAtTime(
-//                        thumbnailFrame,
-//                        MediaMetadataRetriever.OPTION_CLOSEST_SYNC
-//                    )
-//                    onBitmapLoaded(result)
-//                    it.release()
-//                }
-//            }
-//        }
-//        Box(
-//            modifier = Modifier
-//                .fillMaxSize()
-//                .background(Color.Black)
-//                .border(2.dp, Color.White.copy(alpha = 0.4f)),
-//            contentAlignment = Alignment.Center
-//        ) {
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.ui.components.card
+
+import android.graphics.Bitmap
+import android.media.MediaMetadataRetriever
+import androidx.compose.animation.Crossfade
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.*
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
+import androidx.media3.common.C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
+import androidx.media3.common.MediaItem
+import androidx.media3.common.Player
+import androidx.media3.common.Player.Listener
+import androidx.media3.common.Player.REPEAT_MODE_ONE
+import androidx.media3.common.util.UnstableApi
+import androidx.media3.datasource.DataSource
+import androidx.media3.datasource.DefaultHttpDataSource
+import androidx.media3.exoplayer.ExoPlayer
+import androidx.media3.exoplayer.source.ClippingMediaSource
+import androidx.media3.exoplayer.source.MediaSource
+import androidx.media3.exoplayer.source.ProgressiveMediaSource
+import androidx.media3.ui.AspectRatioFrameLayout
+import androidx.media3.ui.PlayerView
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.mjdev.tvlib.annotations.Previews
+import org.mjdev.tvlib.extensions.ModifierExt.tvAspectRatio
+import org.mjdev.tvlib.ui.components.image.ImageAny
+
+// todo
+@Suppress("unused")
+@UnstableApi
+@Previews
+@Composable
+fun PreviewCard(
+    modifier: Modifier = Modifier,
+    videoUrl: String = "",
+    aspectRatio: Float? = 16f / 9f,
+    hasFocus: Boolean = false,
+    clipStartPosition: Long = 2000000,
+    clipEndPosition: Long = 8000000,
+    thumbnailFrame: Long = 5000000,
+    thumbnailUrl: String? = null
+) {
+    Card(
+        modifier = modifier.tvAspectRatio(aspectRatio)
+    ) {
+        val context = LocalContext.current
+        var currentlyPlaying by remember(videoUrl) { mutableStateOf(false) }
+        var isBuffering by remember(videoUrl) { mutableStateOf(true) }
+        var thumbnailBitmap by rememberSaveable(videoUrl) {
+            mutableStateOf<Bitmap?>(null)
+        }
+        val exoPlayer = remember(videoUrl) {
+            ExoPlayer.Builder(context).build().apply {
+                repeatMode = REPEAT_MODE_ONE
+                volume = 0f
+                videoScalingMode = VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
+            }
+        }
+        exoPlayer.addListener(object : Listener {
+            override fun onPlaybackStateChanged(playbackState: Int) {
+                super.onPlaybackStateChanged(playbackState)
+                currentlyPlaying = playbackState == Player.STATE_READY
+            }
+        })
+        LaunchedEffect(key1 = videoUrl) {
+            val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
+            val mediaSource: MediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
+                .createMediaSource(MediaItem.fromUri(videoUrl))
+            val clip = ClippingMediaSource(mediaSource, clipStartPosition, clipEndPosition)
+            exoPlayer.setMediaSource(clip)
+            exoPlayer.prepare()
+            exoPlayer.playWhenReady = true
+            exoPlayer.addListener(object : Listener {
+                override fun onPlaybackStateChanged(playbackState: Int) {
+                    super.onPlaybackStateChanged(playbackState)
+                    isBuffering = playbackState == Player.STATE_BUFFERING
+                }
+            })
+        }
+        val lifecycleOwner by rememberUpdatedState(LocalLifecycleOwner.current)
+        DisposableEffect(lifecycleOwner) {
+            val lifecycle = lifecycleOwner.lifecycle
+            val observer = LifecycleEventObserver { _, event ->
+                when (event) {
+                    Lifecycle.Event.ON_PAUSE -> {
+                        exoPlayer.playWhenReady = false
+                    }
+
+                    Lifecycle.Event.ON_RESUME -> {
+                        exoPlayer.playWhenReady = true
+                    }
+
+                    Lifecycle.Event.ON_DESTROY -> {
+                        exoPlayer.run {
+                            stop()
+                            release()
+                        }
+                    }
+
+                    else -> {}
+                }
+            }
+            lifecycle.addObserver(observer)
+            onDispose {
+                lifecycle.removeObserver(observer)
+            }
+        }
+        Crossfade(
+            targetState = hasFocus, animationSpec = tween(durationMillis = 700),
+            label = ""
+        ) { focused ->
+            if (focused) {
+                Box {
+                    AndroidView(
+                        modifier = Modifier
+                            .fillMaxSize(),
+                        factory = {
+                            PlayerView(context).apply {
+                                player = exoPlayer
+                                useController = false
+                                resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
+                                controllerAutoShow = false
+                                setKeepContentOnPlayerReset(true)
+                                setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
+                            }
+                        }
+                    )
+                    if (isBuffering) {
+                        PreviewThumbnail(
+                            thumbnailUrl,
+                            thumbnailBitmap,
+                            thumbnailFrame,
+                            videoUrl,
+                            true
+                        ) {
+                            thumbnailBitmap = it
+                        }
+                    }
+                }
+            } else {
+                PreviewThumbnail(thumbnailUrl, thumbnailBitmap, thumbnailFrame, videoUrl, false) {
+                    thumbnailBitmap = it
+                }
+            }
+        }
+    }
+}
+
+@Previews
+@Composable
+fun PreviewThumbnail(
+    thumbnail: String? = "",
+    thumbnailBitmap: Bitmap? = null,
+    thumbnailFrame: Long = 0,
+    videoUrl: String = "",
+    isLoadingVideo: Boolean = false,
+    onBitmapLoaded: (bitmap: Bitmap?) -> Unit = {}
+) {
+    if (thumbnail == null && thumbnailBitmap == null) {
+        LaunchedEffect(videoUrl) {
+            withContext(Dispatchers.IO) {
+                MediaMetadataRetriever().apply {
+                    setDataSource(videoUrl, HashMap())
+                }.also {
+                    val result = it.getFrameAtTime(
+                        thumbnailFrame,
+                        MediaMetadataRetriever.OPTION_CLOSEST_SYNC
+                    )
+                    onBitmapLoaded(result)
+                    it.release()
+                }
+            }
+        }
+        Box(
+            modifier = Modifier
+                .fillMaxSize()
+                .background(Color.Black)
+                .border(2.dp, Color.White.copy(alpha = 0.4f)),
+            contentAlignment = Alignment.Center
+        ) {
 //            CircularProgressIndicator()
-//        }
-//    } else {
-//        Box(
-//            modifier = Modifier
-//                .fillMaxSize(),
-//            contentAlignment = Alignment.Center
-//        ) {
-//            if (thumbnailBitmap != null) {
-//                Image(
-//                    painter = rememberAsyncImagePainter(thumbnailBitmap),
-//                    contentDescription = null,
-//                    contentScale = ContentScale.Crop,
-//                    alignment = Alignment.Center,
-//                    modifier = Modifier.fillMaxSize()
-//                )
-//            } else {
-//                AsyncImage(
-//                    model = thumbnail,
-//                    contentDescription = null,
-//                    contentScale = ContentScale.Crop,
-//                    alignment = Alignment.Center,
-//                    modifier = Modifier.fillMaxSize()
-//                )
-//            }
-//            if (isLoadingVideo) {
+        }
+    } else {
+        Box(
+            modifier = Modifier
+                .fillMaxSize(),
+            contentAlignment = Alignment.Center
+        ) {
+            if (thumbnailBitmap != null) {
+                ImageAny(
+                    src = thumbnailBitmap,
+                    contentDescription = null,
+                    contentScale = ContentScale.Crop,
+                    alignment = Alignment.Center,
+                    modifier = Modifier.fillMaxSize()
+                )
+            } else {
+                ImageAny(
+                    src = thumbnail,
+                    contentDescription = null,
+                    contentScale = ContentScale.Crop,
+                    alignment = Alignment.Center,
+                    modifier = Modifier.fillMaxSize()
+                )
+            }
+            if (isLoadingVideo) {
 //                CircularProgressIndicator(strokeWidth = 4.dp)
-//            }
-//        }
-//    }
-//}
+            }
+        }
+    }
+}

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

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -23,14 +23,12 @@ import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardScale
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusRequester
 import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusState
 import org.mjdev.tvlib.extensions.ModifierExt.swipeGestures
 import org.mjdev.tvlib.ui.components.card.FocusHelper
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @SuppressLint("AutoboxingStateValueProperty")
 @Previews
 @Composable

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

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -18,7 +18,6 @@ import androidx.compose.ui.focus.FocusState
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardScale
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusState
@@ -27,7 +26,6 @@ import org.mjdev.tvlib.ui.components.card.FocusHelper
 import org.mjdev.tvlib.ui.components.card.PhotoCard
 
 @SuppressLint("ModifierParameter")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun CarouselCard(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/complex/FocusableBox.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -23,7 +23,6 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.Border
 import androidx.tv.material3.ClickableSurfaceDefaults
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Surface
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.isFocused
@@ -33,7 +32,6 @@ import org.mjdev.tvlib.extensions.ModifierExt.focusState
 import org.mjdev.tvlib.extensions.ModifierExt.requestFocusOnTouch
 
 // todo focus state from user
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun FocusableBox(

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

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -37,7 +37,6 @@ import androidx.tv.material3.CardGlow
 import androidx.tv.material3.CardScale
 import androidx.tv.material3.CardShape
 import androidx.tv.material3.CompactCard
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.MaterialTheme
 import org.mjdev.tvlib.R
 import org.mjdev.tvlib.annotations.Previews
@@ -61,7 +60,6 @@ import org.mjdev.tvlib.ui.components.text.AutoHideEmptyText
 import org.mjdev.tvlib.ui.components.text.TextAny
 
 @SuppressLint("ModifierParameter")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun FocusableCard(

+ 4 - 8
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/gallery/ImmersiveInnerList.kt

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -21,7 +21,6 @@ import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Brush
@@ -30,8 +29,6 @@ import androidx.compose.ui.graphics.Color
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.extensions.ComposeExt
 import org.mjdev.tvlib.extensions.ComposeExt.createVerticalColorBrush
-import org.mjdev.tvlib.extensions.ModifierExt.conditional
-import org.mjdev.tvlib.helpers.brush.BrushBuilder
 import org.mjdev.tvlib.ui.components.immersivelist.ImmersiveListScope
 
 @OptIn(ExperimentalTvMaterial3Api::class)
@@ -42,7 +39,7 @@ fun ImmersiveListScope.ImmersiveInnerList(
     backgroundColor: Color = Color.Transparent,
     enter: EnterTransition = fadeIn() + slideInVertically(initialOffsetY = { it / 2 }),
     exit: ExitTransition = fadeOut() + slideOutVertically(targetOffsetY = { it / 2 }),
-    list: @Composable ImmersiveListScope.() -> Unit = {},
+    content: @Composable ImmersiveListScope.() -> Unit = {},
 ) {
     val background: State<Brush> = remember(backgroundColor) {
         derivedStateOf {
@@ -68,10 +65,9 @@ fun ImmersiveListScope.ImmersiveInnerList(
         exit = exit
     ) {
         Box(
-            modifier = modifier
-                .background(background.value)
+            modifier = modifier.background(background.value)
         ) {
-            list()
+            content()
         }
     }
 }

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/gridview/TvGridView.kt

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -22,13 +22,11 @@ import androidx.tv.foundation.lazy.grid.TvLazyHorizontalGrid
 import androidx.tv.foundation.lazy.grid.TvLazyVerticalGrid
 import androidx.tv.foundation.lazy.grid.items
 import androidx.tv.foundation.lazy.grid.rememberTvLazyGridState
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.computeCardWidth
 import org.mjdev.tvlib.extensions.ComposeExt.isPortraitMode
 import org.mjdev.tvlib.ui.components.card.PhotoCard
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun TvGridView(

+ 3 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/icon/ConversationReceiptIcon.kt

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Check
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -41,6 +40,7 @@ import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
+import org.mjdev.tvlib.ui.components.text.TextAny
 import kotlin.math.roundToInt
 
 @Preview
@@ -90,7 +90,7 @@ fun TextDashed() {
         modifier = Modifier.fillMaxWidth(),
         contentAlignment = Alignment.Center
     ) {
-        Text(
+        TextAny(
             modifier = Modifier
                 .width(227.dp)
                 .background(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/icon/IconAny.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -25,7 +25,6 @@ import androidx.compose.ui.graphics.ImageBitmap
 import androidx.compose.ui.graphics.asImageBitmap
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.res.painterResource
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Icon
 import androidx.tv.material3.LocalContentColor
 import com.skydoves.landscapist.ImageOptions
@@ -34,7 +33,6 @@ import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.DrawableExt.asImageBitmap
 import java.net.URL
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @SuppressLint("ModifierParameter")
 @Previews
 @Composable

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/DrawerSheet.kt

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -28,12 +28,10 @@ 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.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusRequester
 
 @Suppress("IllegalExperimentalApiUsage")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun DrawerSheet(

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

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -22,7 +22,6 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.DrawerValue
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ModifierExt.onlyPortrait
 import org.mjdev.tvlib.extensions.NavExt.rememberNavControllerEx
@@ -30,7 +29,6 @@ import org.mjdev.tvlib.navigation.MenuItem
 import org.mjdev.tvlib.navigation.NavHostControllerEx
 
 @SuppressLint("AutoboxingStateValueProperty")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun NavDrawerContent(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/NavigationRow.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -34,7 +34,6 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.DrawerValue
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import org.mjdev.tvlib.extensions.ComposeExt.isFocused
@@ -52,7 +51,6 @@ import org.mjdev.tvlib.ui.components.complex.FocusableBox
 import org.mjdev.tvlib.ui.components.icon.IconAny
 import org.mjdev.tvlib.ui.components.text.TextAny
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun NavigationRow(

+ 0 - 189
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/scroll/VerticalScrollbar.kt

@@ -1,189 +0,0 @@
-/*
- *  Copyright (c) Milan Jurkulák 2024.
- *  Contact:
- *  e: mimoccc@gmail.com
- *  e: mj@mjdev.org
- *  w: https://mjdev.org
- */
-
-package org.mjdev.tvlib.ui.components.scroll
-
-import androidx.compose.foundation.ScrollState
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxWithConstraints
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.layout.wrapContentWidth
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-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.Shape
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import org.mjdev.tvlib.extensions.ModifierExt.conditional
-import org.mjdev.tvlib.ui.icons.ScrollDown
-import org.mjdev.tvlib.ui.icons.ScrollDownDisabled
-import org.mjdev.tvlib.ui.icons.ScrollUp
-import org.mjdev.tvlib.ui.icons.ScrollUpDisabled
-
-@Composable
-inline fun <reified T> WithScope(
-    scope: T,
-    noinline config: @Composable T.() -> Unit,
-    block: @Composable T.() -> Unit
-) {
-    config.invoke(scope)
-    block.invoke(scope)
-}
-
-@Preview
-@Composable
-fun ScrollBarVertical(
-    modifier: Modifier = Modifier,
-    config: @Composable ScrollBarVerticalConfigScope.() -> Unit = {},
-    visible: Boolean = true,
-    scrollState: ScrollState = rememberScrollState(),
-) = WithScope(ScrollBarVerticalConfigScope(), config) {
-    BoxWithConstraints(
-        modifier = Modifier
-            .fillMaxHeight()
-            .conditional(
-                condition = visible,
-                ifTrue = {
-                    wrapContentWidth()
-                },
-                ifFalse = {
-                    width(0.dp)
-                }
-            )
-    ) {
-        val maxHeight = maxHeight.value
-        val steps by remember {
-            derivedStateOf {
-                scrollState.maxValue.toFloat()
-            }
-        }
-        val currentValue by remember {
-            derivedStateOf {
-                scrollState.value.toFloat()
-            }
-        }
-        if (visible) {
-            val canScrollDown by remember {
-                derivedStateOf {
-                    steps > currentValue
-                }
-            }
-            val canScrollTop by remember {
-                derivedStateOf {
-                    currentValue > 0
-                }
-            }
-            val topIcon by remember {
-                derivedStateOf {
-                    if (canScrollTop) Icons.Filled.ScrollUp else Icons.Filled.ScrollUpDisabled
-                }
-            }
-            val bottomIcon by remember {
-                derivedStateOf {
-                    if (canScrollDown) Icons.Filled.ScrollDown else Icons.Filled.ScrollDownDisabled
-                }
-            }
-            val handleHeight by remember {
-                derivedStateOf {
-                    maxHeight / (steps - 1)
-                }
-            }
-            val handleContainerSize by remember {
-                derivedStateOf {
-                    maxHeight - handleHeight
-                }
-            }
-            val stepSize by remember {
-                derivedStateOf {
-                    handleContainerSize / (steps + 1)
-                }
-            }
-            val handlePosition by remember {
-                derivedStateOf {
-                    stepSize * currentValue
-                }
-            }
-            Column(
-                modifier = modifier,
-                horizontalAlignment = Alignment.CenterHorizontally,
-            ) {
-                Icon(
-                    imageVector = topIcon,
-                    contentDescription = "",
-                    modifier = Modifier
-                        .padding(iconPadding)
-                        .size(iconSize)
-                )
-                Box(
-                    modifier = Modifier
-                        .width(iconSize + iconPadding + iconPadding)
-                        .fillMaxHeight()
-                        .weight(1f),
-                    contentAlignment = Alignment.Center
-                ) {
-                    Box(
-                        modifier = Modifier
-                            .height(maxHeight.dp)
-                            .width(handleWidth)
-                            .border(
-                                handleBorderWidth,
-                                color = handleBorderColor,
-                                shape = handleShape
-                            )
-                    ) {
-                        Box(
-                            modifier = Modifier
-                                .padding(top = handlePosition.dp)
-                                .height(handleHeight.dp)
-                                .width(handleWidth)
-                                .background(
-                                    color = handleColor,
-                                    shape = MaterialTheme.shapes.medium
-                                )
-                        ) {}
-                    }
-                }
-                Icon(
-                    imageVector = bottomIcon,
-                    contentDescription = "",
-                    modifier = Modifier
-                        .padding(iconPadding)
-                        .size(iconSize)
-                )
-            }
-        }
-    }
-}
-
-data class ScrollBarVerticalConfigScope(
-    val iconSize: Dp = 24.dp,
-    val iconPadding: Dp = 16.dp,
-
-    val handleColor: Color = Color.Black,
-    val handleBorderColor: Color = Color.Black,
-    val handleShape: Shape = RoundedCornerShape(12.0.dp),
-    val handleWidth: Dp = 8.dp,
-    val handleBorderWidth: Dp = 1.dp
-)

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/text/AutoHideEmptyText.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -21,12 +21,10 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.TextUnit
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.LocalTextStyle
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.textFrom
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @SuppressLint("ModifierParameter")
 @Previews
 @Composable

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/text/CircleText.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -27,14 +27,12 @@ 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.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.isPortraitMode
 import org.mjdev.tvlib.extensions.ModifierExt.tvAspectRatio
 
 @SuppressLint("ModifierParameter")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun CircleText(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/text/TextAny.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -21,13 +21,11 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.TextUnit
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.LocalTextStyle
 import androidx.tv.material3.Text
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.textFrom
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @SuppressLint("ModifierParameter")
 @Previews
 @Composable

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/text/TextWithShadow.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -19,11 +19,9 @@ 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.tvlib.annotations.Previews
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun TextWithShadow(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/AppsRow.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -21,7 +21,6 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.foundation.lazy.list.TvLazyListState
 import androidx.tv.foundation.lazy.list.rememberTvLazyListState
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.extensions.ComposeExt.computeCardWidth
 import org.mjdev.tvlib.helpers.apps.rememberAppsManager
 import org.mjdev.tvlib.R
@@ -29,7 +28,6 @@ import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.data.local.App
 import org.mjdev.tvlib.ui.components.card.ItemCard
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun AppsRow(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/CategoryRow.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -30,14 +30,12 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.foundation.lazy.list.TvLazyListState
 import androidx.tv.foundation.lazy.list.rememberTvLazyListState
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.computeCardWidth
 import org.mjdev.tvlib.ui.components.card.PhotoCard
 import org.mjdev.tvlib.ui.components.text.TextAny
 
 @SuppressLint("AutoboxingStateValueProperty")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun CategoryRow(

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

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -35,7 +35,6 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.foundation.lazy.list.TvLazyListState
 import androidx.tv.foundation.lazy.list.rememberTvLazyListState
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.computeCardWidth
 import org.mjdev.tvlib.extensions.CursorExt.getData
@@ -46,7 +45,6 @@ import org.mjdev.tvlib.ui.components.text.TextAny
 
 @Suppress("DEPRECATION")
 @SuppressLint("AutoboxingStateValueProperty")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun CursorRow(

+ 4 - 8
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/ErrorMessage.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -21,8 +21,6 @@ import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.Divider
-import androidx.compose.material3.HorizontalDivider
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
@@ -38,14 +36,12 @@ 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 org.mjdev.tvlib.ui.components.button.Button
 import org.mjdev.tvlib.R
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import org.mjdev.tvlib.ui.components.text.TextAny
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun ErrorMessage(
@@ -94,11 +90,11 @@ fun ErrorMessage(
                 softWrap = false,
                 color = color
             )
-            HorizontalDivider(
+            Box(
                 modifier = Modifier
                     .width(1.dp)
-                    .height(24.dp),
-                color = Color.White
+                    .height(24.dp)
+                    .background(Color.White),
             )
             TextAny(
                 modifier = Modifier

+ 53 - 55
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/Loading.kt

@@ -1,55 +1,53 @@
-///*
-// * 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.compose.foundation.background
-//import androidx.compose.foundation.layout.Box
-//import androidx.compose.foundation.layout.fillMaxSize
-//import androidx.compose.runtime.Composable
-//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.graphics.Shape
-//import androidx.compose.ui.text.TextStyle
-//import androidx.compose.ui.unit.TextUnit
-//import androidx.compose.ui.unit.sp
-//import androidx.tv.material3.ExperimentalTvMaterial3Api
-//import androidx.tv.material3.MaterialTheme
-//import org.mjdev.tvlib.R
-//import org.mjdev.tvlib.annotations.Previews
-//import org.mjdev.tvlib.ui.components.text.TextAny
-//
-//@OptIn(ExperimentalTvMaterial3Api::class)
-//@Previews
-//@Composable
-//fun Loading(
-//    modifier: Modifier = Modifier,
-//    backgroundColor: Color = Color.Black,
-//    shape: Shape = RectangleShape,
-//    text: Any? = R.string.msg_loading,
-//    textColor: Color = Color.White,
-//    textSize: TextUnit = 20.sp,
-//    textStyle: TextStyle = MaterialTheme.typography.headlineMedium,
-//    contentAlignment: Alignment = Alignment.Center
-//) {
-//    Box(
-//        modifier = modifier
-//            .fillMaxSize()
-//            .background(backgroundColor, shape),
-//        contentAlignment = contentAlignment
-//    ) {
-//        TextAny(
-//            text = text,
-//            color = textColor,
-//            fontSize = textSize,
-//            style = textStyle
-//        )
-//    }
-//}
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.ui.components.tv
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+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.graphics.Shape
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.sp
+import androidx.tv.material3.MaterialTheme
+import org.mjdev.tvlib.R
+import org.mjdev.tvlib.annotations.Previews
+import org.mjdev.tvlib.ui.components.text.TextAny
+
+@Previews
+@Composable
+fun Loading(
+    modifier: Modifier = Modifier,
+    backgroundColor: Color = Color.Black,
+    shape: Shape = RectangleShape,
+    text: Any? = R.string.msg_loading,
+    textColor: Color = Color.White,
+    textSize: TextUnit = 20.sp,
+    textStyle: TextStyle = MaterialTheme.typography.headlineMedium,
+    contentAlignment: Alignment = Alignment.Center
+) {
+    Box(
+        modifier = modifier
+            .fillMaxSize()
+            .background(backgroundColor, shape),
+        contentAlignment = contentAlignment
+    ) {
+        TextAny(
+            text = text,
+            color = textColor,
+            fontSize = textSize,
+            style = textStyle
+        )
+    }
+}

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/Tabs.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -26,7 +26,6 @@ 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.Tab
 import androidx.tv.material3.TabDefaults
 import androidx.tv.material3.TabRow
@@ -40,7 +39,6 @@ import org.mjdev.tvlib.ui.components.text.TextAny
 
 // todo from user
 @SuppressLint("AutoboxingStateValueProperty")
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun Tabs(

+ 1 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/UserPic.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023. 
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -17,7 +17,6 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.MaterialTheme
 import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import org.mjdev.tvlib.extensions.ModifierExt.conditional
@@ -26,7 +25,6 @@ import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.ui.components.complex.FocusableBox
 import org.mjdev.tvlib.ui.components.image.CircleImage
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun UserPic(

+ 2 - 4
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/dialog/BlurDialog.kt

@@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
@@ -33,15 +32,14 @@ import androidx.compose.ui.input.key.onKeyEvent
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.MaterialTheme
 import org.mjdev.tvlib.ui.toolkit.blur.legacyBackgroundBlur
 import org.mjdev.tvlib.annotations.Previews
+import org.mjdev.tvlib.ui.components.text.TextAny
 import org.mjdev.tvlib.ui.toolkit.ImageBrush
 import org.mjdev.tvlib.ui.toolkit.shadow.shadow
 import org.mjdev.tvlib.ui.toolkit.visualEffect
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Previews
 @Composable
 fun BlurDialog(
@@ -109,7 +107,7 @@ fun BlurDialog(
                     .background(backgroundColor.copy(0.98f))
                     .padding(8.dp)
             ) {
-                Text(
+                TextAny(
                     text = title,
                     color = textColor
                 )

+ 1 - 7
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/theme/ThemeHelper.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
+ *  Copyright (c) Milan Jurkulák 2024.
  *  Contact:
  *  e: mimoccc@gmail.com
  *  e: mj@mjdev.org
@@ -40,13 +40,11 @@ import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.core.view.WindowCompat
 import androidx.tv.material3.ColorScheme
-import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.MaterialTheme
 import androidx.tv.material3.darkColorScheme
 import androidx.tv.material3.lightColorScheme
 import org.mjdev.tvlib.extensions.ComposeExt.isTV
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 fun ThemeHelper(
     useDarkTheme: Boolean = isSystemInDarkTheme() || isTV(),
@@ -122,12 +120,10 @@ class ThemeProvider {
     val detailsTextColor: Color = Color.White
     val detailTextBackgroundColor: Color = Color.Black
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     val detailsTitleTextStyle: TextStyle
         @Composable
         get() = MaterialTheme.typography.headlineSmall
 
-    @OptIn(ExperimentalTvMaterial3Api::class)
     val detailsTextStyle: TextStyle
         @Composable
         get() = MaterialTheme.typography.bodySmall
@@ -163,7 +159,6 @@ object ThemeHelper {
 }
 
 @RequiresApi(Build.VERSION_CODES.S)
-@OptIn(ExperimentalTvMaterial3Api::class)
 fun dynamicDarkColorScheme(context: Context): ColorScheme {
     val tonalPalette = dynamicTonalPalette(context)
     return darkColorScheme(
@@ -193,7 +188,6 @@ fun dynamicDarkColorScheme(context: Context): ColorScheme {
 }
 
 @RequiresApi(Build.VERSION_CODES.S)
-@OptIn(ExperimentalTvMaterial3Api::class)
 fun dynamicLightColorScheme(context: Context): ColorScheme {
     val tonalPalette = dynamicTonalPalette(context)
     return lightColorScheme(