Преглед на файлове

library pre-implementation

Milan Jurkulak преди 3 години
родител
ревизия
a7a6e90a2b
променени са 100 файла, в които са добавени 834 реда и са изтрити 685 реда
  1. 1 0
      README.md
  2. 20 59
      app/build.gradle.kts
  3. 4 4
      app/src/main/kotlin/org/mjdev/tvapp/activity/MainActivity.kt
  4. 0 37
      app/src/main/kotlin/org/mjdev/tvapp/base/helpers/SquashedOval.kt
  5. 0 13
      app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithTitle.kt
  6. 0 18
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/media/PlayerControls.kt
  7. 3 3
      app/src/main/kotlin/org/mjdev/tvapp/data/Message.kt
  8. 7 7
      app/src/main/kotlin/org/mjdev/tvapp/data/Movie.kt
  9. 8 9
      app/src/main/kotlin/org/mjdev/tvapp/module/ProvideModule.kt
  10. 1 1
      app/src/main/kotlin/org/mjdev/tvapp/repository/MovieRepository.kt
  11. 1 1
      app/src/main/kotlin/org/mjdev/tvapp/sync/SyncAdapter.kt
  12. 0 105
      app/src/main/kotlin/org/mjdev/tvapp/ui/components/Details.kt
  13. 0 41
      app/src/main/kotlin/org/mjdev/tvapp/ui/components/Loading.kt
  14. 4 4
      app/src/main/kotlin/org/mjdev/tvapp/ui/components/MediaPlayer.kt
  15. 6 6
      app/src/main/kotlin/org/mjdev/tvapp/ui/pages/AboutPage.kt
  16. 14 12
      app/src/main/kotlin/org/mjdev/tvapp/ui/pages/MainPage.kt
  17. 5 5
      app/src/main/kotlin/org/mjdev/tvapp/ui/pages/PluginsPage.kt
  18. 5 5
      app/src/main/kotlin/org/mjdev/tvapp/ui/pages/SubscriptionPage.kt
  19. 92 13
      app/src/main/kotlin/org/mjdev/tvapp/ui/screens/DetailScreen.kt
  20. 5 5
      app/src/main/kotlin/org/mjdev/tvapp/ui/screens/MainScreen.kt
  21. 7 7
      app/src/main/kotlin/org/mjdev/tvapp/ui/screens/PlayerScreen.kt
  22. 11 8
      app/src/main/kotlin/org/mjdev/tvapp/ui/screens/SplashScreen.kt
  23. 1 1
      app/src/main/kotlin/org/mjdev/tvapp/ui/theme/Theme.kt
  24. 1 1
      app/src/main/kotlin/org/mjdev/tvapp/viewmodel/DetailViewModel.kt
  25. 8 9
      app/src/main/kotlin/org/mjdev/tvapp/viewmodel/MainViewModel.kt
  26. 3 1
      app/src/main/res/values-cs/strings.xml
  27. 2 0
      app/src/main/res/values-sk/strings.xml
  28. 2 1
      app/src/main/res/values/strings.xml
  29. 2 1
      settings.gradle.kts
  30. 1 0
      tvlib/.gitignore
  31. 153 0
      tvlib/build.gradle.kts
  32. 0 0
      tvlib/consumer-rules.pro
  33. 21 0
      tvlib/proguard-rules.pro
  34. 10 0
      tvlib/src/main/AndroidManifest.xml
  35. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/activity/ActivityResultHandler.kt
  36. 15 14
      tvlib/src/main/kotlin/org/mjdev/tvlib/activity/ComposableActivity.kt
  37. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/annotations/TvPreview.kt
  38. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/AnimExt.kt
  39. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/BitmapExt.kt
  40. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ColorFilterExt.kt
  41. 5 9
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ComposeExt.kt
  42. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ContextExt.kt
  43. 2 2
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/CursorExt.kt
  44. 6 6
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/DrawableExt.kt
  45. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/GlobalExt.kt
  46. 46 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/HiltExt.kt
  47. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ListExt.kt
  48. 59 55
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ModifierExt.kt
  49. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/NavBackStackEntryExt.kt
  50. 3 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/NavControllerExt.kt
  51. 7 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/NavExt.kt
  52. 4 4
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/NavGraphBuilderExt.kt
  53. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/StringExt.kt
  54. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ViewExt.kt
  55. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/BrushBuilder.kt
  56. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/LifeCycle.kt
  57. 37 0
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/SquashedOval.kt
  58. 4 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/apps/AppsManager.kt
  59. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/AudioCursor.kt
  60. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/AudioItem.kt
  61. 2 2
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/CachingCursor.kt
  62. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/PhotoCursor.kt
  63. 4 4
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/PhotoItem.kt
  64. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/VideoCursor.kt
  65. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/VideoItem.kt
  66. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemAudio.kt
  67. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemPhoto.kt
  68. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemVideo.kt
  69. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithBackground.kt
  70. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithDescription.kt
  71. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithId.kt
  72. 13 0
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithImage.kt
  73. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithIntent.kt
  74. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithMessage.kt
  75. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithSubtitle.kt
  76. 13 0
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithTitle.kt
  77. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithUri.kt
  78. 3 2
      tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/AnyType.kt
  79. 3 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/MenuItem.kt
  80. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/MenuItemClickListener.kt
  81. 2 2
      tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/NavGraphBuilderEx.kt
  82. 2 2
      tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/NavHostControllerEx.kt
  83. 9 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/network/CacheInterceptor.kt
  84. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/network/ConnectivityCallback.kt
  85. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/network/NetworkConnectivityService.kt
  86. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/network/NetworkConnectivityServiceImpl.kt
  87. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/network/NetworkStatus.kt
  88. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/paging/ListPagingSource.kt
  89. 36 27
      tvlib/src/main/kotlin/org/mjdev/tvlib/permission/PermissonManager.kt
  90. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/screen/Screen.kt
  91. 5 5
      tvlib/src/main/kotlin/org/mjdev/tvlib/screen/ScreenWithPages.kt
  92. 4 4
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/badge/Badge.kt
  93. 8 8
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/button/Button.kt
  94. 3 3
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/Card.kt
  95. 7 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/CardContent.kt
  96. 12 12
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/ItemCard.kt
  97. 14 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PhotoCard.kt
  98. 8 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PreviewCard.kt
  99. 7 7
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/carousel/BigCarousel.kt
  100. 10 10
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/carousel/CarouselCard.kt

+ 1 - 0
README.md

@@ -22,6 +22,7 @@
 
 ## Description
 
+All in one, tablet, mobile and tv android app.
 Just an test app as showcase of coding skills, using modern frameworks  
 and a new unstable tv compose framework for tv apps with the diferrence  
 that components in this example should be touchable and therefore this  

+ 20 - 59
app/build.gradle.kts

@@ -167,17 +167,12 @@ android {
 }
 
 dependencies {
-
+    // tv library by mjde milan jurkulak
+    implementation(project(mapOf("path" to ":tvlib")))
     // base libs
     implementation("androidx.core:core-ktx:1.12.0-alpha05")
-    // reflect / debug purposes only
-    implementation(kotlin("reflect", "1.8.21"))
-    // window manager
-    implementation("androidx.window:window:1.1.0")
     // compose base libs
-    implementation(
-        platform("androidx.compose:compose-bom:2023.06.01")
-    )
+    implementation(platform("androidx.compose:compose-bom:2023.06.01"))
     implementation("androidx.compose.ui:ui-tooling")
     implementation("androidx.activity:activity-compose:1.7.2")
     // more icons
@@ -185,74 +180,41 @@ dependencies {
     // tv compose
     implementation("androidx.tv:tv-foundation:1.0.0-SNAPSHOT")
     implementation("androidx.tv:tv-material:1.0.0-alpha07")
-    // paging
-    implementation("androidx.paging:paging-compose:3.2.0-rc01")
-    // view model
-    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
-    // navigation
-    implementation("androidx.navigation:navigation-compose:2.7.0-beta02")
-    // image loading
-    implementation("io.coil-kt:coil-base:2.4.0")
-    implementation("io.coil-kt:coil-gif:2.2.2")
-    implementation("io.coil-kt:coil-svg:1.2.2")
-    implementation("io.coil-kt:coil-video:1.2.2")
-    implementation("io.coil-kt:coil-compose:2.4.0")
-    implementation("com.github.skydoves:landscapist-coil:2.2.2")
-    // constraint layout // todo remove
-    implementation("androidx.constraintlayout:constraintlayout-compose:1.0.1")
-    // debug
-    implementation("com.jakewharton.timber:timber:5.0.1")
-    // dagger core
-    implementation("com.google.dagger:dagger:2.46.1")
-    implementation("androidx.compose.material3:material3:1.1.1")
-    kapt("com.google.dagger:dagger-compiler:2.46.1")
-    // dagger android
+    // dagger - hilt
     implementation("com.google.dagger:dagger-android:2.46.1")
     implementation("com.google.dagger:dagger-android-support:2.46.1")
-    kapt("com.google.dagger:dagger-android-processor:2.46.1")
-    // dagger - hilt
+    implementation("com.google.dagger:dagger:2.46.1")
     implementation("com.google.dagger:hilt-android:2.46.1")
     implementation("androidx.hilt:hilt-navigation-compose:1.1.0-alpha01")
-    kapt("com.google.dagger:hilt-compiler:2.46.1")
+    // moshi json
+    implementation("com.squareup.moshi:moshi:1.15.0")
+    implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
     // okhttp
     implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
     implementation("com.squareup.okhttp3:okhttp")
     implementation("com.squareup.okhttp3:logging-interceptor")
-    // moshi json
-    implementation("com.squareup.moshi:moshi:1.15.0")
-    implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
+    // debug
+    implementation("com.jakewharton.timber:timber:5.0.1")
+    // kapt
+    kapt("com.google.dagger:dagger-compiler:2.46.1")
+    kapt("com.google.dagger:dagger-android-processor:2.46.1")
+    kapt("com.google.dagger:hilt-compiler:2.46.1")
     kapt("com.squareup.moshi:moshi-kotlin-codegen:1.15.0")
+    // view model
+    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
+    // navigation
+    implementation("androidx.navigation:navigation-compose:2.7.0-beta02")
     // retrofit
     implementation("com.squareup.retrofit2:retrofit:2.9.0")
     implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
     implementation("com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2")
     // encrypt data
     implementation("com.scottyab:aescrypt:0.0.1")
-    // exoplayer
-    implementation("androidx.media3:media3-exoplayer:1.1.0")
-    implementation("androidx.media3:media3-exoplayer-dash:1.1.0")
-    implementation("androidx.media3:media3-exoplayer-hls:1.1.0")
-    implementation("androidx.media3:media3-exoplayer-rtsp:1.1.0")
-    implementation("androidx.media3:media3-exoplayer-ima:1.1.0")
-    implementation("androidx.media3:media3-datasource-cronet:1.1.0")
-    implementation("androidx.media3:media3-datasource-okhttp:1.1.0")
-    implementation("androidx.media3:media3-datasource-rtmp:1.1.0")
-    implementation("androidx.media3:media3-ui:1.1.0")
-    implementation("androidx.media3:media3-ui-leanback:1.1.0")
-    implementation("androidx.media3:media3-session:1.1.0")
-    implementation("androidx.media3:media3-extractor:1.1.0")
-    implementation("androidx.media3:media3-cast:1.1.0")
-    implementation("androidx.media3:media3-exoplayer-workmanager:1.1.0")
-    implementation("androidx.media3:media3-transformer:1.1.0")
-    implementation("androidx.media3:media3-database:1.1.0")
-    implementation("androidx.media3:media3-decoder:1.1.0")
-    implementation("androidx.media3:media3-datasource:1.1.0")
-    implementation("androidx.media3:media3-common:1.1.0")
     // permission
     implementation("com.google.accompanist:accompanist-permissions:0.31.5-beta")
-
+    // previews
     debugImplementation("androidx.customview:customview-poolingcontainer:1.0.0")
-
+    // libs mismatch
     constraints {
         implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0")?.apply {
             because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib")
@@ -261,5 +223,4 @@ dependencies {
             because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib")
         }
     }
-
 }

+ 4 - 4
app/src/main/kotlin/org/mjdev/tvapp/activity/MainActivity.kt

@@ -10,10 +10,10 @@ package org.mjdev.tvapp.activity
 
 import androidx.compose.runtime.Composable
 import dagger.hilt.android.AndroidEntryPoint
-import org.mjdev.tvapp.base.activity.ComposableActivity
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.NavGraphBuilderExt.screen
-import org.mjdev.tvapp.base.navigation.NavGraphBuilderEx
+import org.mjdev.tvlib.activity.ComposableActivity
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.NavGraphBuilderExt.screen
+import org.mjdev.tvlib.navigation.NavGraphBuilderEx
 import org.mjdev.tvapp.ui.screens.DetailScreen
 import org.mjdev.tvapp.ui.screens.MainScreen
 import org.mjdev.tvapp.ui.screens.PlayerScreen

+ 0 - 37
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/SquashedOval.kt

@@ -1,37 +0,0 @@
-///*
-// * Copyright (c) Milan Jurkulák 2023.
-// *  Contact:
-// *  e: mimoccc@gmail.com
-// *  e: mj@mjdev.org
-// *  w: https://mjdev.org
-// */
-//
-//package org.mjdev.tvapp.base.helpers
-//
-//import androidx.compose.ui.geometry.Rect
-//import androidx.compose.ui.geometry.Size
-//import androidx.compose.ui.graphics.Outline
-//import androidx.compose.ui.graphics.Path
-//import androidx.compose.ui.graphics.Shape
-//import androidx.compose.ui.unit.Density
-//import androidx.compose.ui.unit.LayoutDirection
-//
-//class SquashedOval : Shape {
-//    override fun createOutline(
-//        size: Size,
-//        layoutDirection: LayoutDirection,
-//        density: Density
-//    ): Outline {
-//        val path = Path().apply {
-//            addOval(
-//                Rect(
-//                    left = size.width / 4f,
-//                    top = 0f,
-//                    right = size.width * 3 / 4f,
-//                    bottom = size.height
-//                )
-//            )
-//        }
-//        return Outline.Generic(path = path)
-//    }
-//}

+ 0 - 13
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithTitle.kt

@@ -1,13 +0,0 @@
-/*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
- */
-
-package org.mjdev.tvapp.base.interfaces
-
-interface ItemWithTitle<T> {
-    val title : T?
-}

+ 0 - 18
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/media/PlayerControls.kt

@@ -1,18 +0,0 @@
-/*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
- */
-
-package org.mjdev.tvapp.base.ui.components.media
-
-import androidx.compose.runtime.Composable
-import org.mjdev.tvapp.base.annotations.TvPreview
-
-// todo
-@TvPreview
-@Composable
-fun PlayerControls () {
-}

+ 3 - 3
app/src/main/kotlin/org/mjdev/tvapp/data/Message.kt

@@ -12,9 +12,9 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 import io.objectbox.annotation.Entity
 import io.objectbox.annotation.Id
-import org.mjdev.tvapp.base.interfaces.ItemWithId
-import org.mjdev.tvapp.base.interfaces.ItemWithMessage
-import org.mjdev.tvapp.base.interfaces.ItemWithTitle
+import org.mjdev.tvlib.interfaces.ItemWithId
+import org.mjdev.tvlib.interfaces.ItemWithMessage
+import org.mjdev.tvlib.interfaces.ItemWithTitle
 
 @Entity
 @JsonClass(generateAdapter = true)

+ 7 - 7
app/src/main/kotlin/org/mjdev/tvapp/data/Movie.kt

@@ -12,13 +12,13 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 import io.objectbox.annotation.Entity
 import io.objectbox.annotation.Id
-import org.mjdev.tvapp.base.interfaces.ItemWithBackground
-import org.mjdev.tvapp.base.interfaces.ItemWithDescription
-import org.mjdev.tvapp.base.interfaces.ItemWithId
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.interfaces.ItemWithSubtitle
-import org.mjdev.tvapp.base.interfaces.ItemWithTitle
-import org.mjdev.tvapp.base.interfaces.ItemWithUri
+import org.mjdev.tvlib.interfaces.ItemWithBackground
+import org.mjdev.tvlib.interfaces.ItemWithDescription
+import org.mjdev.tvlib.interfaces.ItemWithId
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.interfaces.ItemWithSubtitle
+import org.mjdev.tvlib.interfaces.ItemWithTitle
+import org.mjdev.tvlib.interfaces.ItemWithUri
 import java.io.Serializable
 
 @Entity

+ 8 - 9
app/src/main/kotlin/org/mjdev/tvapp/module/ProvideModule.kt

@@ -20,13 +20,13 @@ import dagger.hilt.components.SingletonComponent
 import okhttp3.OkHttpClient
 import okhttp3.logging.HttpLoggingInterceptor
 import org.mjdev.tvapp.BuildConfig
-import org.mjdev.tvapp.base.helpers.apps.AppsManager
-import org.mjdev.tvapp.base.helpers.cursor.AudioCursor
-import org.mjdev.tvapp.base.helpers.cursor.PhotoCursor
-import org.mjdev.tvapp.base.helpers.cursor.VideoCursor
-import org.mjdev.tvapp.base.network.CacheInterceptor
-import org.mjdev.tvapp.base.network.NetworkConnectivityService
-import org.mjdev.tvapp.base.network.NetworkConnectivityServiceImpl
+import org.mjdev.tvlib.helpers.apps.AppsManager
+import org.mjdev.tvlib.helpers.cursor.AudioCursor
+import org.mjdev.tvlib.helpers.cursor.PhotoCursor
+import org.mjdev.tvlib.helpers.cursor.VideoCursor
+import org.mjdev.tvlib.network.CacheInterceptor
+import org.mjdev.tvlib.network.NetworkConnectivityService
+import org.mjdev.tvlib.network.NetworkConnectivityServiceImpl
 import org.mjdev.tvapp.database.DAO
 import org.mjdev.tvapp.repository.IMovieRepository
 import org.mjdev.tvapp.repository.MovieRepository
@@ -84,8 +84,7 @@ class ProvideModule {
 
     @Singleton
     @Provides
-    fun providesHttpLoggingInterceptor(
-    ) = HttpLoggingInterceptor().apply {
+    fun providesHttpLoggingInterceptor() = HttpLoggingInterceptor().apply {
         level = HttpLoggingInterceptor.Level.BODY
     }
 

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/repository/MovieRepository.kt

@@ -8,10 +8,10 @@
 
 package org.mjdev.tvapp.repository
 
-import org.mjdev.tvapp.base.extensions.GlobalExt.runSafe
 import org.mjdev.tvapp.data.Message
 import org.mjdev.tvapp.data.Movie
 import org.mjdev.tvapp.database.DAO
+import org.mjdev.tvlib.extensions.GlobalExt.runSafe
 import javax.inject.Inject
 
 class MovieRepository @Inject constructor(

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/sync/SyncAdapter.kt

@@ -10,10 +10,10 @@ import io.objectbox.Box
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.runBlocking
-import org.mjdev.tvapp.base.extensions.ListExt.containsNot
 import org.mjdev.tvapp.data.Movie
 import org.mjdev.tvapp.database.DAO
 import org.mjdev.tvapp.repository.IMovieRepository
+import org.mjdev.tvlib.extensions.ListExt.containsNot
 import timber.log.Timber
 
 @Suppress("unused", "PrivatePropertyName")

+ 0 - 105
app/src/main/kotlin/org/mjdev/tvapp/ui/components/Details.kt

@@ -1,105 +0,0 @@
-/*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
- */
-
-package org.mjdev.tvapp.ui.components
-
-import android.annotation.SuppressLint
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.foundation.background
-import androidx.compose.foundation.gestures.detectTapGestures
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.alpha
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.layout.ContentScale
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.interfaces.ItemWithBackground
-import org.mjdev.tvapp.base.interfaces.ItemWithDescription
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.interfaces.ItemWithSubtitle
-import org.mjdev.tvapp.base.interfaces.ItemWithTitle
-import org.mjdev.tvapp.base.ui.components.image.ImageAny
-import org.mjdev.tvapp.base.ui.components.text.TextAny
-import org.mjdev.tvapp.base.ui.theme.LocalThemeProvider
-
-@SuppressLint("ModifierParameter")
-@TvPreview
-@Composable
-fun Details(
-    data: Any? = null,
-    modifier: Modifier = Modifier,
-) {
-    val themeProvider = LocalThemeProvider.current
-    val backgroundImage = (data as? ItemWithBackground<*>)?.background
-    val image = (data as? ItemWithImage<*>)?.image
-    val title = (data as? ItemWithTitle<*>)?.title
-    val subtitle = (data as? ItemWithSubtitle<*>)?.subtitle
-    val description = (data as? ItemWithDescription<*>)?.description
-    var infoVisible by remember { mutableStateOf(true) }
-
-    Box(
-        modifier = modifier
-            .fillMaxSize()
-            .pointerInput(Unit) {
-                detectTapGestures {
-                    infoVisible = !infoVisible
-                }
-            },
-        contentAlignment = Alignment.BottomStart,
-    ) {
-        ImageAny(
-            src = backgroundImage ?: image,
-            contentDescription = null,
-            contentScale = ContentScale.Crop,
-            modifier = Modifier.fillMaxSize()
-        )
-        AnimatedVisibility(
-            visible = infoVisible,
-            enter = fadeIn(),
-            exit = fadeOut(),
-        ) {
-            Column(
-                modifier = Modifier
-                    .fillMaxWidth().alpha(0.8f)
-                    .background(themeProvider.detailTextBackgroundColor)
-                    .padding(
-                        vertical = themeProvider.detailTextPaddingVertical,
-                        horizontal = themeProvider.detailTextPaddingHorizontal
-                    )
-            ) {
-                TextAny(
-                    text = title ?: "-",
-                    style = themeProvider.detailsTitleTextStyle,
-                    color = themeProvider.detailsTextColor
-                )
-                TextAny(
-                    text = subtitle ?: "-",
-                    style = themeProvider.detailsTextStyle,
-                    color = themeProvider.detailsTextColor
-                )
-                TextAny(
-                    text = description ?: "-",
-                    style = themeProvider.detailsTextStyle,
-                    color = themeProvider.detailsTextColor
-                )
-            }
-        }
-    }
-}

+ 0 - 41
app/src/main/kotlin/org/mjdev/tvapp/ui/components/Loading.kt

@@ -1,41 +0,0 @@
-/*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
- */
-
-package org.mjdev.tvapp.ui.components
-
-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.unit.sp
-import androidx.tv.material3.MaterialTheme
-import androidx.tv.material3.Text
-import org.mjdev.tvapp.base.annotations.TvPreview
-
-@TvPreview
-@Composable
-fun Loading(modifier: Modifier = Modifier) {
-    Box(
-        modifier = modifier.fillMaxSize().background(
-            Color.DarkGray,
-            RectangleShape
-        ),
-        contentAlignment = Alignment.Center
-    ) {
-        Text(
-            text = "Loading...",
-            color = Color.White,
-            fontSize=20.sp,
-            style = MaterialTheme.typography.headlineMedium
-        )
-    }
-}

+ 4 - 4
app/src/main/kotlin/org/mjdev/tvapp/ui/components/MediaPlayer.kt

@@ -13,10 +13,10 @@ import android.net.Uri
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.StringExt.parseUri
-import org.mjdev.tvapp.base.interfaces.ItemWithUri
-import org.mjdev.tvapp.base.ui.components.media.MediaPlayerContainer
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.StringExt.parseUri
+import org.mjdev.tvlib.interfaces.ItemWithUri
+import org.mjdev.tvlib.ui.components.media.MediaPlayerContainer
 import java.net.URL
 
 @SuppressLint("ModifierParameter")

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

@@ -27,12 +27,12 @@ import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardDefaults
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.ui.components.card.Card
-import org.mjdev.tvapp.base.ui.components.page.Page
-import org.mjdev.tvapp.base.ui.components.card.CardContent
-import org.mjdev.tvapp.base.ui.components.image.CircleImage
-import org.mjdev.tvapp.base.ui.components.text.TextAny
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.ui.components.card.Card
+import org.mjdev.tvlib.ui.components.page.Page
+import org.mjdev.tvlib.ui.components.card.CardContent
+import org.mjdev.tvlib.ui.components.image.CircleImage
+import org.mjdev.tvlib.ui.components.text.TextAny
 
 class AboutPage : Page() {
 

+ 14 - 12
app/src/main/kotlin/org/mjdev/tvapp/ui/pages/MainPage.kt

@@ -20,18 +20,18 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.HiltExt.appViewModel
-import org.mjdev.tvapp.base.extensions.NavControllerExt.open
-import org.mjdev.tvapp.base.extensions.StringExt.asException
-import org.mjdev.tvapp.base.interfaces.ItemWithId
-import org.mjdev.tvapp.base.interfaces.ItemWithUri
-import org.mjdev.tvapp.base.ui.components.page.Page
-import org.mjdev.tvapp.base.ui.components.tv.AppsRow
-import org.mjdev.tvapp.base.ui.components.tv.BrowseView
-import org.mjdev.tvapp.base.ui.components.tv.LocalAudioRow
-import org.mjdev.tvapp.base.ui.components.tv.LocalPhotosRow
-import org.mjdev.tvapp.base.ui.components.tv.LocalVideoRow
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.HiltExt.appViewModel
+import org.mjdev.tvlib.extensions.NavControllerExt.open
+import org.mjdev.tvlib.extensions.StringExt.asException
+import org.mjdev.tvlib.interfaces.ItemWithId
+import org.mjdev.tvlib.interfaces.ItemWithUri
+import org.mjdev.tvlib.ui.components.page.Page
+import org.mjdev.tvlib.ui.components.tv.AppsRow
+import org.mjdev.tvlib.ui.components.tv.BrowseView
+import org.mjdev.tvlib.ui.components.tv.LocalAudioRow
+import org.mjdev.tvlib.ui.components.tv.LocalPhotosRow
+import org.mjdev.tvlib.ui.components.tv.LocalVideoRow
 import org.mjdev.tvapp.ui.screens.DetailScreen
 import org.mjdev.tvapp.ui.screens.PlayerScreen
 import org.mjdev.tvapp.viewmodel.MainViewModel
@@ -88,6 +88,8 @@ class MainPage : Page() {
 
         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(),

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

@@ -22,14 +22,14 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
+import androidx.tv.material3.Card
 import androidx.tv.material3.CardDefaults
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.ui.components.card.Card
-import org.mjdev.tvapp.base.ui.components.card.CardContent
-import org.mjdev.tvapp.base.ui.components.page.Page
-import org.mjdev.tvapp.base.ui.components.text.TextAny
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.ui.components.card.CardContent
+import org.mjdev.tvlib.ui.components.page.Page
+import org.mjdev.tvlib.ui.components.text.TextAny
 
 class PluginsPage : Page() {
 

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

@@ -25,11 +25,11 @@ import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardDefaults
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.ui.components.card.Card
-import org.mjdev.tvapp.base.ui.components.page.Page
-import org.mjdev.tvapp.base.ui.components.card.CardContent
-import org.mjdev.tvapp.base.ui.components.text.TextAny
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.ui.components.card.Card
+import org.mjdev.tvlib.ui.components.page.Page
+import org.mjdev.tvlib.ui.components.card.CardContent
+import org.mjdev.tvlib.ui.components.text.TextAny
 
 class SubscriptionPage : Page() {
 

+ 92 - 13
app/src/main/kotlin/org/mjdev/tvapp/ui/screens/DetailScreen.kt

@@ -8,23 +8,48 @@
 
 package org.mjdev.tvapp.ui.screens
 
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Info
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.ContentScale
 import androidx.navigation.navArgument
 import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.HiltExt.appViewModel
-import org.mjdev.tvapp.base.extensions.StringExt.asException
-import org.mjdev.tvapp.base.navigation.AnyType
-import org.mjdev.tvapp.base.screen.Screen
+import org.mjdev.tvapp.base.ui.components.tv.Loading
 import org.mjdev.tvapp.state.DetailsLoadingState
-import org.mjdev.tvapp.ui.components.Details
-import org.mjdev.tvapp.ui.components.Loading
 import org.mjdev.tvapp.viewmodel.DetailViewModel
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.HiltExt.appViewModel
+import org.mjdev.tvlib.extensions.StringExt.asException
+import org.mjdev.tvlib.interfaces.ItemWithBackground
+import org.mjdev.tvlib.interfaces.ItemWithDescription
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.interfaces.ItemWithSubtitle
+import org.mjdev.tvlib.interfaces.ItemWithTitle
+import org.mjdev.tvlib.navigation.AnyType
+import org.mjdev.tvlib.screen.Screen
+import org.mjdev.tvlib.ui.components.image.ImageAny
+import org.mjdev.tvlib.ui.components.text.TextAny
+import org.mjdev.tvlib.ui.theme.ThemeHelper.themeProvider
 
 class DetailScreen : Screen() {
 
@@ -52,23 +77,77 @@ class DetailScreen : Screen() {
         }
 
         val data: Any? = args[data]
+
         val dataState = remember {
             viewModel.detailsLoadingState(data)
         }.collectAsState()
 
+        val backgroundImage = (data as? ItemWithBackground<*>)?.background
+        val image = (data as? ItemWithImage<*>)?.image
+        val title = (data as? ItemWithTitle<*>)?.title
+        val subtitle = (data as? ItemWithSubtitle<*>)?.subtitle
+        val description = (data as? ItemWithDescription<*>)?.description
+        var infoVisible by remember { mutableStateOf(true) }
+
         fun postError(error: String) = viewModel.postError(error.asException())
 
         when (dataState.value) {
-            is DetailsLoadingState.Ready ->
-                Details((dataState.value as DetailsLoadingState.Ready).data)
-
-            is DetailsLoadingState.NotFound -> {
-                postError("File or address $data not found.")
+            is DetailsLoadingState.Ready -> {
+                Box(
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .pointerInput(Unit) {
+                            detectTapGestures {
+                                infoVisible = !infoVisible
+                            }
+                        },
+                    contentAlignment = Alignment.BottomStart,
+                ) {
+                    ImageAny(
+                        src = backgroundImage ?: image,
+                        contentDescription = null,
+                        contentScale = ContentScale.Crop,
+                        modifier = Modifier.fillMaxSize()
+                    )
+                    AnimatedVisibility(
+                        visible = infoVisible,
+                        enter = fadeIn(),
+                        exit = fadeOut(),
+                    ) {
+                        Column(
+                            modifier = Modifier
+                                .fillMaxWidth().alpha(0.8f)
+                                .background(themeProvider.detailTextBackgroundColor)
+                                .padding(
+                                    vertical = themeProvider.detailTextPaddingVertical,
+                                    horizontal = themeProvider.detailTextPaddingHorizontal
+                                )
+                        ) {
+                            TextAny(
+                                text = title ?: "-",
+                                style = themeProvider.detailsTitleTextStyle,
+                                color = themeProvider.detailsTextColor
+                            )
+                            TextAny(
+                                text = subtitle ?: "-",
+                                style = themeProvider.detailsTextStyle,
+                                color = themeProvider.detailsTextColor
+                            )
+                            TextAny(
+                                text = description ?: "-",
+                                style = themeProvider.detailsTextStyle,
+                                color = themeProvider.detailsTextColor
+                            )
+                        }
+                    }
+                }
+            }
+            DetailsLoadingState.Loading -> {
                 Loading()
             }
-
             else -> {
                 Loading()
+                postError("File or address $data not found.")
             }
         }
 

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/ui/screens/MainScreen.kt

@@ -13,15 +13,15 @@ import androidx.compose.material.icons.filled.Home
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.vector.ImageVector
 import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.screen.ScreenWithPages
-import org.mjdev.tvapp.base.ui.components.page.PagerScope
-import org.mjdev.tvapp.base.ui.components.page.SearchPage
-import org.mjdev.tvapp.base.ui.components.page.SettingsPage
 import org.mjdev.tvapp.ui.pages.AboutPage
 import org.mjdev.tvapp.ui.pages.MainPage
 import org.mjdev.tvapp.ui.pages.PluginsPage
 import org.mjdev.tvapp.ui.pages.SubscriptionPage
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.screen.ScreenWithPages
+import org.mjdev.tvlib.ui.components.page.PagerScope
+import org.mjdev.tvlib.ui.components.page.SearchPage
+import org.mjdev.tvlib.ui.components.page.SettingsPage
 
 class MainScreen : ScreenWithPages() {
 

+ 7 - 7
app/src/main/kotlin/org/mjdev/tvapp/ui/screens/PlayerScreen.kt

@@ -18,16 +18,16 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.navigation.navArgument
 import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
-import org.mjdev.tvapp.base.extensions.HiltExt.appViewModel
-import org.mjdev.tvapp.base.extensions.StringExt.asException
-import org.mjdev.tvapp.base.navigation.AnyType
-import org.mjdev.tvapp.base.screen.Screen
+import org.mjdev.tvapp.base.ui.components.tv.Loading
 import org.mjdev.tvapp.state.DetailsLoadingState
-import org.mjdev.tvapp.ui.components.Loading
 import org.mjdev.tvapp.ui.components.MediaPlayer
 import org.mjdev.tvapp.viewmodel.DetailViewModel
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
+import org.mjdev.tvlib.extensions.HiltExt.appViewModel
+import org.mjdev.tvlib.extensions.StringExt.asException
+import org.mjdev.tvlib.navigation.AnyType
+import org.mjdev.tvlib.screen.Screen
 
 class PlayerScreen : Screen() {
 

+ 11 - 8
app/src/main/kotlin/org/mjdev/tvapp/ui/screens/SplashScreen.kt

@@ -29,13 +29,13 @@ import androidx.compose.ui.unit.sp
 import com.google.accompanist.permissions.ExperimentalPermissionsApi
 import kotlinx.coroutines.delay
 import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
-import org.mjdev.tvapp.base.extensions.NavControllerExt.openAsTop
-import org.mjdev.tvapp.base.permission.rememberPermissionManager
-import org.mjdev.tvapp.base.screen.Screen
-import org.mjdev.tvapp.base.ui.components.text.TextAny
-import org.mjdev.tvapp.base.ui.components.tv.Title
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
+import org.mjdev.tvlib.extensions.NavControllerExt.openAsTop
+import org.mjdev.tvlib.permission.rememberPermissionManager
+import org.mjdev.tvlib.screen.Screen
+import org.mjdev.tvlib.ui.components.text.TextAny
+import org.mjdev.tvlib.ui.components.tv.Title
 
 @Suppress("UNUSED_VARIABLE")
 class SplashScreen : Screen() {
@@ -60,7 +60,10 @@ class SplashScreen : Screen() {
                 .fillMaxSize(),
             contentAlignment = Alignment.Center
         ) {
-            Title()
+            Title(
+                icon = R.mipmap.ic_launcher,
+                title = R.string.app_name
+            )
         }
         Box(
             modifier = Modifier

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/ui/theme/Theme.kt

@@ -11,7 +11,7 @@ package org.mjdev.tvapp.ui.theme
 import android.os.Build
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.runtime.Composable
-import org.mjdev.tvapp.base.ui.theme.ThemeHelper
+import org.mjdev.tvlib.ui.theme.ThemeHelper
 
 @Composable
 fun TVAppTheme(

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/viewmodel/DetailViewModel.kt

@@ -16,7 +16,7 @@ import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.stateIn
-import org.mjdev.tvapp.base.viewmodel.BaseViewModel
+import org.mjdev.tvlib.viewmodel.BaseViewModel
 import org.mjdev.tvapp.database.DAO
 import org.mjdev.tvapp.repository.IMovieRepository
 import org.mjdev.tvapp.repository.MovieRepository

+ 8 - 9
app/src/main/kotlin/org/mjdev/tvapp/viewmodel/MainViewModel.kt

@@ -16,14 +16,14 @@ import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.channelFlow
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.stateIn
-import org.mjdev.tvapp.base.extensions.ListExt.asMap
-import org.mjdev.tvapp.base.helpers.apps.AppsManager
-import org.mjdev.tvapp.base.helpers.cursor.AudioCursor
-import org.mjdev.tvapp.base.helpers.cursor.PhotoCursor
-import org.mjdev.tvapp.base.helpers.cursor.VideoCursor
-import org.mjdev.tvapp.base.network.NetworkConnectivityService
-import org.mjdev.tvapp.base.network.NetworkConnectivityServiceImpl
-import org.mjdev.tvapp.base.viewmodel.BaseViewModel
+import org.mjdev.tvlib.extensions.ListExt.asMap
+import org.mjdev.tvlib.helpers.apps.AppsManager
+import org.mjdev.tvlib.helpers.cursor.AudioCursor
+import org.mjdev.tvlib.helpers.cursor.PhotoCursor
+import org.mjdev.tvlib.helpers.cursor.VideoCursor
+import org.mjdev.tvlib.network.NetworkConnectivityService
+import org.mjdev.tvlib.network.NetworkConnectivityServiceImpl
+import org.mjdev.tvlib.viewmodel.BaseViewModel
 import org.mjdev.tvapp.data.Message
 import org.mjdev.tvapp.data.Movie
 import org.mjdev.tvapp.database.DAO
@@ -86,7 +86,6 @@ class MainViewModel @Inject constructor(
         mapOf()
     )
 
-
     companion object {
 
         @Suppress("unused")

+ 3 - 1
app/src/main/res/values-cs/strings.xml

@@ -22,10 +22,12 @@
     <string name="menu_title_exit">Ukončit</string>
     <string name="menu_title_home">Domov</string>
 
+    <string name="msg_loading">Načítam …</string>
+
     <string name="text_app_description">\n\n\nSimple TV Application for AndroidTV or SetTopBox with Android or any tablet or mobile device.\nAll in one solution for mobile app responsive to device.\nThis app is just an simple demonstration of Jetpack Compose and all other modern architecture components.\n\n\n</string>
     <string name="text_unimplemented_yet">Tato funkce zatím nebyla implementovaná.</string>
 
-    <string name="title_about">O aplikáci</string>
+    <string name="title_about">O aplikaci</string>
     <string name="title_apps">Aplikace</string>
     <string name="title_error">Chyba</string>
     <string name="title_home">Domov</string>

+ 2 - 0
app/src/main/res/values-sk/strings.xml

@@ -22,6 +22,8 @@
     <string name="menu_title_exit">Ukončiť</string>
     <string name="menu_title_home">Domov</string>
 
+    <string name="msg_loading">Načítam …</string>
+
     <string name="text_app_description">\n\n\nSimple TV Application for AndroidTV or SetTopBox with Android or any tablet or mobile device.\nAll in one solution for mobile app responsive to device.\nThis app is just an simple demonstration of Jetpack Compose and all other modern architecture components.\n\n\n</string>
     <string name="text_unimplemented_yet">Táto funkcia žiaľ ešte nie je implementovaná.</string>
 

+ 2 - 1
app/src/main/res/values/strings.xml

@@ -22,6 +22,8 @@
     <string name="menu_title_exit">Exit</string>
     <string name="menu_title_home">Home</string>
 
+    <string name="msg_loading">Loading…</string>
+
     <string name="text_app_description">\n\n\nSimple TV Application for AndroidTV or SetTopBox with Android or any tablet or mobile device.\nAll in one solution for mobile app responsive to device.\nThis app is just an simple demonstration of Jetpack Compose and all other modern architecture components.\n\n\n</string>
     <string name="text_unimplemented_yet">This feature is not yet implemented.</string>
 
@@ -41,5 +43,4 @@
     <string name="title_video_local">Local video files</string>
     <string name="title_photo_local">Local photo files</string>
 
-
 </resources>

+ 2 - 1
settings.gradle.kts

@@ -48,4 +48,5 @@ gradleEnterprise {
 }
 
 rootProject.name = "TvApp"
-include(":app")
+include(":app")
+include(":tvlib")

+ 1 - 0
tvlib/.gitignore

@@ -0,0 +1 @@
+/build

+ 153 - 0
tvlib/build.gradle.kts

@@ -0,0 +1,153 @@
+@file:Suppress("UnstableApiUsage")
+
+/*
+ * Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+plugins {
+    id("com.android.library")
+    kotlin("android")
+    kotlin("kapt")
+    id("com.google.dagger.hilt.android")
+    id("dagger.hilt.android.plugin")
+    id("org.jetbrains.dokka") version "1.8.10"
+}
+
+android {
+    namespace = "org.mjdev.tvlib"
+    compileSdk = 34
+
+    defaultConfig {
+        minSdk = 21
+        targetSdk = 34
+        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+        consumerProguardFiles("consumer-rules.pro")
+    }
+
+    buildTypes {
+        release {
+            isMinifyEnabled = false
+            proguardFiles(
+                getDefaultProguardFile("proguard-android-optimize.txt"),
+                "proguard-rules.pro"
+            )
+        }
+    }
+
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_17
+        targetCompatibility = JavaVersion.VERSION_17
+    }
+
+    kotlinOptions {
+        jvmTarget = JavaVersion.VERSION_17.toString()
+    }
+
+    buildFeatures {
+        compose = true
+        buildConfig = true
+    }
+
+    composeOptions {
+        kotlinCompilerExtensionVersion = "1.3.2"
+    }
+
+    packaging {
+        resources.excludes.add("/META-INF/{AL2.0,LGPL2.1}")
+    }
+
+    lint {
+        checkReleaseBuilds = false
+    }
+
+}
+
+dependencies {
+    // base libs
+    implementation("androidx.core:core-ktx:1.12.0-alpha05")
+    // reflect / debug purposes only
+    implementation(kotlin("reflect", "1.8.21"))
+    // window manager
+    implementation("androidx.window:window:1.1.0")
+    // compose base libs
+    implementation(platform("androidx.compose:compose-bom:2023.06.01"))
+    implementation("androidx.compose.ui:ui-tooling")
+    implementation("androidx.activity:activity-compose:1.7.2")
+    // more icons
+    implementation("androidx.compose.material:material-icons-extended:1.4.3")
+    // tv compose
+    implementation("androidx.tv:tv-foundation:1.0.0-SNAPSHOT")
+    implementation("androidx.tv:tv-material:1.0.0-alpha07")
+    // paging
+    implementation("androidx.paging:paging-compose:3.2.0-rc01")
+    // view model
+    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
+    // navigation
+    implementation("androidx.navigation:navigation-compose:2.7.0-beta02")
+    // image loading
+    implementation("io.coil-kt:coil-base:2.4.0")
+    implementation("io.coil-kt:coil-gif:2.2.2")
+    implementation("io.coil-kt:coil-svg:1.2.2")
+    implementation("io.coil-kt:coil-video:1.2.2")
+    implementation("io.coil-kt:coil-compose:2.4.0")
+    implementation("com.github.skydoves:landscapist-coil:2.2.2")
+    // constraint layout // todo remove
+    implementation("androidx.constraintlayout:constraintlayout-compose:1.0.1")
+    // debug
+    implementation("com.jakewharton.timber:timber:5.0.1")
+    // dagger core
+    implementation("com.google.dagger:dagger:2.46.1")
+    implementation("androidx.compose.material3:material3:1.1.1")
+    kapt("com.google.dagger:dagger-compiler:2.46.1")
+    // dagger android
+    implementation("com.google.dagger:dagger-android:2.46.1")
+    implementation("com.google.dagger:dagger-android-support:2.46.1")
+    kapt("com.google.dagger:dagger-android-processor:2.46.1")
+    // dagger - hilt
+    implementation("com.google.dagger:hilt-android:2.46.1")
+    implementation("androidx.hilt:hilt-navigation-compose:1.1.0-alpha01")
+    kapt("com.google.dagger:hilt-compiler:2.46.1")
+    // encrypt data
+    implementation("com.scottyab:aescrypt:0.0.1")
+    // exoplayer
+    implementation("androidx.media3:media3-exoplayer:1.1.0")
+    implementation("androidx.media3:media3-exoplayer-dash:1.1.0")
+    implementation("androidx.media3:media3-exoplayer-hls:1.1.0")
+    implementation("androidx.media3:media3-exoplayer-rtsp:1.1.0")
+    implementation("androidx.media3:media3-exoplayer-ima:1.1.0")
+    implementation("androidx.media3:media3-datasource-cronet:1.1.0")
+    implementation("androidx.media3:media3-datasource-okhttp:1.1.0")
+    implementation("androidx.media3:media3-datasource-rtmp:1.1.0")
+    implementation("androidx.media3:media3-ui:1.1.0")
+    implementation("androidx.media3:media3-ui-leanback:1.1.0")
+    implementation("androidx.media3:media3-session:1.1.0")
+    implementation("androidx.media3:media3-extractor:1.1.0")
+    implementation("androidx.media3:media3-cast:1.1.0")
+    implementation("androidx.media3:media3-exoplayer-workmanager:1.1.0")
+    implementation("androidx.media3:media3-transformer:1.1.0")
+    implementation("androidx.media3:media3-database:1.1.0")
+    implementation("androidx.media3:media3-decoder:1.1.0")
+    implementation("androidx.media3:media3-datasource:1.1.0")
+    implementation("androidx.media3:media3-common:1.1.0")
+    // permission
+    implementation("com.google.accompanist:accompanist-permissions:0.31.5-beta")
+    // for previews
+    debugImplementation("androidx.customview:customview-poolingcontainer:1.0.0")
+    // constraints
+    constraints {
+        implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0")?.apply {
+            because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib")
+        }
+        implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0")?.apply {
+            because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib")
+        }
+    }
+    // testing
+    testImplementation("junit:junit:4.13.2")
+    androidTestImplementation("androidx.test.ext:junit:1.1.5")
+    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+}

+ 0 - 0
tvlib/consumer-rules.pro


+ 21 - 0
tvlib/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 10 - 0
tvlib/src/main/AndroidManifest.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (c) Milan Jurkulák 2023.
+  ~  Contact:
+  ~  e: mimoccc@gmail.com
+  ~  e: mj@mjdev.org
+  ~  w: https://mjdev.org
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" />

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/activity/ActivityResultHandler.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/activity/ActivityResultHandler.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.activity
+package org.mjdev.tvlib.activity
 
 import android.content.Intent
 import androidx.lifecycle.Lifecycle

+ 15 - 14
app/src/main/kotlin/org/mjdev/tvapp/base/activity/ComposableActivity.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/activity/ComposableActivity.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.activity
+package org.mjdev.tvlib.activity
 
 import android.content.Intent
 import android.os.Bundle
@@ -25,18 +25,19 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.core.view.WindowCompat
 import androidx.tv.material3.ExperimentalTvMaterial3Api
+import androidx.tv.material3.MaterialTheme
 import androidx.tv.material3.NonInteractiveSurfaceDefaults
 import androidx.tv.material3.Surface
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.ContextExt.isATv
-import org.mjdev.tvapp.base.extensions.NavExt.rememberNavControllerEx
-import org.mjdev.tvapp.base.extensions.NavGraphBuilderExt.screen
-import org.mjdev.tvapp.base.ui.components.screen.EmptyScreen
-import org.mjdev.tvapp.base.navigation.NavGraphBuilderEx
-import org.mjdev.tvapp.base.ui.components.navigation.NavHostEx
-import org.mjdev.tvapp.ui.theme.TVAppTheme
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.ContextExt.isATv
+import org.mjdev.tvlib.extensions.NavExt.rememberNavControllerEx
+import org.mjdev.tvlib.extensions.NavGraphBuilderExt.screen
+import org.mjdev.tvlib.navigation.NavGraphBuilderEx
+import org.mjdev.tvlib.ui.components.navigation.NavHostEx
+import org.mjdev.tvlib.ui.components.screen.EmptyScreen
 import timber.log.Timber
 
+// todo theme
 @Suppress("MemberVisibilityCanBePrivate", "unused", "LeakingThis")
 open class ComposableActivity : ComponentActivity() {
 
@@ -58,7 +59,7 @@ open class ComposableActivity : ComponentActivity() {
 
         val navController = rememberNavControllerEx()
 
-        TVAppTheme {
+        MaterialTheme {
             Surface(
                 modifier = Modifier
                     .background(backgroundColor, backgroundShape)

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/annotations/TvPreview.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/annotations/TvPreview.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.annotations
+package org.mjdev.tvlib.annotations
 
 import android.content.res.Configuration.UI_MODE_TYPE_TELEVISION
 import androidx.compose.ui.tooling.preview.Devices

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/AnimExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/AnimExt.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.fadeIn

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/BitmapExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/BitmapExt.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.graphics.Bitmap
 

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ColorFilterExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ColorFilterExt.kt

@@ -8,7 +8,7 @@
 
 @file:Suppress("unused")
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import androidx.annotation.FloatRange
 import androidx.compose.ui.graphics.ColorFilter

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

@@ -1,14 +1,14 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
 @file:Suppress("unused")
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.annotation.SuppressLint
 import android.content.ContentResolver
@@ -30,14 +30,10 @@ import coil.ImageLoader
 import coil.decode.GifDecoder
 import coil.decode.ImageDecoderDecoder
 import coil.request.CachePolicy
-import org.mjdev.tvapp.BuildConfig
 
 @Suppress("MemberVisibilityCanBePrivate")
 object ComposeExt {
 
-    @Composable
-    fun isDebug() = BuildConfig.DEBUG
-
     @Composable
     fun isEditMode() = LocalInspectionMode.current
 

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ContextExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ContextExt.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.app.UiModeManager
 import android.content.Context

+ 2 - 2
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/CursorExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/CursorExt.kt

@@ -6,14 +6,14 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.database.Cursor
 import androidx.core.database.getBlobOrNull
 import androidx.core.database.getFloatOrNull
 import androidx.core.database.getIntOrNull
 import androidx.core.database.getStringOrNull
-import org.mjdev.tvapp.base.helpers.cursor.CachingCursor
+import org.mjdev.tvlib.helpers.cursor.CachingCursor
 import timber.log.Timber
 
 object CursorExt {

+ 6 - 6
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/DrawableExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/DrawableExt.kt

@@ -1,18 +1,18 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.graphics.drawable.Drawable
 import androidx.compose.ui.graphics.ImageBitmap
 import androidx.compose.ui.graphics.asImageBitmap
 import androidx.core.graphics.drawable.toBitmap
-import org.mjdev.tvapp.base.ui.drawable.PhotoDrawable
+import org.mjdev.tvlib.ui.drawable.PhotoDrawable
 
 object DrawableExt {
 

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/GlobalExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/GlobalExt.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.os.Handler
 import timber.log.Timber

+ 46 - 7
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/HiltExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/HiltExt.kt

@@ -1,16 +1,17 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.app.Activity
 import android.content.Context
 import android.content.ContextWrapper
+import android.os.Bundle
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.platform.LocalContext
 import androidx.lifecycle.ViewModel
@@ -20,8 +21,15 @@ import androidx.lifecycle.viewmodel.CreationExtras
 import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
 import androidx.lifecycle.viewmodel.compose.viewModel
 import androidx.navigation.NavBackStackEntry
-import dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.createInternal
-import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
+import androidx.savedstate.SavedStateRegistryOwner
+import dagger.hilt.EntryPoint
+import dagger.hilt.EntryPoints
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
+import dagger.hilt.android.internal.builders.ViewModelComponentBuilder
+import dagger.hilt.android.internal.lifecycle.HiltViewModelFactory
+import dagger.hilt.android.internal.lifecycle.HiltViewModelMap
+import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import kotlin.reflect.KClass
 import kotlin.reflect.full.companionObject
 import kotlin.reflect.full.functions
@@ -100,6 +108,37 @@ object HiltExt {
         }
     }
 
+    fun createInternal(
+        activity: Activity,
+        owner: SavedStateRegistryOwner,
+        defaultArgs: Bundle?,
+        delegateFactory: ViewModelProvider.Factory
+    ): ViewModelProvider.Factory {
+        return createInternal(activity, delegateFactory)
+    }
+
+    fun createInternal(
+        activity: Activity, delegateFactory: ViewModelProvider.Factory
+    ): ViewModelProvider.Factory {
+        val entryPoint = EntryPoints.get(
+            activity,
+            ActivityCreatorEntryPoint::class.java
+        )
+        return HiltViewModelFactory(
+            entryPoint.viewModelKeys,
+            delegateFactory,
+            entryPoint.viewModelComponentBuilder
+        )
+    }
+
+    @EntryPoint
+    @InstallIn(ActivityComponent::class)
+    internal interface ActivityCreatorEntryPoint {
+        @get:HiltViewModelMap.KeySet
+        val viewModelKeys: Set<String?>
+        val viewModelComponentBuilder: ViewModelComponentBuilder
+    }
+
     private fun createInternal(
         context: Context,
         modelCreator: MutableMap<KClass<*>, (context: Context) -> Any>.() -> Unit

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ListExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ListExt.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import androidx.core.os.bundleOf
 

+ 59 - 55
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ModifierExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ModifierExt.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.annotation.SuppressLint
 import androidx.compose.foundation.gestures.detectTapGestures
@@ -34,13 +34,16 @@ import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.platform.debugInspectorInfo
 import androidx.compose.ui.unit.dp
 import kotlinx.coroutines.delay
+import org.mjdev.tvlib.BuildConfig
 import timber.log.Timber
 import java.lang.Float.min
-import org.mjdev.tvapp.BuildConfig
 
 @Suppress("MemberVisibilityCanBePrivate")
 object ModifierExt {
 
+    // used to debug library
+    val isDebug = false
+
     fun Modifier.conditional(
         condition: Boolean,
         other: Modifier.() -> Modifier
@@ -85,63 +88,64 @@ object ModifierExt {
 
     @Stable
     fun Modifier.recomposeHighlighter(): Modifier = conditional(
-        BuildConfig.DEBUG_RECOMPOSE
+        isDebug
     ) { this.then(recomposeModifier) }
 
     @SuppressLint("AutoboxingStateValueProperty")
     private val recomposeModifier = Modifier.composed(
         inspectorInfo = debugInspectorInfo {
-            name = "recomposeHighlighter" }) {
-            val totalCompositions = remember { arrayOf(0L) }
-            totalCompositions[0]++
-            val totalCompositionsAtLastTimeout = remember { mutableLongStateOf(0L) }
-            LaunchedEffect(totalCompositions[0]) {
-                delay(3000)
-                totalCompositionsAtLastTimeout.value = totalCompositions[0]
-            }
-            Modifier.drawWithCache {
-                onDrawWithContent {
-                    drawContent()
-                    val numCompositionsSinceTimeout =
-                        totalCompositions[0] - totalCompositionsAtLastTimeout.value
-                    val hasValidBorderParams = size.minDimension > 0f
-                    if (!hasValidBorderParams || numCompositionsSinceTimeout <= 0) {
-                        return@onDrawWithContent
-                    }
-                    val (color, strokeWidthPx) =
-                        when (numCompositionsSinceTimeout) {
-                            1L -> Color.Blue to 1f
-                            2L -> Color.Green to 2.dp.toPx()
-                            else -> {
-                                lerp(
-                                    Color.Yellow.copy(alpha = 0.8f),
-                                    Color.Red.copy(alpha = 0.5f),
-                                    min(
-                                        1f,
-                                        (numCompositionsSinceTimeout - 1).toFloat() / 100f
-                                    )
-                                ) to numCompositionsSinceTimeout.toInt().dp.toPx()
-                            }
+            name = "recomposeHighlighter"
+        }) {
+        val totalCompositions = remember { arrayOf(0L) }
+        totalCompositions[0]++
+        val totalCompositionsAtLastTimeout = remember { mutableLongStateOf(0L) }
+        LaunchedEffect(totalCompositions[0]) {
+            delay(3000)
+            totalCompositionsAtLastTimeout.value = totalCompositions[0]
+        }
+        Modifier.drawWithCache {
+            onDrawWithContent {
+                drawContent()
+                val numCompositionsSinceTimeout =
+                    totalCompositions[0] - totalCompositionsAtLastTimeout.value
+                val hasValidBorderParams = size.minDimension > 0f
+                if (!hasValidBorderParams || numCompositionsSinceTimeout <= 0) {
+                    return@onDrawWithContent
+                }
+                val (color, strokeWidthPx) =
+                    when (numCompositionsSinceTimeout) {
+                        1L -> Color.Blue to 1f
+                        2L -> Color.Green to 2.dp.toPx()
+                        else -> {
+                            lerp(
+                                Color.Yellow.copy(alpha = 0.8f),
+                                Color.Red.copy(alpha = 0.5f),
+                                min(
+                                    1f,
+                                    (numCompositionsSinceTimeout - 1).toFloat() / 100f
+                                )
+                            ) to numCompositionsSinceTimeout.toInt().dp.toPx()
                         }
+                    }
 
-                    val halfStroke = strokeWidthPx / 2
-                    val topLeft = Offset(halfStroke, halfStroke)
-                    val borderSize = Size(
-                        size.width - strokeWidthPx,
-                        size.height - strokeWidthPx
-                    )
-                    val fillArea = (strokeWidthPx * 2) > size.minDimension
-                    val rectTopLeft = if (fillArea) Offset.Zero else topLeft
-                    val size = if (fillArea) size else borderSize
-                    val style = if (fillArea) Fill else Stroke(strokeWidthPx)
-                    drawRect(
-                        brush = SolidColor(color),
-                        topLeft = rectTopLeft,
-                        size = size,
-                        style = style
-                    )
-                }
+                val halfStroke = strokeWidthPx / 2
+                val topLeft = Offset(halfStroke, halfStroke)
+                val borderSize = Size(
+                    size.width - strokeWidthPx,
+                    size.height - strokeWidthPx
+                )
+                val fillArea = (strokeWidthPx * 2) > size.minDimension
+                val rectTopLeft = if (fillArea) Offset.Zero else topLeft
+                val size = if (fillArea) size else borderSize
+                val style = if (fillArea) Fill else Stroke(strokeWidthPx)
+                drawRect(
+                    brush = SolidColor(color),
+                    topLeft = rectTopLeft,
+                    size = size,
+                    style = style
+                )
             }
         }
+    }
 
 }

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/NavBackStackEntryExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/NavBackStackEntryExt.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import androidx.navigation.NavBackStackEntry
 

+ 3 - 3
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/NavControllerExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/NavControllerExt.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.os.Bundle
 import androidx.annotation.MainThread
@@ -15,8 +15,8 @@ import androidx.navigation.NavHostController
 import androidx.navigation.NavOptions
 import androidx.navigation.Navigator
 import androidx.navigation.navOptions
-import org.mjdev.tvapp.base.extensions.ListExt.toBundle
-import org.mjdev.tvapp.base.screen.Screen
+import org.mjdev.tvlib.extensions.ListExt.toBundle
+import org.mjdev.tvlib.screen.Screen
 import kotlin.reflect.full.createInstance
 
 @Suppress("MemberVisibilityCanBePrivate")

+ 7 - 7
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/NavExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/NavExt.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.content.Context
 import androidx.compose.runtime.Composable
@@ -19,8 +19,8 @@ import androidx.navigation.Navigator
 import androidx.navigation.NavigatorProvider
 import androidx.navigation.compose.ComposeNavigator
 import androidx.navigation.compose.DialogNavigator
-import org.mjdev.tvapp.base.navigation.NavGraphBuilderEx
-import org.mjdev.tvapp.base.navigation.NavHostControllerEx
+import org.mjdev.tvlib.navigation.NavGraphBuilderEx
+import org.mjdev.tvlib.navigation.NavHostControllerEx
 
 object NavExt {
 

+ 4 - 4
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/NavGraphBuilderExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/NavGraphBuilderExt.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import androidx.compose.animation.AnimatedContentTransitionScope
 import androidx.compose.animation.EnterTransition
@@ -14,9 +14,9 @@ import androidx.compose.animation.ExitTransition
 import androidx.navigation.NavBackStackEntry
 import androidx.navigation.NavDeepLink
 import androidx.navigation.compose.composable
-import org.mjdev.tvapp.base.extensions.NavBackStackEntryExt.arg
-import org.mjdev.tvapp.base.navigation.NavGraphBuilderEx
-import org.mjdev.tvapp.base.screen.Screen
+import org.mjdev.tvlib.extensions.NavBackStackEntryExt.arg
+import org.mjdev.tvlib.navigation.NavGraphBuilderEx
+import org.mjdev.tvlib.screen.Screen
 
 object NavGraphBuilderExt {
 

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/StringExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/StringExt.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.net.Uri
 

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ViewExt.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ViewExt.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.extensions
+package org.mjdev.tvlib.extensions
 
 import android.graphics.Bitmap
 import android.graphics.Canvas

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/BrushBuilder.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/BrushBuilder.kt

@@ -8,7 +8,7 @@
 
 @file:Suppress("unused")
 
-package org.mjdev.tvapp.base.helpers
+package org.mjdev.tvlib.helpers
 
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawBehind

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/LifeCycle.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/LifeCycle.kt

@@ -8,7 +8,7 @@
 
 @file:Suppress("unused")
 
-package org.mjdev.tvapp.base.helpers
+package org.mjdev.tvlib.helpers
 
 import android.annotation.SuppressLint
 import androidx.compose.runtime.Composable

+ 37 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/SquashedOval.kt

@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.helpers
+
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Outline
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+
+class SquashedOval : Shape {
+    override fun createOutline(
+        size: Size,
+        layoutDirection: LayoutDirection,
+        density: Density
+    ): Outline {
+        val path = Path().apply {
+            addOval(
+                Rect(
+                    left = size.width / 4f,
+                    top = 0f,
+                    right = size.width * 3 / 4f,
+                    bottom = size.height
+                )
+            )
+        }
+        return Outline.Generic(path = path)
+    }
+}

+ 4 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/apps/AppsManager.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/apps/AppsManager.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.helpers.apps
+package org.mjdev.tvlib.helpers.apps
 
 import android.content.Context
 import android.content.Intent
@@ -15,12 +15,11 @@ import android.graphics.drawable.Drawable
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.interfaces.ItemWithIntent
-import org.mjdev.tvapp.base.interfaces.ItemWithTitle
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.interfaces.ItemWithIntent
+import org.mjdev.tvlib.interfaces.ItemWithTitle
 import java.util.Collections
 
-// todo saveable, parcelable is too big
 @Composable
 fun rememberAppsManager(): List<App> {
     val context: Context = LocalContext.current

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/cursor/AudioCursor.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/AudioCursor.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.helpers.cursor
+package org.mjdev.tvlib.helpers.cursor
 
 import android.content.ContentResolver
 import android.content.Context

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/cursor/AudioItem.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/AudioItem.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.helpers.cursor
+package org.mjdev.tvlib.helpers.cursor
 
 import android.content.ContentResolver
 import android.database.Cursor
@@ -14,10 +14,10 @@ import android.net.Uri
 import android.os.Build
 import android.provider.MediaStore
 import android.util.Size
-import org.mjdev.tvapp.base.extensions.CursorExt.asMap
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.interfaces.ItemWithTitle
-import org.mjdev.tvapp.base.interfaces.ItemWithUri
+import org.mjdev.tvlib.extensions.CursorExt.asMap
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.interfaces.ItemWithTitle
+import org.mjdev.tvlib.interfaces.ItemWithUri
 import timber.log.Timber
 
 @Suppress("unused")

+ 2 - 2
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/cursor/CachingCursor.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/CachingCursor.kt

@@ -8,7 +8,7 @@
 
 @file:Suppress("unused")
 
-package org.mjdev.tvapp.base.helpers.cursor
+package org.mjdev.tvlib.helpers.cursor
 
 import android.annotation.SuppressLint
 import android.content.ContentResolver
@@ -28,7 +28,7 @@ import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.platform.LocalContext
-import org.mjdev.tvapp.base.extensions.CursorExt.isNotEmpty
+import org.mjdev.tvlib.extensions.CursorExt.isNotEmpty
 import timber.log.Timber
 
 @Suppress("FunctionName")

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/cursor/PhotoCursor.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/PhotoCursor.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.helpers.cursor
+package org.mjdev.tvlib.helpers.cursor
 
 import android.content.ContentResolver
 import android.content.Context

+ 4 - 4
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/cursor/PhotoItem.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/PhotoItem.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.helpers.cursor
+package org.mjdev.tvlib.helpers.cursor
 
 import android.content.ContentResolver
 import android.database.Cursor
@@ -14,9 +14,9 @@ import android.net.Uri
 import android.os.Build
 import android.provider.MediaStore
 import android.util.Size
-import org.mjdev.tvapp.base.extensions.CursorExt.asMap
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.interfaces.ItemWithTitle
+import org.mjdev.tvlib.extensions.CursorExt.asMap
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.interfaces.ItemWithTitle
 import timber.log.Timber
 
 @Suppress( "unused")

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/cursor/VideoCursor.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/VideoCursor.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.helpers.cursor
+package org.mjdev.tvlib.helpers.cursor
 
 import android.content.ContentResolver
 import android.content.Context

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/helpers/cursor/VideoItem.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/helpers/cursor/VideoItem.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.helpers.cursor
+package org.mjdev.tvlib.helpers.cursor
 
 import android.content.ContentResolver
 import android.database.Cursor
@@ -14,10 +14,10 @@ import android.net.Uri
 import android.os.Build
 import android.provider.MediaStore
 import android.util.Size
-import org.mjdev.tvapp.base.extensions.CursorExt.asMap
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.interfaces.ItemWithTitle
-import org.mjdev.tvapp.base.interfaces.ItemWithUri
+import org.mjdev.tvlib.extensions.CursorExt.asMap
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.interfaces.ItemWithTitle
+import org.mjdev.tvlib.interfaces.ItemWithUri
 import timber.log.Timber
 
 @Suppress("unused")

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemAudio.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemAudio.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 @Suppress("unused")
 class ItemAudio {

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemPhoto.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemPhoto.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 @Suppress("unused")
 class ItemPhoto {

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemVideo.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemVideo.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 @Suppress("unused")
 class ItemVideo {

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithBackground.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithBackground.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 interface ItemWithBackground<T> {
     val background: T?

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithDescription.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithDescription.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 interface ItemWithDescription<T> {
     val description: T?

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithId.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithId.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 interface ItemWithId {
     val id: Long

+ 13 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithImage.kt

@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.interfaces
+
+interface ItemWithImage<T> {
+    val image : T?
+}

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithIntent.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithIntent.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 import android.content.Intent
 

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithMessage.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithMessage.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 interface ItemWithMessage<T> {
     val message: T?

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithSubtitle.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithSubtitle.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 interface ItemWithSubtitle <T>{
     val subtitle: T?

+ 13 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithTitle.kt

@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.interfaces
+
+interface ItemWithTitle<T> {
+    val title : T?
+}

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/interfaces/ItemWithUri.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/interfaces/ItemWithUri.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.interfaces
+package org.mjdev.tvlib.interfaces
 
 interface ItemWithUri<T> {
 

+ 3 - 2
app/src/main/kotlin/org/mjdev/tvapp/base/navigation/AnyType.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/AnyType.kt

@@ -6,11 +6,12 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.navigation
+package org.mjdev.tvlib.navigation
 
 import android.os.Bundle
 import androidx.core.os.bundleOf
 import androidx.navigation.NavType
+import java.lang.RuntimeException
 
 @Suppress("DEPRECATION")
 object AnyType : NavType<Any?>(isNullableAllowed = true) {
@@ -20,7 +21,7 @@ object AnyType : NavType<Any?>(isNullableAllowed = true) {
     }
 
     override fun parseValue(value: String): Any? {
-        TODO("Not yet implemented")
+        throw(RuntimeException("Not yet implemented."))
     }
 
     override fun put(bundle: Bundle, key: String, value: Any?) {

+ 3 - 3
app/src/main/kotlin/org/mjdev/tvapp/base/navigation/MenuItem.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/MenuItem.kt

@@ -6,14 +6,14 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.navigation
+package org.mjdev.tvlib.navigation
 
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.ExitToApp
 import androidx.compose.material.icons.filled.Search
 import androidx.compose.material.icons.filled.Settings
-import org.mjdev.tvapp.R
-import org.mjdev.tvapp.base.ui.components.page.Page
+import org.mjdev.tvlib.R
+import org.mjdev.tvlib.ui.components.page.Page
 
 @Suppress("unused")
 data class MenuItem(

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/navigation/MenuItemClickListener.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/MenuItemClickListener.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.navigation
+package org.mjdev.tvlib.navigation
 
 interface MenuItemClickListener {
 

+ 2 - 2
app/src/main/kotlin/org/mjdev/tvapp/base/navigation/NavGraphBuilderEx.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/NavGraphBuilderEx.kt

@@ -6,12 +6,12 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.navigation
+package org.mjdev.tvlib.navigation
 
 import androidx.navigation.NavGraph
 import androidx.navigation.NavGraphBuilder
 import androidx.navigation.NavigatorProvider
-import org.mjdev.tvapp.base.ui.components.screen.EmptyScreen.Companion.ROUTE_NONE
+import org.mjdev.tvlib.ui.components.screen.EmptyScreen.Companion.ROUTE_NONE
 
 class NavGraphBuilderEx(
     provider: NavigatorProvider,

+ 2 - 2
app/src/main/kotlin/org/mjdev/tvapp/base/navigation/NavHostControllerEx.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/navigation/NavHostControllerEx.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.navigation
+package org.mjdev.tvlib.navigation
 
 import android.annotation.SuppressLint
 import android.content.Context
@@ -23,7 +23,7 @@ import androidx.navigation.NavHostController
 import androidx.tv.material3.DrawerState
 import androidx.tv.material3.DrawerValue
 import androidx.tv.material3.ExperimentalTvMaterial3Api
-import org.mjdev.tvapp.base.extensions.ListExt.addUnique
+import org.mjdev.tvlib.extensions.ListExt.addUnique
 
 // todo apply lifecycle
 @Suppress("unused", "MemberVisibilityCanBePrivate")

+ 9 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/network/CacheInterceptor.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/network/CacheInterceptor.kt

@@ -1,4 +1,12 @@
-package org.mjdev.tvapp.base.network
+/*
+ * Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.network
 
 import okhttp3.CacheControl
 import okhttp3.Interceptor

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/network/ConnectivityCallback.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/network/ConnectivityCallback.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.network
+package org.mjdev.tvlib.network
 
 import android.net.ConnectivityManager
 import android.net.Network

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/network/NetworkConnectivityService.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/network/NetworkConnectivityService.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.network
+package org.mjdev.tvlib.network
 
 import kotlinx.coroutines.flow.Flow
 

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/network/NetworkConnectivityServiceImpl.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/network/NetworkConnectivityServiceImpl.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.network
+package org.mjdev.tvlib.network
 
 import android.content.Context
 import android.net.ConnectivityManager

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/network/NetworkStatus.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/network/NetworkStatus.kt

@@ -1,14 +1,14 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
 @file:Suppress("unused")
 
-package org.mjdev.tvapp.base.network
+package org.mjdev.tvlib.network
 
 import android.net.Network
 import androidx.compose.runtime.State

+ 1 - 1
app/src/main/kotlin/org/mjdev/tvapp/base/paging/ListPagingSource.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/paging/ListPagingSource.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.paging
+package org.mjdev.tvlib.paging
 
 import androidx.paging.PagingSource
 import androidx.paging.PagingState

+ 36 - 27
app/src/main/kotlin/org/mjdev/tvapp/base/permission/PermissonManager.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/permission/PermissonManager.kt

@@ -8,7 +8,7 @@
 
 @file:Suppress("MemberVisibilityCanBePrivate")
 
-package org.mjdev.tvapp.base.permission
+package org.mjdev.tvlib.permission
 
 import android.annotation.SuppressLint
 import android.content.pm.PackageInfo
@@ -23,31 +23,38 @@ import androidx.lifecycle.LifecycleEventObserver
 import com.google.accompanist.permissions.ExperimentalPermissionsApi
 import com.google.accompanist.permissions.MultiplePermissionsState
 import com.google.accompanist.permissions.rememberMultiplePermissionsState
-import org.mjdev.tvapp.BuildConfig
+import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
+import timber.log.Timber
 
 @Composable
 fun manifestPermissions(): List<String> {
     val context = LocalContext.current
     return rememberSaveable {
-        val packageManager = context.packageManager
-        arrayListOf<String>().apply {
-            val pkgInfo: PackageInfo = packageManager.getPackageInfo(
-                BuildConfig.APPLICATION_ID,
-                PackageManager.GET_PERMISSIONS
-            )
-            pkgInfo.requestedPermissions.forEach { p -> add(p) }
+        try {
+            val packageManager = context.packageManager
+            arrayListOf<String>().apply {
+                val pkgInfo: PackageInfo = packageManager.getPackageInfo(
+                    context.packageName,
+                    PackageManager.GET_PERMISSIONS
+                )
+                pkgInfo.requestedPermissions.forEach { p -> add(p) }
+            }
+        } catch (e: Exception) {
+            Timber.e(e)
+            emptyList()
         }
     }
 }
 
+@OptIn(ExperimentalPermissionsApi::class)
 @Suppress("LocalVariableName")
 @SuppressLint("ComposableNaming")
-@OptIn(ExperimentalPermissionsApi::class)
 @Composable
 fun rememberPermissionManager(
     permissions: List<String> = manifestPermissions(),
     onNeedToGrant: MultiplePermissionsState.(permissions: List<String>) -> Unit = {}
 ) {
+    val isEdit = isEditMode()
     var _ps: MultiplePermissionsState? = null
     val lifecycleOwner = LocalLifecycleOwner.current
     val onPermissionsResult: (Map<String, Boolean>) -> Unit = { map ->
@@ -61,23 +68,25 @@ fun rememberPermissionManager(
             }
         }
     }
-    val permissionsState = rememberMultiplePermissionsState(
-        permissions = permissions,
-        onPermissionsResult = onPermissionsResult
-    )
-    _ps = permissionsState
-    DisposableEffect(
-        key1 = lifecycleOwner,
-        effect = {
-            val observer = LifecycleEventObserver { _, event ->
-                if (event == Lifecycle.Event.ON_RESUME) {
-                    permissionsState.launchMultiplePermissionRequest()
+    if (!isEdit) {
+        val permissionsState = rememberMultiplePermissionsState(
+            permissions = permissions,
+            onPermissionsResult = onPermissionsResult
+        )
+        _ps = permissionsState
+        DisposableEffect(
+            key1 = lifecycleOwner,
+            effect = {
+                val observer = LifecycleEventObserver { _, event ->
+                    if (event == Lifecycle.Event.ON_RESUME) {
+                        permissionsState.launchMultiplePermissionRequest()
+                    }
+                }
+                lifecycleOwner.lifecycle.addObserver(observer)
+                onDispose {
+                    lifecycleOwner.lifecycle.removeObserver(observer)
                 }
             }
-            lifecycleOwner.lifecycle.addObserver(observer)
-            onDispose {
-                lifecycleOwner.lifecycle.removeObserver(observer)
-            }
-        }
-    )
+        )
+    }
 }

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/screen/Screen.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/screen/Screen.kt

@@ -8,7 +8,7 @@
 
 @file:Suppress("MemberVisibilityCanBePrivate")
 
-package org.mjdev.tvapp.base.screen
+package org.mjdev.tvlib.screen
 
 import androidx.annotation.CallSuper
 import androidx.compose.foundation.background
@@ -29,10 +29,10 @@ import androidx.compose.ui.unit.sp
 import androidx.navigation.NamedNavArgument
 import androidx.navigation.NavBackStackEntry
 import androidx.tv.material3.Text
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.NavExt.rememberNavControllerEx
-import org.mjdev.tvapp.base.navigation.MenuItem
-import org.mjdev.tvapp.base.navigation.NavHostControllerEx
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.NavExt.rememberNavControllerEx
+import org.mjdev.tvlib.navigation.MenuItem
+import org.mjdev.tvlib.navigation.NavHostControllerEx
 
 @Suppress("unused", "LeakingThis")
 open class Screen {

+ 5 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/screen/ScreenWithPages.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/screen/ScreenWithPages.kt

@@ -6,13 +6,13 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.screen
+package org.mjdev.tvlib.screen
 
 import androidx.compose.runtime.Composable
-import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.NavExt.rememberNavControllerEx
-import org.mjdev.tvapp.base.ui.components.page.TvPager
-import org.mjdev.tvapp.base.ui.components.page.PagerScope
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.NavExt.rememberNavControllerEx
+import org.mjdev.tvlib.ui.components.page.PagerScope
+import org.mjdev.tvlib.ui.components.page.TvPager
 
 open class ScreenWithPages : Screen() {
 

+ 4 - 4
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/badge/Badge.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/badge/Badge.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.badge
+package org.mjdev.tvlib.ui.components.badge
 
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.runtime.Composable
@@ -19,9 +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 org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
-import org.mjdev.tvapp.base.ui.components.complex.FocusableBox
-import org.mjdev.tvapp.base.ui.components.text.CircleText
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.ui.components.complex.FocusableBox
+import org.mjdev.tvlib.ui.components.text.CircleText
 
 @Preview
 @Composable

+ 8 - 8
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/button/Button.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/button/Button.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.button
+package org.mjdev.tvlib.ui.components.button
 
 import android.annotation.SuppressLint
 import androidx.compose.foundation.BorderStroke
@@ -32,9 +32,9 @@ import androidx.tv.material3.ButtonGlow
 import androidx.tv.material3.ButtonScale
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Glow
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
-import org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
-import org.mjdev.tvapp.base.ui.components.text.TextAny
+import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusState
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.ui.components.text.TextAny
 
 
 @Suppress("UNUSED_PARAMETER")

+ 3 - 3
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/Card.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/Card.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.card
+package org.mjdev.tvlib.ui.components.card
 
 import android.annotation.SuppressLint
 import androidx.compose.foundation.BorderStroke
@@ -35,8 +35,8 @@ import androidx.tv.material3.CardScale
 import androidx.tv.material3.CardShape
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Glow
-import org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
-import org.mjdev.tvapp.base.extensions.ModifierExt.tvAspectRatio
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.extensions.ModifierExt.tvAspectRatio
 
 @SuppressLint("ModifierParameter")
 @OptIn(ExperimentalTvMaterial3Api::class)

+ 7 - 7
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/CardContent.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/CardContent.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.card
+package org.mjdev.tvlib.ui.components.card
 
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -16,8 +16,8 @@ import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.tv.material3.MaterialTheme
 import androidx.tv.material3.ProvideTextStyle
-import org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
-import org.mjdev.tvapp.base.ui.components.text.AutoHideEmptyText
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.ui.components.text.AutoHideEmptyText
 
 @Preview
 @Composable

+ 12 - 12
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/ItemCard.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/ItemCard.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.card
+package org.mjdev.tvlib.ui.components.card
 
 import android.annotation.SuppressLint
 import androidx.compose.foundation.layout.fillMaxSize
@@ -25,13 +25,13 @@ import androidx.tv.material3.CardGlow
 import androidx.tv.material3.CardScale
 import androidx.tv.material3.CardShape
 import androidx.tv.material3.ExperimentalTvMaterial3Api
-import org.mjdev.tvapp.base.extensions.ComposeExt.computeCardWidth
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
-import org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
-import org.mjdev.tvapp.base.interfaces.ItemWithDescription
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.ui.components.complex.FocusableCard
-import org.mjdev.tvapp.base.ui.components.image.ImageAny
+import org.mjdev.tvlib.extensions.ComposeExt.computeCardWidth
+import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusState
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.interfaces.ItemWithDescription
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.ui.components.complex.FocusableCard
+import org.mjdev.tvlib.ui.components.image.ImageAny
 
 @SuppressLint("ModifierParameter")
 @OptIn(ExperimentalTvMaterial3Api::class)

+ 14 - 7
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/PhotoCard.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PhotoCard.kt

@@ -6,9 +6,10 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.card
+package org.mjdev.tvlib.ui.components.card
 
 import android.annotation.SuppressLint
+import androidx.annotation.FloatRange
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.ui.Modifier
 import androidx.compose.runtime.Composable
@@ -21,12 +22,12 @@ import androidx.compose.ui.unit.Dp
 import androidx.tv.material3.CardDefaults
 import androidx.tv.material3.CardScale
 import androidx.tv.material3.ExperimentalTvMaterial3Api
-import org.mjdev.tvapp.base.extensions.ComposeExt.computeCardWidth
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
-import org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
-import org.mjdev.tvapp.base.interfaces.ItemWithDescription
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.ui.components.image.PhotoImage
+import org.mjdev.tvlib.extensions.ComposeExt.computeCardWidth
+import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusState
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.interfaces.ItemWithDescription
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.ui.components.image.PhotoImage
 
 @SuppressLint("ModifierParameter")
 @OptIn(ExperimentalTvMaterial3Api::class)
@@ -38,11 +39,17 @@ fun PhotoCard(
     contentScale: ContentScale = ContentScale.Crop,
     textColor: Color = Color.White,
     focusState: MutableState<FocusState?> = rememberFocusState(item),
+    @FloatRange(from = 0.0, to = 10.0)
+    contrast: Float = 5f,
+    @FloatRange(from = -255.0, to = 255.0)
+    brightness: Float = -255f,
     imageRenderer: @Composable () -> Unit = {
         PhotoImage(
             modifier = Modifier.fillMaxSize(),
             src = (item as? ItemWithImage<*>)?.image,
             contentScale = contentScale,
+            contrast = contrast,
+            brightness = brightness,
             contentDescription = (item as? ItemWithDescription<*>)?.description?.toString(),
         )
     },

+ 8 - 7
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/PreviewCard.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PreviewCard.kt

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.card
+package org.mjdev.tvlib.ui.components.card
 
 import android.graphics.Bitmap
 import android.media.MediaMetadataRetriever
@@ -50,9 +50,10 @@ import coil.compose.AsyncImage
 import coil.compose.rememberAsyncImagePainter
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
-import org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
-import org.mjdev.tvapp.base.extensions.ModifierExt.tvAspectRatio
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.extensions.ModifierExt.tvAspectRatio
 
+// todo
 @OptIn(ExperimentalTvMaterial3Api::class)
 @Suppress("unused")
 @UnstableApi

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

@@ -1,12 +1,12 @@
 /*
  * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.carousel
+package org.mjdev.tvlib.ui.components.carousel
 
 import android.annotation.SuppressLint
 import android.content.res.Configuration
@@ -32,8 +32,8 @@ import androidx.tv.material3.CardScale
 import androidx.tv.material3.Carousel
 import androidx.tv.material3.CarouselState
 import androidx.tv.material3.ExperimentalTvMaterial3Api
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
-import org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusState
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
 import kotlin.math.abs
 
 @SuppressLint("AutoboxingStateValueProperty")

+ 10 - 10
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/carousel/CarouselCard.kt → tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/carousel/CarouselCard.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.carousel
+package org.mjdev.tvlib.ui.components.carousel
 
 import android.annotation.SuppressLint
 import androidx.compose.foundation.layout.defaultMinSize
@@ -20,15 +20,15 @@ import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.CardScale
 import androidx.tv.material3.ExperimentalTvMaterial3Api
-import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
-import org.mjdev.tvapp.base.extensions.ModifierExt.conditional
-import org.mjdev.tvapp.base.extensions.ModifierExt.recomposeHighlighter
-import org.mjdev.tvapp.base.interfaces.ItemWithBackground
-import org.mjdev.tvapp.base.interfaces.ItemWithDescription
-import org.mjdev.tvapp.base.interfaces.ItemWithImage
-import org.mjdev.tvapp.base.ui.components.card.PhotoCard
-import org.mjdev.tvapp.base.ui.components.image.ImageAny
+import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
+import org.mjdev.tvlib.extensions.ComposeExt.rememberFocusState
+import org.mjdev.tvlib.extensions.ModifierExt.conditional
+import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
+import org.mjdev.tvlib.interfaces.ItemWithBackground
+import org.mjdev.tvlib.interfaces.ItemWithDescription
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.ui.components.card.PhotoCard
+import org.mjdev.tvlib.ui.components.image.ImageAny
 
 @SuppressLint("ModifierParameter")
 @OptIn(ExperimentalTvMaterial3Api::class)

Някои файлове не бяха показани, защото твърде много файлове са промени