Milan Jurkulak пре 2 година
родитељ
комит
7a5152ce26
100 измењених фајлова са 1831 додато и 802 уклоњено
  1. 99 164
      app/build.gradle.kts
  2. 0 20
      app/debug/output-metadata.json
  3. 21 12
      build.gradle.kts
  4. 29 18
      buildSrc/build.gradle.kts
  5. 242 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/dependency/DependencyHandler.kt
  6. 0 26
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/BuildConfig.kt
  7. 0 47
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/DependencyHandler.kt
  8. 46 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/PluginDependenciesSpecScope.kt
  9. 142 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/Project.kt
  10. 46 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/SigningConfigs.kt
  11. 19 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/String.kt
  12. 19 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/TestedExtension.kt
  13. 48 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/VariantDimension.kt
  14. 14 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/libs/Libs.kt
  15. 2 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/logger/CustomEventLogger.kt
  16. 0 57
      buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/CommonBinaryPlugin.kt
  17. 41 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/DependencyUpdatePlugin.kt
  18. 89 221
      buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/MainAppPlugin.kt
  19. 14 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/versions/Versions.kt
  20. 3 19
      gradle.properties
  21. 10 0
      release-notes.txt
  22. 1 2
      settings.gradle.kts
  23. 62 145
      tvlib/build.gradle.kts
  24. 1 1
      tvlib/src/main/kotlin/org/mjdev/tvlib/auth/AuthManager.kt
  25. 76 68
      tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ModifierExt.kt
  26. 46 0
      tvlib/src/main/kotlin/org/mjdev/tvlib/ui/shape/DiamondShape.kt
  27. 10 0
      wiki/Release-Notes-1.2.1.md
  28. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/-companion/-i-p-t-v_-d-a-t-a.md
  29. 12 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/-companion/index.md
  30. 9 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/-compose.md
  31. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/-i-p-t-v-activity.md
  32. 33 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/index.md
  33. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/nav-graph-builder.md
  34. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/on-intent.md
  35. 9 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-main-activity/-compose.md
  36. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-main-activity/-main-activity.md
  37. 27 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-main-activity/index.md
  38. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-main-activity/nav-graph-builder.md
  39. 9 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/-compose.md
  40. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/-web-activity.md
  41. 27 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/index.md
  42. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/nav-graph-builder.md
  43. 6 0
      wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/on-intent.md
  44. 11 0
      wiki/documentation/app/org.mjdev.tvapp.activity/index.md
  45. 6 0
      wiki/documentation/app/org.mjdev.tvapp.app/-application/-application.md
  46. 18 0
      wiki/documentation/app/org.mjdev.tvapp.app/-application/index.md
  47. 6 0
      wiki/documentation/app/org.mjdev.tvapp.app/-application/on-create.md
  48. 9 0
      wiki/documentation/app/org.mjdev.tvapp.app/index.md
  49. 8 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/-category.md
  50. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/equals.md
  51. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/hash-code.md
  52. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/id.md
  53. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/image.md
  54. 31 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/index.md
  55. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/subtitle.md
  56. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/title.md
  57. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-category/to-string.md
  58. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/-country.md
  59. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/code.md
  60. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/equals.md
  61. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/flag.md
  62. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/hash-code.md
  63. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/id.md
  64. 31 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/index.md
  65. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/languages.md
  66. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-country/name.md
  67. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/-message.md
  68. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/deleted.md
  69. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/equals.md
  70. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/hash-code.md
  71. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/id.md
  72. 31 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/index.md
  73. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/message.md
  74. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/read.md
  75. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-message/title.md
  76. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/-movie.md
  77. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/background.md
  78. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/category.md
  79. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/country.md
  80. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/description.md
  81. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/equals.md
  82. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/hash-code.md
  83. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/id.md
  84. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/image.md
  85. 37 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/index.md
  86. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/is-nsfw.md
  87. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/studio.md
  88. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/subtitle.md
  89. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/title.md
  90. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/uri.md
  91. 6 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/-companion/as-movie.md
  92. 12 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/-companion/index.md
  93. 8 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/-t-v-channel.md
  94. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/alt-names.md
  95. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/broadcast-area.md
  96. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/categories.md
  97. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/channel-id.md
  98. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/city.md
  99. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/closed.md
  100. 9 0
      wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/country.md

+ 99 - 164
app/build.gradle.kts

@@ -6,16 +6,34 @@
  * w: https://mjdev.org
  */
 
-import org.mjdev.gradle.extensions.implementation
-import org.mjdev.gradle.extensions.kapt
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.javaVersion
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.kotlinCompilerExtVersion
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.loadKeyStoreProperties
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.projectCompileSdk
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.projectMinSdk
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.suffixToString
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.versionCode
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.versionName
+import com.android.build.gradle.internal.api.BaseVariantOutputImpl
+import org.mjdev.gradle.dependency.anotherDependencies
+import org.mjdev.gradle.dependency.baseDependencies
+import org.mjdev.gradle.dependency.composeDependencies
+import org.mjdev.gradle.dependency.daggerDependencies
+import org.mjdev.gradle.dependency.encryptDependencies
+import org.mjdev.gradle.dependency.exoPlayerDependencies
+import org.mjdev.gradle.dependency.glideDependencies
+import org.mjdev.gradle.dependency.mjdevTvLib
+import org.mjdev.gradle.dependency.moshiDependencies
+import org.mjdev.gradle.dependency.okHttpDependencies
+import org.mjdev.gradle.dependency.permissionsDependencies
+import org.mjdev.gradle.dependency.retrofitDependencies
+import org.mjdev.gradle.dependency.sandwichDependencies
+import org.mjdev.gradle.dependency.testDependencies
+import org.mjdev.gradle.dependency.timberDependencies
+import org.mjdev.gradle.dependency.widgetDependencies
+import org.mjdev.gradle.extensions.buildConfigString
+import org.mjdev.gradle.extensions.loadKeyStoreProperties
+import org.mjdev.gradle.extensions.manifestPlaceholders
+import org.mjdev.gradle.extensions.stringRes
+import org.mjdev.gradle.extensions.suffixToString
+import org.mjdev.gradle.extensions.versionCode
+import org.mjdev.gradle.extensions.versionName
+import org.mjdev.gradle.plugin.javaVersion
+import org.mjdev.gradle.plugin.kotlinCompilerExtVersion
+import org.mjdev.gradle.plugin.projectCompileSdk
+import org.mjdev.gradle.plugin.projectMinSdk
 
 @Suppress("PropertyName")
 val CONFIG_KEYSTORE_PROPERTIES_FILE = "config/keystore.properties"
@@ -24,17 +42,27 @@ val CONFIG_KEYSTORE_PROPERTIES_FILE = "config/keystore.properties"
 val SIGNING_CONFIG_NAME = "Any"
 
 plugins {
-    id("com.android.application")
+//    kotlinAndroid()
+//    kotlinKapt()
+//    kotlinParcelize()
+//    androidApplication()
+//    hilt()
+//    ksp()
+//    mainAppPlugin()
+//    objectBox()
     kotlin("android")
+    kotlin("kapt")
+    id("com.android.application")
     id("kotlin-parcelize")
     id("com.google.dagger.hilt.android")
     id("dagger.hilt.android.plugin")
-    id("io.objectbox")
-    id("MainAppPlugin")
-    kotlin("kapt")
     id("com.google.devtools.ksp")
-//    id("org.jetbrains.dokka") version "1.8.10"
+//    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
 //    id ("app.cash.paparazzi") version "1.3.1"
+//    id("DependencyUpdatePlugin")
+//    id("AndroidCoreLibraryPlugin")
+    id("MainAppPlugin")
+    id("io.objectbox")
 }
 
 android {
@@ -65,16 +93,18 @@ android {
 
         signingConfig = signingConfigs[SIGNING_CONFIG_NAME]
 
-        buildConfigField("String", "IPTV_API_URL", "\"https://iptv-org.github.io/api/\"")
-        buildConfigField("String", "GITHUB_USER", "\"mimoccc\"")
-        buildConfigField("String", "GITHUB_REPOSITORY", "\"tvapp\"")
+        buildConfigString(
+            "IPTV_API_URL" to "https://iptv-org.github.io/api/",
+            "GITHUB_USER" to "mimoccc",
+            "GITHUB_REPOSITORY" to "tvapp"
+        )
 
         multiDexEnabled = true
 
-        manifestPlaceholders.apply {
-            put("auth0Domain", "@string/com_auth0_domain")
-            put("auth0Scheme", "demo")
-        }
+        manifestPlaceholders(
+            "auth0Domain" to "@string/com_auth0_domain",
+            "auth0Scheme" to "demo"
+        )
     }
 
     buildTypes {
@@ -90,20 +120,12 @@ android {
                 getDefaultProguardFile("proguard-android-optimize.txt"),
                 "proguard-rules.pro"
             )
-            buildConfigField(
-                "String",
-                "SYNC_AUTH",
-                "\"${defaultConfig.applicationId}$applicationIdSuffix.sync\""
-            )
-            resValue(
-                "string",
-                "sync_auth",
-                "${defaultConfig.applicationId}$applicationIdSuffix.sync"
+            buildConfigString(
+                "SYNC_AUTH" to "${defaultConfig.applicationId}$applicationIdSuffix.sync"
             )
-            resValue(
-                "string",
-                "app_name",
-                "TV App  ${applicationIdSuffix.suffixToString()}"
+            stringRes(
+                "sync_auth" to "${defaultConfig.applicationId}$applicationIdSuffix.sync",
+                "app_name" to "TV App ${applicationIdSuffix.suffixToString()}"
             )
         }
 
@@ -118,20 +140,12 @@ android {
                 getDefaultProguardFile("proguard-android-optimize.txt"),
                 "proguard-rules.pro"
             )
-            buildConfigField(
-                "String",
-                "SYNC_AUTH",
-                "\"${defaultConfig.applicationId}$applicationIdSuffix.sync\""
+            buildConfigString(
+                "SYNC_AUTH" to "\"${defaultConfig.applicationId}$applicationIdSuffix.sync\""
             )
-            resValue(
-                "string",
-                "sync_auth",
-                "${defaultConfig.applicationId}$applicationIdSuffix.sync"
-            )
-            resValue(
-                "string",
-                "app_name",
-                "TV App  ${applicationIdSuffix.suffixToString()}"
+            stringRes(
+                "sync_auth" to "${defaultConfig.applicationId}$applicationIdSuffix.sync",
+                "app_name" to "TV App ${applicationIdSuffix.suffixToString()}"
             )
         }
     }
@@ -166,128 +180,49 @@ android {
         checkReleaseBuilds = false
     }
 
+    kapt {
+        correctErrorTypes = true
+    }
+
     hilt {
         enableAggregatingTask = true
     }
 
-//    subprojects {
-//        apply(plugin = "org.jetbrains.dokka")
-//    }
-
-//    tasks.dokkaGfm {
-//        outputDirectory.set(File(projectDir, "../wiki/documentation"))
-//    }
-}
-
-dependencies {
-    // todo remove
-    implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.21")
-    // startups
-//    implementation("androidx.startup:startup-runtime:1.1.1")
-    // tv library by mjdev milan jurkulak
-    implementation(project(mapOf("path" to ":tvlib")))
-    // base libs
-    implementation("androidx.core:core-ktx:1.12.0")
-    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
-    // compose base libs
-    implementation(platform("androidx.compose:compose-bom:2023.10.01"))
-    implementation("androidx.compose.ui:ui-tooling")
-    implementation("androidx.activity:activity-compose:1.8.2")
-    // more icons
-    implementation("androidx.compose.material:material-icons-extended:1.5.4")
-    // tv compose
-    implementation("androidx.tv:tv-foundation:1.0.0-alpha10")
-    implementation("androidx.tv:tv-material:1.0.0-alpha10")
-    // dagger - hilt
-    implementation("com.google.dagger:dagger-android:2.50")
-    implementation("com.google.dagger:dagger-android-support:2.50")
-    implementation("com.google.dagger:dagger:2.50")
-    implementation("com.google.dagger:hilt-android:2.50")
-    implementation("androidx.hilt:hilt-navigation-compose:1.1.0")
-    // 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:5.0.0-alpha.12"))
-    implementation("com.squareup.okhttp3:okhttp")
-    implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.12")
-    // debug
-    implementation("com.jakewharton.timber:timber:5.0.1")
-    implementation("com.android.volley:volley:1.2.1")
-    // kapt
-    kapt("com.google.dagger:dagger-compiler:2.50")
-    kapt("com.google.dagger:dagger-android-processor:2.50")
-    kapt("com.google.dagger:hilt-compiler:2.50")
-    ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.0")
-    // view model
-    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
-    // navigation
-    implementation("androidx.navigation:navigation-compose:2.7.6")
-    // 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")
-    // sandwich
-    implementation("com.github.skydoves:sandwich:2.0.5")
-    implementation("com.github.skydoves:sandwich-retrofit:2.0.5")
-    // encrypt data
-    implementation("com.scottyab:aescrypt:0.0.1")
-    // permission
-    implementation("com.google.accompanist:accompanist-permissions:0.33.2-alpha")
-    // previews
-    debugImplementation("androidx.customview:customview-poolingcontainer:1.0.0")
-    // lottie
-    implementation("com.airbnb.android:lottie-compose:6.2.0")
-    // widgets
-    implementation("androidx.glance:glance-appwidget:1.0.0")
-    implementation("androidx.glance:glance-material:1.0.0")
-    implementation("androidx.glance:glance-material3:1.0.0")
-    // fix duplicates
-    implementation("androidx.work:work-runtime-ktx:2.9.0")
-    // image loading
-    implementation("com.github.bumptech.glide:okhttp3-integration:4.16.0")
-    implementation("com.github.bumptech.glide:compose:1.0.0-beta01")
-    implementation("com.github.skydoves:landscapist-glide:2.2.13")
-    implementation("com.github.skydoves:landscapist-transformation:2.2.13")
-    implementation("com.github.skydoves:landscapist-palette:2.2.13")
-    implementation("com.github.skydoves:landscapist-placeholder:2.2.13")
-    ksp("com.github.bumptech.glide:ksp:4.16.0")
-    // exoplayer
-    implementation("androidx.media3:media3-exoplayer:1.2.0")
-    implementation("androidx.media3:media3-exoplayer-dash:1.2.0")
-    implementation("androidx.media3:media3-exoplayer-hls:1.2.0")
-    implementation("androidx.media3:media3-exoplayer-rtsp:1.2.0")
-    implementation("androidx.media3:media3-datasource-cronet:1.2.0")
-    implementation("androidx.media3:media3-datasource-okhttp:1.2.0")
-    implementation("androidx.media3:media3-datasource-rtmp:1.2.0")
-    implementation("androidx.media3:media3-ui:1.2.0")
-    implementation("androidx.media3:media3-session:1.2.0")
-    implementation("androidx.media3:media3-extractor:1.2.0")
-    implementation("androidx.media3:media3-cast:1.2.0")
-    implementation("androidx.media3:media3-exoplayer-workmanager:1.2.0")
-    implementation("androidx.media3:media3-transformer:1.2.0")
-    implementation("androidx.media3:media3-database:1.2.0")
-    implementation("androidx.media3:media3-decoder:1.2.0")
-    implementation("androidx.media3:media3-datasource:1.2.0")
-    implementation("androidx.media3:media3-common:1.2.0")
-    // generative a.i.
-//    implementation("com.google.ai.client.generativeai:generativeai:0.1.1")
-    // 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")
-        }
-        implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0").apply {
-            because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib")
+    applicationVariants.all {
+        outputs.map {
+            it as BaseVariantOutputImpl
+        }.forEach { output ->
+            val outputFileName = "$applicationId-$versionName.apk"
+            output.outputFileName = outputFileName
         }
     }
-    // fix duplicates
-    @Suppress("UnstableApiUsage")
-    configurations {
-        all {
-            resolutionStrategy {
-                force("androidx.work:work-runtime-ktx:2.8.1")
-            }
+
+    tasks {
+        dokkaGfm {
+            outputDirectory.set(File(projectDir, "../wiki/documentation/"))
         }
     }
+
+    mainAppConfig {
+        createDocumentation = true
+    }
+}
+
+dependencies {
+    mjdevTvLib()
+    baseDependencies()
+    composeDependencies()
+    daggerDependencies()
+    moshiDependencies()
+    okHttpDependencies()
+    timberDependencies()
+    retrofitDependencies()
+    sandwichDependencies()
+    glideDependencies()
+    exoPlayerDependencies()
+    testDependencies()
+    encryptDependencies()
+    permissionsDependencies()
+    anotherDependencies()
+    widgetDependencies()
 }

+ 0 - 20
app/debug/output-metadata.json

@@ -1,20 +0,0 @@
-{
-  "version": 3,
-  "artifactType": {
-    "type": "APK",
-    "kind": "Directory"
-  },
-  "applicationId": "org.mjdev.tvapp.debug",
-  "variantName": "debug",
-  "elements": [
-    {
-      "type": "SINGLE",
-      "filters": [],
-      "attributes": [],
-      "versionCode": 10100,
-      "versionName": "1.1.0",
-      "outputFile": "app-debug.apk"
-    }
-  ],
-  "elementType": "File"
-}

+ 21 - 12
build.gradle.kts

@@ -7,39 +7,48 @@
  */
 
 plugins {
-    id("com.android.application") version "8.1.1" apply false
-    id("com.android.library") version "8.1.1" apply false
-    kotlin("android") version "1.7.20" apply false
     id("com.google.dagger.hilt.android") version "2.47" apply false
     id("com.google.devtools.ksp") version "1.9.0-1.0.11" apply false
     id("org.jlleitschuh.gradle.ktlint") version "11.3.2" apply true
+    id("org.jetbrains.dokka") version "1.8.10" apply true
     // todo ktorfit https://foso.github.io/Ktorfit/
 //    id("de.jensklingenberg.ktorfit") version "1.10.2" apply true
 }
 
-subprojects {
-    apply(plugin = "org.jlleitschuh.gradle.ktlint")
-}
-
 buildscript {
+
     repositories {
         mavenCentral()
         maven(url = "https://storage.googleapis.com/r8-releases/raw")
         maven(url = "https://mvn.dailymotion.com/repository/releases/")
         google()
     }
+
     dependencies {
-        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21")
-        classpath("com.android.tools:r8:8.1.72")
-        classpath("io.objectbox:objectbox-gradle-plugin:3.6.0")
-        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0")
         classpath("com.android.tools.build:gradle:8.2.0")
-        classpath("com.android.tools.build:gradle-api:8.1.4")
+        classpath("com.android.tools.build:gradle-api:8.2.0")
+        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0")
+        classpath("com.android.tools:r8:8.2.33")
+        classpath("io.objectbox:objectbox-gradle-plugin:3.7.1")
+//        classpath("com.github.ben-manes:gradle-versions-plugin:0.42.0")
+//        classpath("com.diffplug.spotless:spotless-plugin-gradle:6.4.2")
+//        classpath("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.20.0-RC2")
+//        classpath("com.bmuschko:gradle-docker-plugin:9.4.0")
+//        classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1")
 //        classpath("com.newrelic.agent.android:agent-gradle-plugin:5.9.0")
 //        classpath ("app.cash.paparazzi:paparazzi-gradle-plugin:1.3.1")
     }
 }
 
+allprojects {
+    apply(plugin = "org.jlleitschuh.gradle.ktlint")
+    apply(plugin = "org.jetbrains.dokka")
+}
+
+subprojects {
+    apply(plugin = "org.jetbrains.dokka")
+}
+
 tasks.register<Delete>("clean") {
     delete(rootProject.layout.buildDirectory)
 }

+ 29 - 18
buildSrc/build.gradle.kts

@@ -6,9 +6,7 @@
  * w: https://mjdev.org
  */
 
-@file:Suppress("DEPRECATION")
-
-@Suppress("JcenterRepositoryObsolete")
+@Suppress("DEPRECATION", "JcenterRepositoryObsolete")
 repositories {
     jcenter()
     google()
@@ -21,24 +19,25 @@ repositories {
 
 plugins {
     `kotlin-dsl`
-    `kotlin-dsl-precompiled-script-plugins`
-//    `java-gradle-plugin`
-//    `groovy-gradle-plugin`
-//    id("org.jetbrains.dokka") version "1.8.10"
-//    id("com.google.devtools.ksp")
+    `java-gradle-plugin`
+//    id("org.jetbrains.dokka") version "1.8.10" apply false
+//    id("io.gitlab.arturbosch.detekt")
+//    id("com.github.ben-manes.versions")
+//    id("com.bmuschko.docker-remote-api")
 }
 
 dependencies {
-    implementation(localGroovy())
     implementation(gradleApi())
+    implementation(gradleKotlinDsl())
+    implementation("com.android.tools.build:gradle-api:8.2.0")
+    implementation("com.android.tools.build:gradle:8.2.0")
+    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0")
+    implementation("com.squareup:javapoet:1.13.0")
 
-//    implementation("com.android.tools.build:gradle:3.4.2")
-//    implementation("com.android.tools.build:gradle-api:3.4.3")
-//    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0")
-//    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61")
-
+//    implementation("com.bmuschko:gradle-docker-plugin:9.4.0")
+//    implementation("org.jetbrains.dokka:dokka-android-gradle-plugin:0.9.18")
 //    implementation(kotlin("reflect", "1.8.21"))
-//    implementation("com.google.code.gson:gson:2.10.1")
+
 //    implementation("com.twelvemonkeys.imageio:imageio-core:3.9.4")
 //    implementation("com.twelvemonkeys.imageio:imageio-webp:3.9.4")
 //    implementation("com.twelvemonkeys.imageio:imageio-png:3.9.4")
@@ -71,16 +70,28 @@ dependencies {
 //    implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2")
 //    implementation("org.ini4j:ini4j:0.5.4")
 //    implementation("org.jsoup:jsoup:1.15.4")
+//    implementation("com.google.code.gson:gson:2.10.1")
 //    implementation("net.lingala.zip4j:zip4j:1.2.4")
 //    implementation("org.eclipse.jgit:org.eclipse.jgit:4.8.0.201706111038-r")
-//    implementation("org.jetbrains.dokka:dokka-android-gradle-plugin:0.9.18")
 }
 
 gradlePlugin {
     plugins {
-        create("MainAppPlugin") {
+        register("MainAppPlugin") {
             id = "MainAppPlugin"
+            displayName = "MainAppPlugin"
+            description = "Common app plugin to handle all stuffs needed."
             implementationClass = "org.mjdev.gradle.plugin.MainAppPlugin"
         }
+//        register("DependencyUpdatePlugin") {
+//            id = "DependencyUpdatePlugin"
+//            displayName = "DependencyUpdatePlugin"
+//            description = "Dependency update plugin"
+//            implementationClass = "org.mjdev.gradle.plugin.DependencyUpdatePlugin"
+//        }
+//        register("AndroidCoreLibraryPlugin") {
+//            id = "AndroidCoreLibraryPlugin"
+//            implementationClass = "commons.AndroidCoreLibraryPlugin"
+//        }
     }
-}
+}

+ 242 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/dependency/DependencyHandler.kt

@@ -0,0 +1,242 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+@file:Suppress("unused")
+
+package org.mjdev.gradle.dependency
+
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.dsl.DependencyHandler
+import kotlin.String
+
+fun DependencyHandler.debugImplementation(dependencyNotation: String): Dependency? =
+    add("debugImplementation", dependencyNotation)
+
+fun DependencyHandler.releaseImplementation(dependencyNotation: String): Dependency? =
+    add("releaseImplementation", dependencyNotation)
+
+fun DependencyHandler.testImplementation(dependencyNotation: String): Dependency? =
+    add("testImplementation", dependencyNotation)
+
+fun DependencyHandler.androidTestImplementation(dependencyNotation: String): Dependency? =
+    add("androidTestImplementation", dependencyNotation)
+
+fun DependencyHandler.androidTestImplementation(dependency: Dependency): Dependency? =
+    add("androidTestImplementation", dependency)
+
+fun DependencyHandler.testAnnotationProcessor(dependencyNotation: String): Dependency? =
+    add("testAnnotationProcessor", dependencyNotation)
+
+fun DependencyHandler.androidTestAnnotationProcessor(dependencyNotation: String): Dependency? =
+    add("androidTestAnnotationProcessor", dependencyNotation)
+
+fun DependencyHandler.implementation(dependencyNotation: String): Dependency? =
+    add("implementation", dependencyNotation)
+
+fun DependencyHandler.implementation(dependency: Dependency): Dependency? =
+    add("implementation", dependency)
+
+fun DependencyHandler.kapt(dependencyNotation: String): Dependency? =
+    add("kapt", dependencyNotation)
+
+fun DependencyHandler.ksp(dependencyNotation: String): Dependency? =
+    add("ksp", dependencyNotation)
+
+fun DependencyHandler.dokkaPlugin(dependencyNotation: String): Dependency? =
+    add("dokkaPlugin", dependencyNotation)
+
+fun DependencyHandler.mockDependencies() = arrayOf(
+    implementation("io.mockk:mockk:1.9")
+)
+
+fun DependencyHandler.okHttpDependencies() = arrayOf(
+    implementation(platform("com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.12")),
+    implementation("com.squareup.okhttp3:okhttp"),
+    implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.12"),
+)
+
+fun DependencyHandler.retrofitDependencies() = arrayOf(
+    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"),
+)
+
+fun DependencyHandler.moshiDependencies() = arrayOf(
+    implementation("com.squareup.moshi:moshi:1.15.0"),
+    implementation("com.squareup.retrofit2:converter-moshi:2.9.0"),
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"),
+    ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.0"),
+)
+
+fun DependencyHandler.exoPlayerDependencies() = arrayOf(
+    implementation("androidx.media3:media3-exoplayer:1.2.0"),
+    implementation("androidx.media3:media3-exoplayer-dash:1.2.0"),
+    implementation("androidx.media3:media3-exoplayer-hls:1.2.0"),
+    implementation("androidx.media3:media3-exoplayer-rtsp:1.2.0"),
+    implementation("androidx.media3:media3-datasource-cronet:1.2.0"),
+    implementation("androidx.media3:media3-datasource-okhttp:1.2.0"),
+    implementation("androidx.media3:media3-datasource-rtmp:1.2.0"),
+    implementation("androidx.media3:media3-ui:1.2.0"),
+    implementation("androidx.media3:media3-session:1.2.0"),
+    implementation("androidx.media3:media3-extractor:1.2.0"),
+    implementation("androidx.media3:media3-cast:1.2.0"),
+    implementation("androidx.media3:media3-exoplayer-workmanager:1.2.0"),
+    implementation("androidx.media3:media3-transformer:1.2.0"),
+    implementation("androidx.media3:media3-database:1.2.0"),
+    implementation("androidx.media3:media3-decoder:1.2.0"),
+    implementation("androidx.media3:media3-datasource:1.2.0"),
+    implementation("androidx.media3:media3-common:1.2.0"),
+    implementation("androidx.media3:media3-exoplayer-ima:1.1.0"),
+    implementation("androidx.media3:media3-ui-leanback:1.1.0"),
+)
+
+fun DependencyHandler.composeDependencies() = arrayOf(
+    implementation(platform("androidx.compose:compose-bom:2023.10.01")),
+    implementation("androidx.compose.ui:ui-tooling"),
+    implementation("androidx.activity:activity-compose:1.8.2"),
+    // more icons
+    implementation("androidx.compose.material:material-icons-extended:1.5.4"),
+    // tv compose
+    implementation("androidx.tv:tv-foundation:1.0.0-alpha10"),
+    implementation("androidx.tv:tv-material:1.0.0-alpha10"),
+    // view model
+    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2"),
+    // navigation
+    implementation("androidx.navigation:navigation-compose:2.7.6"),
+    // todo remove, dynamic background & colors
+    implementation("androidx.compose.material3:material3:1.1.2"),
+    // previews
+    debugImplementation("androidx.customview:customview-poolingcontainer:1.0.0"),
+    // foundation
+    implementation("androidx.compose.foundation:foundation:1.1.1"),
+)
+
+fun DependencyHandler.baseDependencies() = arrayOf(
+    // startups
+//    implementation("androidx.startup:startup-runtime:1.1.1"),
+    // dokka
+    dokkaPlugin("org.jetbrains.dokka:android-documentation-plugin:1.9.10"),
+    // core
+    implementation("androidx.core:core-ktx:1.12.0"),
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"),
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"),
+    // reflect / todo : remove
+    implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.22"),
+    // window manager
+    implementation("androidx.window:window:1.2.0"),
+    // fix duplicates
+    implementation("androidx.work:work-runtime-ktx:2.9.0"),
+)
+
+fun DependencyHandler.sandwichDependencies() = arrayOf(
+    implementation("com.github.skydoves:sandwich:2.0.5"),
+    implementation("com.github.skydoves:sandwich-retrofit:2.0.5"),
+)
+
+fun DependencyHandler.glideDependencies() = arrayOf(
+    // glide
+    implementation("com.github.bumptech.glide:okhttp3-integration:4.16.0"),
+    implementation("com.github.bumptech.glide:compose:1.0.0-beta01"),
+    // landscapist
+    implementation("com.github.skydoves:landscapist-glide:2.2.13"),
+    implementation("com.github.skydoves:landscapist-transformation:2.2.13"),
+    implementation("com.github.skydoves:landscapist-palette:2.2.13"),
+    implementation("com.github.skydoves:landscapist-placeholder:2.2.13"),
+    // glide annotations
+    ksp("com.github.bumptech.glide:ksp:4.16.0"),
+)
+
+fun DependencyHandler.daggerDependencies() = arrayOf(
+    // dagger
+    implementation("com.google.dagger:dagger:2.50"),
+    // dagger android
+    implementation("com.google.dagger:dagger-android:2.50"),
+    implementation("com.google.dagger:dagger-android-support:2.50"),
+    // dagger hilt
+    implementation("com.google.dagger:hilt-android:2.50"),
+    implementation("androidx.hilt:hilt-navigation-compose:1.1.0"),
+    // dagger annotations
+    kapt("com.google.dagger:dagger-compiler:2.50"),
+    kapt("com.google.dagger:dagger-android-processor:2.50"),
+    kapt("com.google.dagger:hilt-compiler:2.50"),
+)
+
+fun DependencyHandler.timberDependencies() = arrayOf(
+    implementation("com.jakewharton.timber:timber:5.0.1"),
+)
+
+fun DependencyHandler.oauthDependencies() = arrayOf(
+    implementation("com.auth0.android:auth0:2.10.2"),
+    implementation("com.auth0.android:jwtdecode:2.0.2"),
+)
+
+fun DependencyHandler.testDependencies() = arrayOf(
+    testImplementation("junit:junit:4.13.2"),
+    androidTestImplementation("androidx.test.ext:junit:1.1.5"),
+    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1"),
+    // anr
+    implementation("com.github.anrwatchdog:anrwatchdog:1.4.0"),
+)
+
+fun DependencyHandler.encryptDependencies() = arrayOf(
+    implementation("com.scottyab:aescrypt:0.0.1"),
+)
+
+fun DependencyHandler.permissionsDependencies() = arrayOf(
+// permission
+    implementation("com.google.accompanist:accompanist-permissions:0.33.2-alpha"),
+)
+
+fun DependencyHandler.widgetDependencies() = arrayOf(
+    implementation("androidx.glance:glance-appwidget:1.0.0"),
+    implementation("androidx.glance:glance-material:1.0.0"),
+    implementation("androidx.glance:glance-material3:1.0.0"),
+)
+
+fun DependencyHandler.anotherDependencies() = arrayOf(
+    // zxing
+    implementation("com.google.zxing:core:3.5.2"),
+    // svg
+    implementation("com.caverock:androidsvg-aar:1.4"),
+    // pallette
+    implementation("androidx.palette:palette-ktx:1.0.0"),
+    // lottie
+    implementation("com.airbnb.android:lottie-compose:6.2.0"),
+    // exif info
+    implementation("androidx.exifinterface:exifinterface:1.3.7"),
+    // jsoup
+    implementation("org.jsoup:jsoup:1.17.1"),
+    // dm
+    implementation("com.dailymotion.dailymotion-sdk-android:sdk:0.2.12"),
+    // dynamic theme
+    implementation("com.google.android.material:material:1.11.0"),
+    // stripe payments
+    implementation("com.stripe:stripe-android:20.33.0"),
+    implementation("com.stripe:stripecardscan:20.33.0"),
+    implementation("com.stripe:financial-connections:20.33.0"),
+    // scrape
+    implementation("net.sourceforge.htmlunit:htmlunit-android:2.67.0"),
+    // flip card
+    implementation("com.wajahatkarim:flippable:1.5.4"),
+    // ui controller
+//    implementation("com.google.accompanist:accompanist-systemuicontroller:0.23.1"),
+    // insets
+//    implementation("com.google.accompanist:accompanist-insets:0.23.1"),
+    // indicators
+//    implementation("com.google.accompanist:accompanist-pager-indicators:0.23.1"),
+    // settings
+//    implementation("com.github.alorma:compose-settings-ui-m3:1.3.0")
+    // yt
+    // ...
+    // a.i.
+//    implementation("com.google.ai.client.generativeai:generativeai:0.1.1"),
+)
+
+fun DependencyHandler.mjdevTvLib() = arrayOf(
+    implementation(project(mapOf("path" to ":tvlib")))
+)

+ 0 - 26
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/BuildConfig.kt

@@ -1,26 +0,0 @@
-/*
- *  Copyright (c) Milan Jurkulák 2023.
- *  Contact:
- *  e: mimoccc@gmail.com
- *  e: mj@mjdev.org
- *  w: https://mjdev.org
- */
-
-package org.mjdev.gradle.extensions
-
-//todo
-
-@Suppress("unused")
-object BuildConfig {
-
-//    fun VariantDimension.configFields(block: com.android.build.api.dsl.DefaultConfig.() -> Unit) {
-//        block.invoke(this)
-//    }
-
-//    fun DefaultConfig.boolean(vararg fields: Pair<String, Boolean>) {
-//        fields.forEach { pair ->
-//            buildConfigField("Boolean", pair.first, pair.second.toString())
-//        }
-//    }
-
-}

+ 0 - 47
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/DependencyHandler.kt

@@ -1,47 +0,0 @@
-/*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
- */
-
-// todo
-
-package org.mjdev.gradle.extensions
-
-import org.gradle.api.artifacts.Dependency
-import org.gradle.api.artifacts.dsl.DependencyHandler
-
-fun DependencyHandler.debugImplementation(dependencyNotation: String): Dependency? =
-    add("debugImplementation", dependencyNotation)
-
-fun DependencyHandler.releaseImplementation(dependencyNotation: String): Dependency? =
-    add("releaseImplementation", dependencyNotation)
-
-fun DependencyHandler.testImplementation(dependencyNotation: String): Dependency? =
-    add("testImplementation", dependencyNotation)
-
-fun DependencyHandler.androidTestImplementation(dependencyNotation: String): Dependency? =
-    add("androidTestImplementation", dependencyNotation)
-
-fun DependencyHandler.androidTestImplementation(dependency: Dependency): Dependency? =
-    add("androidTestImplementation", dependency)
-
-fun DependencyHandler.testAnnotationProcessor(dependencyNotation: String): Dependency? =
-    add("testAnnotationProcessor", dependencyNotation)
-
-fun DependencyHandler.androidTestAnnotationProcessor(dependencyNotation: String): Dependency? =
-    add("androidTestAnnotationProcessor", dependencyNotation)
-
-fun DependencyHandler.implementation(dependencyNotation: String): Dependency? =
-    add("implementation", dependencyNotation)
-
-fun DependencyHandler.implementation(dependency: Dependency): Dependency? =
-    add("implementation", dependency)
-
-fun DependencyHandler.kapt(dependencyNotation: String): Dependency? =
-    add("kapt", dependencyNotation)
-
-fun DependencyHandler.ksp(dependencyNotation: String): Dependency? =
-    add("ksp", dependencyNotation)

+ 46 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/PluginDependenciesSpecScope.kt

@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+@file:Suppress("unused")
+
+package org.mjdev.gradle.extensions
+
+import org.gradle.kotlin.dsl.PluginDependenciesSpecScope
+import org.gradle.kotlin.dsl.kotlin
+import org.gradle.plugin.use.PluginDependenciesSpec
+import org.gradle.plugin.use.PluginDependencySpec
+
+fun PluginDependenciesSpec.ksp(): PluginDependencySpec =
+    id("com.google.devtools.ksp")
+
+fun PluginDependenciesSpecScope.hilt(): PluginDependencySpec =
+    id("dagger.hilt.android.plugin")
+
+fun PluginDependenciesSpecScope.androidHilt(): PluginDependencySpec =
+    id("com.google.dagger.hilt.android")
+
+fun PluginDependenciesSpecScope.objectBox(): PluginDependencySpec =
+    id("io.objectbox")
+
+fun PluginDependenciesSpecScope.kotlinAndroid(): PluginDependencySpec =
+    kotlin("android")
+
+fun PluginDependenciesSpecScope.kotlinKapt(): PluginDependencySpec =
+    kotlin("kapt")
+
+fun PluginDependenciesSpecScope.kotlinParcelize(): PluginDependencySpec =
+    id("kotlin-parcelize")
+
+fun PluginDependenciesSpecScope.androidLibrary(): PluginDependencySpec =
+    id("com.android.library")
+
+fun PluginDependenciesSpecScope.androidApplication(): PluginDependencySpec =
+    id("com.android.application")
+
+fun PluginDependenciesSpecScope.mainAppPlugin(): PluginDependencySpec =
+    id("MainAppPlugin")

+ 142 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/Project.kt

@@ -0,0 +1,142 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+@file:Suppress("unused")
+
+package org.mjdev.gradle.extensions
+
+import com.android.build.api.dsl.ApplicationExtension
+import com.android.build.api.variant.AndroidComponentsExtension
+import com.android.build.gradle.BaseExtension
+import com.android.build.gradle.api.AndroidBasePlugin
+import org.gradle.api.Action
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.kotlin.dsl.extra
+import java.io.File
+import java.io.FileInputStream
+import java.util.Properties
+import java.util.regex.Pattern
+import kotlin.String
+
+private const val VERSION_TAG_MAJOR = "majorVersion"
+private const val VERSION_TAG_MINOR = "minorVersion"
+private const val VERSION_TAG_PATCH = "patchVersion"
+
+private const val TASK_DOKKA = "dokkaGfm"
+
+fun Project.android(): BaseExtension {
+    val android = project.extensions.findByType(BaseExtension::class.java)
+    if (android != null) {
+        return android
+    } else {
+        throw GradleException("Project $name is not an Android project")
+    }
+}
+
+val Project.versionCode
+    get(): Int {
+        val major = runCatching {
+            rootProject.extra.get(VERSION_TAG_MAJOR)?.toString()?.toInt()
+        }.getOrNull() ?: 1
+        val minor = runCatching {
+            rootProject.extra.get(VERSION_TAG_MINOR)?.toString()?.toInt()
+        }.getOrNull() ?: 0
+        val patch = runCatching {
+            rootProject.extra.get(VERSION_TAG_PATCH)?.toString()?.toInt()
+        }.getOrNull() ?: 0
+        return major * 10000 + minor * 100 + patch
+    }
+
+val Project.versionName: String
+    get() {
+        val major = runCatching {
+            rootProject.extra.get(VERSION_TAG_MAJOR)?.toString()?.toInt()
+        }.getOrNull() ?: 1
+        val minor = runCatching {
+            rootProject.extra.get(VERSION_TAG_MINOR)?.toString()?.toInt()
+        }.getOrNull() ?: 0
+        val patch = runCatching {
+            rootProject.extra.get(VERSION_TAG_PATCH)?.toString()?.toInt()
+        }.getOrNull() ?: 0
+        return "${major}.${minor}.${patch}"
+    }
+
+private val Project.taskRequestsStr
+    get() = gradle.startParameter.taskRequests.toString()
+
+val Project.currentFlavor: String
+    get() {
+        val pattern: Pattern = if (taskRequestsStr.contains("assemble")) {
+            Pattern.compile("assemble(\\w+)(Release|Debug)")
+        } else {
+            Pattern.compile("bundle(\\w+)(Release|Debug)")
+        }
+        val matcher = pattern.matcher(taskRequestsStr)
+        val flavor = if (matcher.find()) {
+            matcher.group(1).lowercase()
+        } else {
+            ""
+        }
+        return flavor
+    }
+
+val Project.dokkaGfm get() = tasks.findByName(TASK_DOKKA)
+
+inline fun <reified T : Task> Project.registerTask(
+    name: String,
+    block: Action<T>
+) = project.tasks.register(name, T::class.java).configure(block)
+
+val Project.android
+    get() = extensions.getByType(ApplicationExtension::class.java)
+
+val Project.androidComponents
+    get() = extensions.getByType(AndroidComponentsExtension::class.java)
+
+val Project.containsAndroidPlugin: Boolean
+    get() = project.plugins.toList().any { plugin -> plugin is AndroidBasePlugin }
+
+fun Project.loadKeyStoreProperties(
+    signConfigFilePath: String,
+    block: (keyAlias: String, keyPassword: String, storeFile: File, storePassword: String) -> Unit
+) {
+    val keystorePropertiesFile = project.rootProject.file(signConfigFilePath)
+    val keystoreProperties = Properties()
+    if (keystorePropertiesFile.exists()) {
+        keystoreProperties.load(FileInputStream(keystorePropertiesFile))
+    } else {
+        keystoreProperties["keyAlias"] = System.getenv("KEYSTORE_KEY_ALIAS").orEmpty()
+        keystoreProperties["keyPassword"] = System.getenv("KEYSTORE_KEY_PASSWORD").orEmpty()
+        keystoreProperties["storePassword"] =
+            System.getenv("KEYSTORE_STORE_PASSWORD").orEmpty()
+        keystoreProperties["storeFile"] = System.getenv("KEYSTORE_FILE").orEmpty()
+    }
+    block.invoke(
+        keystoreProperties["keyAlias"] as String? ?: "",
+        keystoreProperties["keyPassword"] as? String? ?: "",
+        File(projectDir, keystoreProperties["storeFile"] as? String? ?: ""),
+        keystoreProperties["storePassword"] as? String? ?: ""
+    )
+}
+
+fun Project.propOrDef(propertyName: String, defaultValue: Any): Any = project
+    .properties[propertyName] ?: (System.getenv(propertyName) ?: defaultValue)
+
+fun Project.getFile(vararg fileNames: String): File? {
+    for (fileName in fileNames) {
+        val file = rootProject.file(fileName)
+        if (file.exists()) {
+            return file
+        }
+    }
+    return null
+}
+
+fun Project.propertyOrEmpty(name: String): String = findProperty(name) as String? ?: ""

+ 46 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/SigningConfigs.kt

@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.extensions
+
+//import com.android.build.gradle.BaseExtension
+//import org.gradle.api.Project
+//import java.io.FileInputStream
+//import java.util.*
+//import kotlin.String
+
+//    fun BaseExtension.setSigningConfigs(
+//        project: Project
+//    ) = signingConfigs {
+//        create("signingConfigRelease") {
+//            val rootProject = project.rootProject
+//            val keystorePropertiesFile = rootProject.file("signing/release.signing.properties")
+//            if (!keystorePropertiesFile.exists()) {
+//                System.err.println("📜 Missing release.signing.properties file for release signing")
+//            } else {
+//                val keystoreProperties = Properties().apply {
+//                    load(FileInputStream(keystorePropertiesFile))
+//                }
+//                try {
+//                    storeFile = rootProject.file(keystoreProperties["storeFile"] as String)
+//                    storePassword = keystoreProperties["storePassword"] as String
+//                    keyAlias = keystoreProperties["keyAlias"] as String
+//                    keyPassword = keystoreProperties["keyPassword"] as String
+//                } catch (e: Exception) {
+//                    System.err.println("📜 release.signing.properties file is malformed")
+//                }
+//            }
+//        }
+//
+//        getByName("debug") {
+//            storeFile = project.rootProject.file("signing/debug.keystore")
+//            keyAlias = "androiddebugkey"
+//            keyPassword = "android"
+//            storePassword = "android"
+//        }
+//    }

+ 19 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/String.kt

@@ -0,0 +1,19 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.extensions
+
+import java.util.Locale
+import kotlin.String
+
+fun String.capitalize() = replaceFirstChar {
+    if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
+}
+
+fun String?.suffixToString() =
+    (this ?: "").replace(".", "").capitalize()

+ 19 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/TestedExtension.kt

@@ -0,0 +1,19 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.extensions
+
+//import com.android.build.gradle.AppExtension
+//import com.android.build.gradle.LibraryExtension
+//import com.android.build.gradle.TestedExtension
+
+//    fun TestedExtension.variants() = when (this) {
+//        is AppExtension -> applicationVariants
+//        is LibraryExtension -> libraryVariants
+//        else -> throw GradleException("Unsupported BaseExtension type!")
+//    }

+ 48 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/VariantDimension.kt

@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+@file:Suppress("unused")
+
+package org.mjdev.gradle.extensions
+
+import com.android.build.api.dsl.VariantDimension
+import kotlin.String
+
+fun VariantDimension.buildConfigBoolean(
+    vararg fields: Pair<String, Boolean>
+) {
+    fields.forEach { pair ->
+        buildConfigField("Boolean", pair.first, pair.second.toString())
+    }
+}
+
+fun VariantDimension.buildConfigString(
+    vararg fields: Pair<String, String>
+) {
+    fields.forEach { pair ->
+        buildConfigField("String", pair.first, "\"${pair.second}\"")
+    }
+}
+
+fun VariantDimension.stringRes(
+    vararg fields: Pair<String, String>
+) {
+    fields.forEach { pair ->
+        resValue("string", pair.first, pair.second)
+    }
+}
+
+fun VariantDimension.manifestPlaceholders(
+    vararg fields: Pair<String, Any>
+) {
+    manifestPlaceholders.apply {
+        fields.forEach { pair ->
+            put(pair.first, pair.second)
+        }
+    }
+}

+ 14 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/libs/Libs.kt

@@ -0,0 +1,14 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.libs
+
+@Suppress("unused")
+object Libs {
+
+}

+ 2 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/helper/CustomEventLogger.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/logger/CustomEventLogger.kt

@@ -8,7 +8,7 @@
 
 @file:Suppress("DEPRECATION")
 
-package org.mjdev.gradle.helper
+package org.mjdev.gradle.logger
 
 import org.gradle.BuildAdapter
 import org.gradle.BuildResult
@@ -17,7 +17,7 @@ import org.gradle.api.execution.TaskExecutionListener
 import org.gradle.api.tasks.TaskState
 
 // todo all messages handling and remove non errors
-@Suppress("deprecation")
+@Suppress("deprecation", "unused")
 class CustomEventLogger : BuildAdapter(), TaskExecutionListener {
 
     override fun beforeExecute(task: Task) {

+ 0 - 57
buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/CommonBinaryPlugin.kt

@@ -1,57 +0,0 @@
-/*
- *  Copyright (c) Milan Jurkulák 2023.
- *  Contact:
- *  e: mimoccc@gmail.com
- *  e: mj@mjdev.org
- *  w: https://mjdev.org
- */
-
-package org.mjdev.gradle.plugin
-
-//class CommonBinaryPlugin : Plugin<Project> {
-
-//    private val Project.android: BaseExtension
-//        get() = extensions.findByName("android") as? BaseExtension
-//            ?: error("Not an Android module: $name")
-
-//    override fun apply(project: Project) {
-//        with(project) {
-//            applyPlugins()
-//            androidConfig()
-//            dependenciesConfig()
-//        }
-//    }
-
-//    private fun Project.applyPlugins() {
-//        plugins.run {
-//            apply("com.android.library")
-//            apply("kotlin-android")
-//            apply("kotlin-android-extensions")
-//        }
-//    }
-
-//    private fun Project.androidConfig() {
-//        android.run {
-//            compileSdkVersion(29)
-//            defaultConfig {
-//                minSdkVersion(23)
-//                targetSdkVersion(29)
-//                versionCode = 1
-//                versionName = "1.0"
-//                testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
-//            }
-//            buildTypes {
-//                getByName("debug") {
-//                    isMinifyEnabled = false
-//                }
-//            }
-//        }
-//    }
-
-//    private fun Project.dependenciesConfig() {
-//        dependencies {
-//            "implementation"("androidx.appcompat:appcompat:1.1.0")
-//        }
-//    }
-
-//}

+ 41 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/DependencyUpdatePlugin.kt

@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+@file:Suppress("unused")
+
+package org.mjdev.gradle.plugin
+
+//import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import java.util.*
+
+class DependencyUpdatePlugin : Plugin<Project> {
+    override fun apply(project: Project) = with(project) {
+//        tasks.named("dependencyUpdates", DependencyUpdatesTask::class.java).configure {
+//            rejectVersionIf {
+//                isNonStable(candidate.version)
+//            }
+//            outputFormatter = "html"
+//            doLast {
+//                exec {
+//                    commandLine("open", "build/dependencyUpdates/report.html")
+//                }
+//            }
+//        }
+    }
+
+    private fun isNonStable(version: String): Boolean {
+        val stableKeyword = listOf("RELEASE", "FINAL", "GA").any {
+            version.uppercase(Locale.getDefault()).contains(it)
+        }
+        val regex = "^[0-9,.v-]+(-r)?$".toRegex()
+        val isStable = stableKeyword || regex.matches(version)
+        return isStable.not()
+    }
+}

+ 89 - 221
buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/MainAppPlugin.kt

@@ -6,266 +6,134 @@
  * w: https://mjdev.org
  */
 
-@file:Suppress("unused")
-
 package org.mjdev.gradle.plugin
 
-import org.gradle.api.Action
 import org.gradle.api.JavaVersion
 import org.gradle.api.Plugin
 import org.gradle.api.Project
-import org.gradle.api.Task
+import org.gradle.api.provider.Property
 import org.gradle.api.tasks.Exec
 import org.gradle.kotlin.dsl.extra
-import org.mjdev.gradle.helper.CustomEventLogger
+import org.mjdev.gradle.extensions.containsAndroidPlugin
 import java.io.File
 import java.io.FileInputStream
-import java.util.Locale
 import java.util.Properties
+import org.mjdev.gradle.extensions.dokkaGfm
+import org.mjdev.gradle.extensions.versionName
+import org.mjdev.gradle.extensions.registerTask
 
-// todo
-@Suppress("UsePropertyAccessSyntax", "MemberVisibilityCanBePrivate")
-abstract class MainAppPlugin : Plugin<Project> {
-
-    companion object {
-
-        const val CONFIG_VERSION_PROPERTIES_FILE = "config/version.properties"
-        const val CONFIG_KEYSTORE_PROPERTIES_FILE = "config/keystore.properties"
-        const val SIGNING_CONFIG_NAME = "Any"
-
-        const val TASK_PREPARE_RELEASE_NOTES = "prepareReleaseNotes"
-//        const val TASK_DOKKA = "dokkaGfm"
-
-        const val TASK_ASSEMBLE_RELEASE = "assembleRelease"
-        const val TASK_ASSEMBLE_DEBUG = "assembleDebug"
-        const val TASK_ASSEMBLE_MINIFIED = "assembleMinified"
-        const val TASK_ASSEMBLE_MOCK = "assembleMock"
-
-        private const val VERSION_TAG_MAJOR = "majorVersion"
-        private const val VERSION_TAG_MINOR = "minorVersion"
-        private const val VERSION_TAG_PATCH = "patchVersion"
-
-        val Project.versionCode
-            get(): Int {
-                val major = rootProject.extra.get(VERSION_TAG_MAJOR)?.toString()?.toInt() ?: 1
-                val minor = rootProject.extra.get(VERSION_TAG_MINOR)?.toString()?.toInt() ?: 0
-                val patch = rootProject.extra.get(VERSION_TAG_PATCH)?.toString()?.toInt() ?: 0
-                return major * 10000 + minor * 100 + patch
-            }
-
-        val Project.versionName
-            get(): String {
-                val major = rootProject.extra.get(VERSION_TAG_MAJOR)?.toString()?.toInt() ?: 1
-                val minor = rootProject.extra.get(VERSION_TAG_MINOR)?.toString()?.toInt() ?: 0
-                val patch = rootProject.extra.get(VERSION_TAG_PATCH)?.toString()?.toInt() ?: 0
-                return "${major}.${minor}.${patch}"
-            }
-
-        fun String.capitalize() = replaceFirstChar {
-            if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
-        }
-
-        fun String?.suffixToString() = (this ?: "").replace(".", "").capitalize()
-
-        val javaVersion: JavaVersion = JavaVersion.VERSION_17
-
-        const val projectCompileSdk: Int = 34
-        const val projectMinSdk = 21
-
-        const val kotlinCompilerExtVersion = "1.5.1"
-
-        inline fun <reified T : Task> Project.registerTask(
-            name: String,
-            block: Action<T>
-        ) = project.tasks.register(name, T::class.java).configure(block)
-
-//        fun DependencyHandler.implementCore(): Array<Dependency?> = arrayOf(
-//            // base, kotlin & etc
-//            implementation("androidx.core:core-ktx:1.10.1"),
-//            implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.7.0")),
-//            // reflection just for view models, unfinished compose libs
-//            implementation(kotlin("reflect", "1.8.21") as String)
-//        )
-
-//        fun DependencyHandler.implementLifeCycle(): Array<Dependency?> = arrayOf(
-//            // base, kotlin & etc
-//            implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1"),
-//        )
-
-//        fun DependencyHandler.implementCoroutines(): Array<Dependency?> = arrayOf(
-//            // coroutines
-//            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1"),
-//            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1"),
-//        )
-
-//        fun DependencyHandler.implementDagger(): Array<Dependency?> = arrayOf(
-//            // dagger core
-//            implementation("com.google.dagger:dagger:2.46.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"),
-//        )
-
-//        fun DependencyHandler.implementHilt(): Array<Dependency?> = arrayOf(
-//            // dagger - hilt
-//            implementation("com.google.dagger:hilt-android:2.46.1"),
-//            kapt("com.google.dagger:hilt-compiler:2.46.1"),
-//        )
-
-//        fun DependencyHandler.implementThemeMaterial3() = arrayOf(
-//            // material
-//            implementation("com.google.android.material:material:1.9.0"),
-//        )
-
-//        fun DependencyHandler.implementCompose() = arrayOf(
-//            // compose things
-//            implementation(platform("androidx.compose:compose-bom:2023.05.01")),
-//            implementation("androidx.activity:activity-compose:1.7.2"),
-//            implementation("androidx.compose.ui:ui:1.4.3"),
-//            implementation("androidx.compose.ui:ui-graphics:1.4.3"),
-//            implementation("androidx.compose.ui:ui-tooling-preview:1.4.3"),
-//            implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.1"),
-//            implementation("androidx.compose.material3:material3:1.1.0"),
-//            implementation("androidx.compose.material3:material3-window-size-class:1.1.0"),
-//            implementation("androidx.hilt:hilt-navigation-compose:1.0.0"),
-//            implementation("androidx.navigation:navigation-compose:2.5.3"),
-//            // kotlin conf
-//            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")
-//                }
-//            }
-//        )
+const val CONFIG_VERSION_PROPERTIES_FILE = "config/version.properties"
+const val CONFIG_KEYSTORE_PROPERTIES_FILE = "config/keystore.properties"
 
-//        fun DependencyHandler.implementGlide() = arrayOf(
-//            // glide things
-//            implementation("com.github.bumptech.glide:glide:4.15.1"),
-//            implementation("com.github.bumptech.glide:gifdecoder:4.15.1"),
-//            implementation("com.github.bumptech.glide:annotations:4.15.1"),
-//            implementation("com.github.bumptech.glide:okhttp4-integration:4.15.1"),
-//            kapt("com.github.bumptech.glide:compiler:4.15.1"),
-//        )
+const val SIGNING_CONFIG_NAME = "Any"
 
-//        fun DependencyHandler.implementOkHttp() = arrayOf(
-//            // okhttp things
-//            implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.11"),
-//            implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2"),
-//        )
+const val projectCompileSdk: Int = 34
+const val projectMinSdk = 21
 
-//        fun DependencyHandler.implementRetrofit() = arrayOf(
-//            // retrofit
-//            implementation("com.squareup.retrofit2:retrofit:2.9.0"),
-//            implementation("com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2"),
-//        )
+const val kotlinCompilerExtVersion = "1.5.1"
 
-//        fun DependencyHandler.implementMoshi() = arrayOf(
-//            implementation("com.squareup.moshi:moshi:1.15.0"),
-//            implementation("com.squareup.retrofit2:converter-moshi:2.9.0"),
-//            kapt("com.squareup.moshi:moshi-kotlin-codegen:1.15.0"),
-//        )
+val javaVersion: JavaVersion = JavaVersion.VERSION_17
 
-//        fun DependencyHandler.implementTimber() = arrayOf(
-//            // timber logger
-//            implementation("com.jakewharton.timber:timber:5.0.1"),
-//        )
+const val TASK_PREPARE_RELEASE_NOTES = "prepareReleaseNotes"
 
-//        fun DependencyHandler.implementORMLite() = arrayOf(
-//            implementation("com.j256.ormlite.cipher:ormlite-sqlcipher:1.4@aar"),
-//            implementation("com.j256.ormlite:ormlite-core:5.1"),
-//            implementation("com.j256.ormlite:ormlite-android:5.1"),
-//            implementation("net.zetetic:android-database-sqlcipher:4.0.1@aar"),
-//        )
+const val TASK_ASSEMBLE_RELEASE = "assembleRelease"
+const val TASK_ASSEMBLE_DEBUG = "assembleDebug"
+const val TASK_ASSEMBLE_MINIFIED = "assembleMinified"
+const val TASK_ASSEMBLE_MOCK = "assembleMock"
 
-//        fun DependencyHandler.implementTestUnit() = arrayOf(
-//            testImplementation("junit:junit:4.13.2"),
-//            testImplementation("com.google.dagger:hilt-android-testing:2.46.1"),
-//            testAnnotationProcessor("com.google.dagger:hilt-compiler:2.46.1"),
-//        )
+val ASSEMBLE_TASKS = listOf(
+    TASK_ASSEMBLE_DEBUG,
+    TASK_ASSEMBLE_MOCK,
+    TASK_ASSEMBLE_RELEASE,
+    TASK_ASSEMBLE_MINIFIED
+)
 
-//        fun DependencyHandler.implementTestInstrumentation() = arrayOf(
-//            androidTestImplementation("androidx.test.ext:junit:1.1.5"),
-//            androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1"),
-//            androidTestImplementation(platform("androidx.compose:compose-bom:2023.05.01")),
-//            androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.4.3"),
-//            androidTestImplementation("com.google.dagger:hilt-android-testing:2.46.1"),
-//            androidTestAnnotationProcessor("com.google.dagger:hilt-compiler:2.46.1"),
-//        )
+@Suppress("unused")
+interface MainAppPluginExtension {
+    val versionPropertiesFile: Property<String?>
+    val signingPropertiesFile: Property<String?>
+    val signingConfigName: Property<String?>
+    val createDocumentation: Property<Boolean>
+    val runDetekt: Property<Boolean>
+}
 
-//        fun DependencyHandler.implementDebug() = arrayOf(
-//            debugImplementation("androidx.compose.ui:ui-tooling:1.4.3"),
-//            debugImplementation("androidx.compose.ui:ui-test-manifest:1.4.3"),
-//        )
+// todo
+@Suppress("unused", "MemberVisibilityCanBePrivate")
+abstract class MainAppPlugin : Plugin<Project> {
 
-//        mocking
-//        implementation("io.mockk:mockk:1.9")
+    @Suppress("UNUSED_VARIABLE")
+    override fun apply(project: Project): Unit = with(project) {
 
-        fun Project.loadKeyStoreProperties(
-            signConfigFilePath: String,
-            block: (keyAlias: String, keyPassword: String, storeFile: File, storePassword: String) -> Unit
-        ) {
-            val keystorePropertiesFile = project.rootProject.file(signConfigFilePath)
-            val keystoreProperties = Properties()
-            if (keystorePropertiesFile.exists()) {
-                keystoreProperties.load(FileInputStream(keystorePropertiesFile))
-            } else {
-                keystoreProperties["keyAlias"] = System.getenv("KEYSTORE_KEY_ALIAS").orEmpty()
-                keystoreProperties["keyPassword"] = System.getenv("KEYSTORE_KEY_PASSWORD").orEmpty()
-                keystoreProperties["storePassword"] =
-                    System.getenv("KEYSTORE_STORE_PASSWORD").orEmpty()
-                keystoreProperties["storeFile"] = System.getenv("KEYSTORE_FILE").orEmpty()
-            }
-            block.invoke(
-                keystoreProperties["keyAlias"] as String? ?: "",
-                keystoreProperties["keyPassword"] as? String? ?: "",
-                File(projectDir, keystoreProperties["storeFile"] as? String? ?: ""),
-                keystoreProperties["storePassword"] as? String? ?: ""
-            )
-        }
+        val mainExt = extensions.create("mainAppConfig", MainAppPluginExtension::class.java)
 
-    }
-
-    override fun apply(project: Project) {
+//        configure<DetektExtension> {
+//            autoCorrect = true
+//            toolVersion = "1.20.0"
+//            parallel = false
+//            source = files(
+//                "src/main/kotlin",
+//                "src/main/java"
+//            )
+//            config = files("${project.rootDir}/buildSrc/detekt.yml")
+//        }
 
         // todo non functional as wanted
-        project.allprojects {
-            gradle.useLogger(CustomEventLogger())
-        }
+//        allprojects {
+//            gradle.useLogger(CustomEventLogger())
+//        }
 
         // versions
-        val versionPropertiesFile = project.rootProject.file(CONFIG_VERSION_PROPERTIES_FILE)
+        val versionPropertiesFile = rootProject.file(CONFIG_VERSION_PROPERTIES_FILE)
         val versionProps = Properties()
         versionProps.load(FileInputStream(versionPropertiesFile))
         versionProps.forEach { prop ->
-            project.rootProject.extra.set(prop.key.toString(), prop.value.toString())
+            rootProject.extra.set(prop.key.toString(), prop.value.toString())
         }
 
         //task release notes
-        project.registerTask<Exec>(TASK_PREPARE_RELEASE_NOTES) {
-            setCommandLine(mutableListOf("./scripts/git_log.sh"))
-            setWorkingDir(project.rootDir)
-            setArgs(mutableListOf(project.versionName))
+        registerTask<Exec>(TASK_PREPARE_RELEASE_NOTES) {
+            commandLine = mutableListOf("./scripts/git_log.sh")
+            workingDir = rootDir
+            setArgs(mutableListOf(versionName))
         }
 
-        // tasks after build
-//        project.afterEvaluate {
-//            listOf(
-//                TASK_ASSEMBLE_DEBUG,
-//                TASK_ASSEMBLE_MOCK,
-//                TASK_ASSEMBLE_RELEASE,
-//                TASK_ASSEMBLE_MINIFIED
-//            ).forEach { taskName ->
-//                tasks.findByName(taskName)
-//                    ?.finalizedBy(TASK_PREPARE_RELEASE_NOTES, TASK_DOKKA)
+        // documentation
+        allprojects {
+            afterEvaluate {
+                ASSEMBLE_TASKS.forEach { taskName ->
+                    val releaseNotesTask = tasks.findByName(TASK_PREPARE_RELEASE_NOTES)
+                    val currentTask = tasks.findByName(taskName)
+                    releaseNotesTask?.apply {
+                        outputs.dir(File(projectDir, "../wiki/documentation"))
+                    }
+                    if (containsAndroidPlugin) {
+                    currentTask?.finalizedBy(dokkaGfm, releaseNotesTask)
+                    } else {
+                        currentTask?.finalizedBy(dokkaGfm)
+                    }
+                }
+            }
+        }
+
+//        android?.finalizeDsl { ext->
+//            ext.buildTypes.create("staging").let { buildType ->
+//                buildType.initWith(ext.buildTypes.getByName("debug"))
+//                buildType.manifestPlaceholders["hostName"] = "example.com"
+//                buildType.applicationIdSuffix = ".debugStaging"
+//            }
+//        }
+
+//        android?.applicationVariants.all {
+//            outputs.map {
+//                it as BaseVariantOutputImpl
+//            }.forEach { output ->
+//                val outputFileName = "${applicationId}-${versionName}.apk"
+//                output.outputFileName = outputFileName
 //            }
 //        }
 
 //        // dependencies
-//        project.dependencies.apply {
+//        dependencies.apply {
 //            // base libs kotlin & etc
 //            implementCore()
 //            // lifecycle

+ 14 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/versions/Versions.kt

@@ -0,0 +1,14 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.versions
+
+@Suppress("unused")
+object Versions {
+
+}

+ 3 - 19
gradle.properties

@@ -1,28 +1,12 @@
-# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
 org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-# AndroidX package structure to make it clearer which packages are bundled with the
-# Android operating system, and which are packaged with your app's APK
-# https://developer.android.com/topic/libraries/support-library/androidx-rn
 android.useAndroidX=true
-# Kotlin code style for this project: "official" or "obsolete":
 kotlin.code.style=official
-# Enables namespacing of each library's R class so that its R class includes only the
-# resources declared in the library itself and none from the library's dependencies,
-# thereby reducing the size of the R class for that library
 android.nonTransitiveRClass=true
 org.gradle.unsafe.configuration-cache=false
 android.suppressUnsupportedCompileSdk=34
 android.nonFinalResIds=true
 gradle.testLauncherAPI.enabled=false
+kotlin.mpp.androidSourceSetLayoutVersion=2
+kotlin.mpp.applyDefaultHierarchyTemplate=false
+#android.experimental.lint.version=8.3.0-alpha18
 #org.gradle.warning.mode=all

+ 10 - 0
release-notes.txt

@@ -0,0 +1,10 @@
+* Release Notes 1.2.1
+* scrapper base
+* navigation improvements
+* navigation improvements / need more improvements
+* code improvements
+* code improvements
+* scroll improvements
+* update fix
+* update fix
+* update fix

+ 1 - 2
settings.gradle.kts

@@ -1,5 +1,3 @@
-@file:Suppress("UnstableApiUsage")
-
 /*
 * Copyright (c) Milan Jurkulák 2023.
 * Contact:
@@ -26,6 +24,7 @@ plugins {
     id("com.gradle.enterprise") version ("3.13.3")
 }
 
+@Suppress("UnstableApiUsage")
 dependencyResolutionManagement {
     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
     repositories {

+ 62 - 145
tvlib/build.gradle.kts

@@ -1,8 +1,22 @@
-import org.mjdev.gradle.extensions.implementation
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.javaVersion
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.kotlinCompilerExtVersion
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.projectCompileSdk
-import org.mjdev.gradle.plugin.MainAppPlugin.Companion.projectMinSdk
+import org.mjdev.gradle.dependency.anotherDependencies
+import org.mjdev.gradle.dependency.baseDependencies
+import org.mjdev.gradle.dependency.composeDependencies
+import org.mjdev.gradle.dependency.daggerDependencies
+import org.mjdev.gradle.dependency.encryptDependencies
+import org.mjdev.gradle.dependency.exoPlayerDependencies
+import org.mjdev.gradle.dependency.glideDependencies
+import org.mjdev.gradle.dependency.moshiDependencies
+import org.mjdev.gradle.dependency.oauthDependencies
+import org.mjdev.gradle.dependency.okHttpDependencies
+import org.mjdev.gradle.dependency.permissionsDependencies
+import org.mjdev.gradle.dependency.retrofitDependencies
+import org.mjdev.gradle.dependency.sandwichDependencies
+import org.mjdev.gradle.dependency.testDependencies
+import org.mjdev.gradle.dependency.timberDependencies
+import org.mjdev.gradle.plugin.javaVersion
+import org.mjdev.gradle.plugin.kotlinCompilerExtVersion
+import org.mjdev.gradle.plugin.projectCompileSdk
+import org.mjdev.gradle.plugin.projectMinSdk
 
 /*
  * Copyright (c) Milan Jurkulák 2023.
@@ -13,13 +27,18 @@ import org.mjdev.gradle.plugin.MainAppPlugin.Companion.projectMinSdk
  */
 
 plugins {
-    id("com.android.library")
     kotlin("android")
+    kotlin("kapt")
+    id("com.android.library")
     id("com.google.dagger.hilt.android")
     id("dagger.hilt.android.plugin")
-    kotlin("kapt")
     id("com.google.devtools.ksp")
-//    id("org.jetbrains.dokka") version "1.8.10"
+//    kotlinAndroid()
+//    kotlinKapt()
+//    androidLibrary()
+//    hilt()
+//    ksp()
+//    mainAppPlugin()
 }
 
 android {
@@ -39,7 +58,6 @@ android {
                 getDefaultProguardFile("proguard-android-optimize.txt"),
                 "proguard-rules.pro"
             )
-            buildConfigField("Boolean", "RECOMPOSE_ENABLED", "false")
         }
         release {
             isMinifyEnabled = false // todo
@@ -47,10 +65,13 @@ android {
                 getDefaultProguardFile("proguard-android-optimize.txt"),
                 "proguard-rules.pro"
             )
-            buildConfigField("Boolean", "RECOMPOSE_ENABLED", "false")
         }
     }
 
+    buildFeatures {
+        compose = true
+    }
+
     compileOptions {
         sourceCompatibility = javaVersion
         targetCompatibility = javaVersion
@@ -70,8 +91,14 @@ android {
     }
 
     packaging {
-        resources.excludes.apply {
+        with(resources.excludes) {
             add("/META-INF/{AL2.0,LGPL2.1}")
+            add("META-INF/")
+            add("okhttp3/")
+            add("kotlin/")
+            add("org/")
+            add(".properties")
+            add(".bin")
         }
     }
 
@@ -83,141 +110,31 @@ android {
         enableAggregatingTask = true
     }
 
-//    tasks.dokkaGfm {
-//        outputDirectory.set(File(projectDir, "../wiki/documentation"))
-//    }
-}
+    kapt {
+        correctErrorTypes = true
+    }
 
-dependencies {
-    // startups
-//    implementation("androidx.startup:startup-runtime:1.1.1")
-    // base libs
-    implementation("androidx.core:core-ktx:1.12.0")
-    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
-    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
-    // reflect / todo : remove
-    implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.21")
-    // window manager
-    implementation("androidx.window:window:1.2.0")
-    // compose base libs
-    implementation(platform("androidx.compose:compose-bom:2023.10.01"))
-    implementation("androidx.compose.ui:ui-tooling")
-    implementation("androidx.activity:activity-compose:1.8.2")
-    // more icons
-    implementation("androidx.compose.material:material-icons-extended:1.5.4")
-    // tv compose
-    implementation("androidx.tv:tv-foundation:1.0.0-alpha10")
-    implementation("androidx.tv:tv-material:1.0.0-alpha10")
-    // view model
-    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
-    // navigation
-    implementation("androidx.navigation:navigation-compose:2.7.6")
-    // okhttp
-    implementation(platform("com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.12"))
-    implementation("com.squareup.okhttp3:okhttp")
-    implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.12")
-    // 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")
-    // moshi json
-    implementation("com.squareup.moshi:moshi:1.15.0")
-    implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
-    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
-    ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.0")
-    // sandwich
-    implementation("com.github.skydoves:sandwich:2.0.5")
-    implementation("com.github.skydoves:sandwich-retrofit:2.0.5")
-    // image loading
-    implementation("com.github.bumptech.glide:okhttp3-integration:4.16.0")
-    implementation("com.github.bumptech.glide:compose:1.0.0-beta01")
-    implementation("com.github.skydoves:landscapist-glide:2.2.13")
-    implementation("com.github.skydoves:landscapist-transformation:2.2.13")
-    implementation("com.github.skydoves:landscapist-palette:2.2.13")
-    implementation("com.github.skydoves:landscapist-placeholder:2.2.13")
-    ksp("com.github.bumptech.glide:ksp:4.16.0")
-    // zxing
-    implementation("com.google.zxing:core:3.5.2")
-    // svg
-    implementation("com.caverock:androidsvg-aar:1.4")
-    // oauth
-    implementation("com.auth0.android:auth0:2.10.2")
-    implementation("com.auth0.android:jwtdecode:2.0.2")
-    // debug
-    implementation("com.jakewharton.timber:timber:5.0.1")
-    // dagger core
-    implementation("com.google.dagger:dagger:2.50")
-    implementation("androidx.compose.material3:material3:1.1.2")
-    kapt("com.google.dagger:dagger-compiler:2.50")
-    // dagger android
-    implementation("com.google.dagger:dagger-android:2.50")
-    implementation("com.google.dagger:dagger-android-support:2.50")
-    kapt("com.google.dagger:dagger-android-processor:2.50")
-    // dagger - hilt
-    implementation("com.google.dagger:hilt-android:2.50")
-    implementation("androidx.hilt:hilt-navigation-compose:1.1.0")
-    kapt("com.google.dagger:hilt-compiler:2.50")
-    // encrypt data
-    implementation("com.scottyab:aescrypt:0.0.1")
-    // exoplayer
-    implementation("androidx.media3:media3-exoplayer:1.2.0")
-    implementation("androidx.media3:media3-exoplayer-dash:1.2.0")
-    implementation("androidx.media3:media3-exoplayer-hls:1.2.0")
-    implementation("androidx.media3:media3-exoplayer-rtsp:1.2.0")
-//    implementation("androidx.media3:media3-exoplayer-ima:1.1.0")
-    implementation("androidx.media3:media3-datasource-cronet:1.2.0")
-    implementation("androidx.media3:media3-datasource-okhttp:1.2.0")
-    implementation("androidx.media3:media3-datasource-rtmp:1.2.0")
-    implementation("androidx.media3:media3-ui:1.2.0")
-//    implementation("androidx.media3:media3-ui-leanback:1.1.0")
-    implementation("androidx.media3:media3-session:1.2.0")
-    implementation("androidx.media3:media3-extractor:1.2.0")
-    implementation("androidx.media3:media3-cast:1.2.0")
-    implementation("androidx.media3:media3-exoplayer-workmanager:1.2.0")
-    implementation("androidx.media3:media3-transformer:1.2.0")
-    implementation("androidx.media3:media3-database:1.2.0")
-    implementation("androidx.media3:media3-decoder:1.2.0")
-    implementation("androidx.media3:media3-datasource:1.2.0")
-    implementation("androidx.media3:media3-common:1.2.0")
-    // permission
-    implementation("com.google.accompanist:accompanist-permissions:0.33.2-alpha")
-    // for previews
-    debugImplementation("androidx.customview:customview-poolingcontainer:1.0.0")
-    // pallette
-    implementation("androidx.palette:palette-ktx:1.0.0")
-    // lottie
-    implementation("com.airbnb.android:lottie-compose:6.2.0")
-    // exif info
-    implementation("androidx.exifinterface:exifinterface:1.3.7")
-    // anr
-    implementation("com.github.anrwatchdog:anrwatchdog:1.4.0")
-    // jsoup
-    implementation("org.jsoup:jsoup:1.17.1")
-    // dm
-    implementation("com.dailymotion.dailymotion-sdk-android:sdk:0.2.12")
-    // dynamic theme
-    implementation("com.google.android.material:material:1.11.0")
-    // stripe payments
-//    implementation("com.stripe:stripe-android:20.33.0")
-//    implementation("com.stripe:stripecardscan:20.33.0")
-//    implementation("com.stripe:financial-connections:20.33.0")
-    // scrape
-//    implementation("org.jsoup:jsoup:1.16.1")
-//    implementation("net.sourceforge.htmlunit:htmlunit-android:2.67.0")
-    implementation("net.sourceforge.htmlunit:htmlunit-android:2.67.0")
-    // yt
-    // ...
-    // 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")
+    tasks {
+        dokkaGfm {
+            outputDirectory.set(File(projectDir, "../wiki/documentation/"))
         }
     }
-    // testing
-    testImplementation("junit:junit:4.13.2")
-    androidTestImplementation("androidx.test.ext:junit:1.1.5")
-    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+}
+
+dependencies {
+    baseDependencies()
+    composeDependencies()
+    okHttpDependencies()
+    retrofitDependencies()
+    moshiDependencies()
+    sandwichDependencies()
+    glideDependencies()
+    oauthDependencies()
+    timberDependencies()
+    daggerDependencies()
+    exoPlayerDependencies()
+    testDependencies()
+    encryptDependencies()
+    permissionsDependencies()
+    anotherDependencies()
 }

+ 1 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/auth/AuthManager.kt

@@ -153,7 +153,7 @@ class AuthManager(
             allowedPackages: List<String> = listOf(),
             onUserChange: AuthManager.(user: User?) -> Unit = {}
         ) = LocalContext.current.let { ctx ->
-            remember(ctx) {
+            remember {
                 AuthManager(
                     context = ctx,
                     scheme = scheme ?: ctx.getString(R.string.com_auth0_scheme),

+ 76 - 68
tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ModifierExt.kt

@@ -10,6 +10,7 @@
 
 package org.mjdev.tvlib.extensions
 
+import android.annotation.SuppressLint
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.gestures.detectDragGestures
 import androidx.compose.foundation.gestures.detectTapGestures
@@ -17,28 +18,40 @@ import androidx.compose.foundation.layout.aspectRatio
 import androidx.compose.foundation.relocation.BringIntoViewResponder
 import androidx.compose.foundation.relocation.bringIntoViewResponder
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.MutableIntState
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableLongStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
+import androidx.compose.ui.draw.drawWithCache
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.FocusState
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.drawscope.Fill
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.lerp
 import androidx.compose.ui.input.pointer.PointerInputScope
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.platform.debugInspectorInfo
+import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.delay
 import org.mjdev.tvlib.BuildConfig
 import org.mjdev.tvlib.extensions.ComposeExt.isLandscapeMode
 import org.mjdev.tvlib.extensions.ComposeExt.isPortraitMode
 import timber.log.Timber
 import kotlin.math.abs
+import kotlin.math.min
 
 @Suppress("MemberVisibilityCanBePrivate")
 object ModifierExt {
@@ -129,76 +142,71 @@ object ModifierExt {
         )
     }
 
-    val isRecomposeHighlighterEnabled: Boolean
-        @Composable
-        get() = BuildConfig.RECOMPOSE_ENABLED
+    @Composable
+    fun Modifier.recomposeHighlighter(
+        isComposeDebug: Boolean = BuildConfig.DEBUG
+    ): Modifier = conditional(
+        isComposeDebug
+    ) {
+        this.then(recomposeModifier)
+    }
 
-//    @Composable
-//    @Stable
-//    fun Modifier.recomposeHighlighter(
-//        isComposeDebug: Boolean = isRecomposeHighlighterEnabled
-//    ): Modifier = conditional(
-//        isComposeDebug
-//    ) {
-//        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()
+                        }
+                    }
 
-//    @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()
-//                        }
-//                    }
-//
-//                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
+                )
+            }
+        }
+    }
 
     // todo anr
     @OptIn(ExperimentalFoundationApi::class)

+ 46 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/shape/DiamondShape.kt

@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.ui.shape
+
+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
+
+@Suppress("unused")
+class DiamondShape : Shape {
+
+    override fun createOutline(
+        size: Size,
+        layoutDirection: LayoutDirection,
+        density: Density
+    ): Outline {
+        return Outline.Generic(
+            path = drawDiamondPath(size)
+        )
+    }
+
+    private fun drawDiamondPath(size: Size): Path {
+        return Path().apply {
+            val centerX = size.width / 2f
+            val diamondCurve = 60f
+            val width = size.width
+            val height = size.height
+
+            moveTo(x = 0f + diamondCurve, y = 0f)
+            lineTo(x = width - diamondCurve, y = 0f)
+            lineTo(x = width, y = diamondCurve)
+            lineTo(x = centerX, y = height)
+            // ...
+        }
+    }
+
+}

+ 10 - 0
wiki/Release-Notes-1.2.1.md

@@ -0,0 +1,10 @@
+* Release Notes 1.2.1
+* scrapper base
+* navigation improvements
+* navigation improvements / need more improvements
+* code improvements
+* code improvements
+* scroll improvements
+* update fix
+* update fix
+* update fix

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/-companion/-i-p-t-v_-d-a-t-a.md

@@ -0,0 +1,6 @@
+//[app](../../../../index.md)/[org.mjdev.tvapp.activity](../../index.md)/[IPTVActivity](../index.md)/[Companion](index.md)/[IPTV_DATA](-i-p-t-v_-d-a-t-a.md)
+
+# IPTV_DATA
+
+[androidJvm]\
+const val [IPTV_DATA](-i-p-t-v_-d-a-t-a.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)

+ 12 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/-companion/index.md

@@ -0,0 +1,12 @@
+//[app](../../../../index.md)/[org.mjdev.tvapp.activity](../../index.md)/[IPTVActivity](../index.md)/[Companion](index.md)
+
+# Companion
+
+[androidJvm]\
+object [Companion](index.md)
+
+## Properties
+
+| Name | Summary |
+|---|---|
+| [IPTV_DATA](-i-p-t-v_-d-a-t-a.md) | [androidJvm]<br>const val [IPTV_DATA](-i-p-t-v_-d-a-t-a.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) |

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/-compose.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[IPTVActivity](index.md)/[Compose](-compose.md)
+
+# Compose
+
+[androidJvm]\
+
+@[Composable](https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable.html)
+
+open override fun [Compose](-compose.md)()

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/-i-p-t-v-activity.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[IPTVActivity](index.md)/[IPTVActivity](-i-p-t-v-activity.md)
+
+# IPTVActivity
+
+[androidJvm]\
+constructor()

Разлика између датотеке није приказан због своје велике величине
+ 33 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/index.md


+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/nav-graph-builder.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[IPTVActivity](index.md)/[navGraphBuilder](nav-graph-builder.md)
+
+# navGraphBuilder
+
+[androidJvm]\
+open override val [navGraphBuilder](nav-graph-builder.md): NavGraphBuilderEx.() -&gt; [Unit](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-i-p-t-v-activity/on-intent.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[IPTVActivity](index.md)/[onIntent](on-intent.md)
+
+# onIntent
+
+[androidJvm]\
+open override fun [onIntent](on-intent.md)(navController: NavHostControllerEx, intent: [Intent](https://developer.android.com/reference/kotlin/android/content/Intent.html)?)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-main-activity/-compose.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[MainActivity](index.md)/[Compose](-compose.md)
+
+# Compose
+
+[androidJvm]\
+
+@[Composable](https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable.html)
+
+open override fun [Compose](-compose.md)()

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-main-activity/-main-activity.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[MainActivity](index.md)/[MainActivity](-main-activity.md)
+
+# MainActivity
+
+[androidJvm]\
+constructor()

Разлика између датотеке није приказан због своје велике величине
+ 27 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-main-activity/index.md


+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-main-activity/nav-graph-builder.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[MainActivity](index.md)/[navGraphBuilder](nav-graph-builder.md)
+
+# navGraphBuilder
+
+[androidJvm]\
+open override val [navGraphBuilder](nav-graph-builder.md): NavGraphBuilderEx.() -&gt; [Unit](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/-compose.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[WebActivity](index.md)/[Compose](-compose.md)
+
+# Compose
+
+[androidJvm]\
+
+@[Composable](https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable.html)
+
+open override fun [Compose](-compose.md)()

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/-web-activity.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[WebActivity](index.md)/[WebActivity](-web-activity.md)
+
+# WebActivity
+
+[androidJvm]\
+constructor()

Разлика између датотеке није приказан због своје велике величине
+ 27 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/index.md


+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/nav-graph-builder.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[WebActivity](index.md)/[navGraphBuilder](nav-graph-builder.md)
+
+# navGraphBuilder
+
+[androidJvm]\
+open override val [navGraphBuilder](nav-graph-builder.md): NavGraphBuilderEx.() -&gt; [Unit](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/-web-activity/on-intent.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.activity](../index.md)/[WebActivity](index.md)/[onIntent](on-intent.md)
+
+# onIntent
+
+[androidJvm]\
+open override fun [onIntent](on-intent.md)(navController: NavHostControllerEx, intent: [Intent](https://developer.android.com/reference/kotlin/android/content/Intent.html)?)

+ 11 - 0
wiki/documentation/app/org.mjdev.tvapp.activity/index.md

@@ -0,0 +1,11 @@
+//[app](../../index.md)/[org.mjdev.tvapp.activity](index.md)
+
+# Package-level declarations
+
+## Types
+
+| Name | Summary |
+|---|---|
+| [IPTVActivity](-i-p-t-v-activity/index.md) | [androidJvm]<br>class [IPTVActivity](-i-p-t-v-activity/index.md) : TvActivity |
+| [MainActivity](-main-activity/index.md) | [androidJvm]<br>class [MainActivity](-main-activity/index.md) : TvActivity |
+| [WebActivity](-web-activity/index.md) | [androidJvm]<br>class [WebActivity](-web-activity/index.md) : ComposableActivity |

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.app/-application/-application.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.app](../index.md)/[Application](index.md)/[Application](-application.md)
+
+# Application
+
+[androidJvm]\
+constructor()

Разлика између датотеке није приказан због своје велике величине
+ 18 - 0
wiki/documentation/app/org.mjdev.tvapp.app/-application/index.md


+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.app/-application/on-create.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.app](../index.md)/[Application](index.md)/[onCreate](on-create.md)
+
+# onCreate
+
+[androidJvm]\
+open override fun [onCreate](on-create.md)()

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.app/index.md

@@ -0,0 +1,9 @@
+//[app](../../index.md)/[org.mjdev.tvapp.app](index.md)
+
+# Package-level declarations
+
+## Types
+
+| Name | Summary |
+|---|---|
+| [Application](-application/index.md) | [androidJvm]<br>class [Application](-application/index.md) : TvApplication |

+ 8 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/-category.md

@@ -0,0 +1,8 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)/[Category](-category.md)
+
+# Category
+
+[androidJvm]\
+constructor(title: [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html))
+
+constructor()

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/equals.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)/[equals](equals.md)
+
+# equals
+
+[androidJvm]\
+open operator override fun [equals](equals.md)(other: [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)?): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/hash-code.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)/[hashCode](hash-code.md)
+
+# hashCode
+
+[androidJvm]\
+open override fun [hashCode](hash-code.md)(): [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/id.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)/[id](id.md)
+
+# id
+
+[androidJvm]\
+
+@Json(name = &quot;id&quot;)
+
+open override var [id](id.md): [Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/image.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)/[image](image.md)
+
+# image
+
+[androidJvm]\
+
+@Json(name = &quot;image&quot;)
+
+open override val [image](image.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? = null

+ 31 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/index.md

@@ -0,0 +1,31 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)
+
+# Category
+
+[androidJvm]\
+@JsonClass(generateAdapter = true)
+
+class [Category](index.md) : [Serializable](https://developer.android.com/reference/kotlin/java/io/Serializable.html), ItemWithId, ItemWithTitle&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithSubtitle&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithImage&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt;
+
+## Constructors
+
+| | |
+|---|---|
+| [Category](-category.md) | [androidJvm]<br>constructor(title: [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html))constructor() |
+
+## Functions
+
+| Name | Summary |
+|---|---|
+| [equals](equals.md) | [androidJvm]<br>open operator override fun [equals](equals.md)(other: [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)?): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |
+| [hashCode](hash-code.md) | [androidJvm]<br>open override fun [hashCode](hash-code.md)(): [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) |
+| [toString](to-string.md) | [androidJvm]<br>open override fun [toString](to-string.md)(): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) |
+
+## Properties
+
+| Name | Summary |
+|---|---|
+| [id](id.md) | [androidJvm]<br>@Json(name = &quot;id&quot;)<br>open override var [id](id.md): [Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) |
+| [image](image.md) | [androidJvm]<br>@Json(name = &quot;image&quot;)<br>open override val [image](image.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? = null |
+| [subtitle](subtitle.md) | [androidJvm]<br>@Json(name = &quot;subtitle&quot;)<br>open override val [subtitle](subtitle.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? = null |
+| [title](title.md) | [androidJvm]<br>@Json(name = &quot;title&quot;)<br>open override var [title](title.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/subtitle.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)/[subtitle](subtitle.md)
+
+# subtitle
+
+[androidJvm]\
+
+@Json(name = &quot;subtitle&quot;)
+
+open override val [subtitle](subtitle.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? = null

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/title.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)/[title](title.md)
+
+# title
+
+[androidJvm]\
+
+@Json(name = &quot;title&quot;)
+
+open override var [title](title.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-category/to-string.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Category](index.md)/[toString](to-string.md)
+
+# toString
+
+[androidJvm]\
+open override fun [toString](to-string.md)(): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/-country.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)/[Country](-country.md)
+
+# Country
+
+[androidJvm]\
+constructor()

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/code.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)/[code](code.md)
+
+# code
+
+[androidJvm]\
+
+@Json(name = &quot;code&quot;)
+
+var [code](code.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/equals.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)/[equals](equals.md)
+
+# equals
+
+[androidJvm]\
+open operator override fun [equals](equals.md)(other: [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)?): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/flag.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)/[flag](flag.md)
+
+# flag
+
+[androidJvm]\
+
+@Json(name = &quot;flag&quot;)
+
+var [flag](flag.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/hash-code.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)/[hashCode](hash-code.md)
+
+# hashCode
+
+[androidJvm]\
+open override fun [hashCode](hash-code.md)(): [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/id.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)/[id](id.md)
+
+# id
+
+[androidJvm]\
+
+@Json(name = &quot;id&quot;)
+
+var [id](id.md): [Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)

+ 31 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/index.md

@@ -0,0 +1,31 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)
+
+# Country
+
+[androidJvm]\
+@JsonClass(generateAdapter = true)
+
+class [Country](index.md)
+
+## Constructors
+
+| | |
+|---|---|
+| [Country](-country.md) | [androidJvm]<br>constructor() |
+
+## Functions
+
+| Name | Summary |
+|---|---|
+| [equals](equals.md) | [androidJvm]<br>open operator override fun [equals](equals.md)(other: [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)?): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |
+| [hashCode](hash-code.md) | [androidJvm]<br>open override fun [hashCode](hash-code.md)(): [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) |
+
+## Properties
+
+| Name | Summary |
+|---|---|
+| [code](code.md) | [androidJvm]<br>@Json(name = &quot;code&quot;)<br>var [code](code.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [flag](flag.md) | [androidJvm]<br>@Json(name = &quot;flag&quot;)<br>var [flag](flag.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [id](id.md) | [androidJvm]<br>@Json(name = &quot;id&quot;)<br>var [id](id.md): [Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) |
+| [languages](languages.md) | [androidJvm]<br>@Json(name = &quot;languages&quot;)<br>var [languages](languages.md): [List](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt;? |
+| [name](name.md) | [androidJvm]<br>@Json(name = &quot;name&quot;)<br>var [name](name.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/languages.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)/[languages](languages.md)
+
+# languages
+
+[androidJvm]\
+
+@Json(name = &quot;languages&quot;)
+
+var [languages](languages.md): [List](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt;?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-country/name.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Country](index.md)/[name](name.md)
+
+# name
+
+[androidJvm]\
+
+@Json(name = &quot;name&quot;)
+
+var [name](name.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/-message.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)/[Message](-message.md)
+
+# Message
+
+[androidJvm]\
+constructor()

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/deleted.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)/[deleted](deleted.md)
+
+# deleted
+
+[androidJvm]\
+
+@Json(name = &quot;deleted&quot;)
+
+val [deleted](deleted.md): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) = false

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/equals.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)/[equals](equals.md)
+
+# equals
+
+[androidJvm]\
+open operator override fun [equals](equals.md)(other: [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)?): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/hash-code.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)/[hashCode](hash-code.md)
+
+# hashCode
+
+[androidJvm]\
+open override fun [hashCode](hash-code.md)(): [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/id.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)/[id](id.md)
+
+# id
+
+[androidJvm]\
+
+@Json(name = &quot;id&quot;)
+
+open override var [id](id.md): [Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)

+ 31 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/index.md

@@ -0,0 +1,31 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)
+
+# Message
+
+[androidJvm]\
+@JsonClass(generateAdapter = true)
+
+class [Message](index.md) : ItemWithTitle&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithMessage&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithId
+
+## Constructors
+
+| | |
+|---|---|
+| [Message](-message.md) | [androidJvm]<br>constructor() |
+
+## Functions
+
+| Name | Summary |
+|---|---|
+| [equals](equals.md) | [androidJvm]<br>open operator override fun [equals](equals.md)(other: [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)?): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |
+| [hashCode](hash-code.md) | [androidJvm]<br>open override fun [hashCode](hash-code.md)(): [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) |
+
+## Properties
+
+| Name | Summary |
+|---|---|
+| [deleted](deleted.md) | [androidJvm]<br>@Json(name = &quot;deleted&quot;)<br>val [deleted](deleted.md): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) = false |
+| [id](id.md) | [androidJvm]<br>@Json(name = &quot;id&quot;)<br>open override var [id](id.md): [Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) |
+| [message](message.md) | [androidJvm]<br>@Json(name = &quot;message&quot;)<br>open override var [message](message.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [read](read.md) | [androidJvm]<br>@Json(name = &quot;read&quot;)<br>val [read](read.md): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) = false |
+| [title](title.md) | [androidJvm]<br>@Json(name = &quot;title&quot;)<br>open override var [title](title.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/message.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)/[message](message.md)
+
+# message
+
+[androidJvm]\
+
+@Json(name = &quot;message&quot;)
+
+open override var [message](message.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/read.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)/[read](read.md)
+
+# read
+
+[androidJvm]\
+
+@Json(name = &quot;read&quot;)
+
+val [read](read.md): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) = false

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-message/title.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Message](index.md)/[title](title.md)
+
+# title
+
+[androidJvm]\
+
+@Json(name = &quot;title&quot;)
+
+open override var [title](title.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/-movie.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[Movie](-movie.md)
+
+# Movie
+
+[androidJvm]\
+constructor()

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/background.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[background](background.md)
+
+# background
+
+[androidJvm]\
+
+@Json(name = &quot;backgroundImageUrl&quot;)
+
+open override var [background](background.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/category.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[category](category.md)
+
+# category
+
+[androidJvm]\
+
+@Json(name = &quot;category&quot;)
+
+var [category](category.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/country.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[country](country.md)
+
+# country
+
+[androidJvm]\
+
+@Json(name = &quot;country&quot;)
+
+var [country](country.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/description.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[description](description.md)
+
+# description
+
+[androidJvm]\
+
+@Json(name = &quot;description&quot;)
+
+open override var [description](description.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/equals.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[equals](equals.md)
+
+# equals
+
+[androidJvm]\
+open operator override fun [equals](equals.md)(other: [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)?): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/hash-code.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[hashCode](hash-code.md)
+
+# hashCode
+
+[androidJvm]\
+open override fun [hashCode](hash-code.md)(): [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/id.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[id](id.md)
+
+# id
+
+[androidJvm]\
+
+@Json(name = &quot;id&quot;)
+
+open override var [id](id.md): [Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/image.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[image](image.md)
+
+# image
+
+[androidJvm]\
+
+@Json(name = &quot;imageUrl&quot;)
+
+open override var [image](image.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 37 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/index.md

@@ -0,0 +1,37 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)
+
+# Movie
+
+[androidJvm]\
+@JsonClass(generateAdapter = true)
+
+class [Movie](index.md) : [Serializable](https://developer.android.com/reference/kotlin/java/io/Serializable.html), ItemWithId, ItemWithTitle&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithSubtitle&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithImage&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithUri&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithBackground&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt; , ItemWithDescription&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt;
+
+## Constructors
+
+| | |
+|---|---|
+| [Movie](-movie.md) | [androidJvm]<br>constructor() |
+
+## Functions
+
+| Name | Summary |
+|---|---|
+| [equals](equals.md) | [androidJvm]<br>open operator override fun [equals](equals.md)(other: [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html)?): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |
+| [hashCode](hash-code.md) | [androidJvm]<br>open override fun [hashCode](hash-code.md)(): [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html) |
+
+## Properties
+
+| Name | Summary |
+|---|---|
+| [background](background.md) | [androidJvm]<br>@Json(name = &quot;backgroundImageUrl&quot;)<br>open override var [background](background.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [category](category.md) | [androidJvm]<br>@Json(name = &quot;category&quot;)<br>var [category](category.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [country](country.md) | [androidJvm]<br>@Json(name = &quot;country&quot;)<br>var [country](country.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [description](description.md) | [androidJvm]<br>@Json(name = &quot;description&quot;)<br>open override var [description](description.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [id](id.md) | [androidJvm]<br>@Json(name = &quot;id&quot;)<br>open override var [id](id.md): [Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) |
+| [image](image.md) | [androidJvm]<br>@Json(name = &quot;imageUrl&quot;)<br>open override var [image](image.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [isNsfw](is-nsfw.md) | [androidJvm]<br>@Json(name = &quot;isNsfw&quot;)<br>var [isNsfw](is-nsfw.md): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |
+| [studio](studio.md) | [androidJvm]<br>@Json(name = &quot;studio&quot;)<br>var [studio](studio.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [subtitle](subtitle.md) | [androidJvm]<br>open override var [subtitle](subtitle.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [title](title.md) | [androidJvm]<br>@Json(name = &quot;title&quot;)<br>open override var [title](title.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |
+| [uri](uri.md) | [androidJvm]<br>@Json(name = &quot;videoUri&quot;)<br>open override var [uri](uri.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)? |

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/is-nsfw.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[isNsfw](is-nsfw.md)
+
+# isNsfw
+
+[androidJvm]\
+
+@Json(name = &quot;isNsfw&quot;)
+
+var [isNsfw](is-nsfw.md): [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/studio.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[studio](studio.md)
+
+# studio
+
+[androidJvm]\
+
+@Json(name = &quot;studio&quot;)
+
+var [studio](studio.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/subtitle.md

@@ -0,0 +1,6 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[subtitle](subtitle.md)
+
+# subtitle
+
+[androidJvm]\
+open override var [subtitle](subtitle.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/title.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[title](title.md)
+
+# title
+
+[androidJvm]\
+
+@Json(name = &quot;title&quot;)
+
+open override var [title](title.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-movie/uri.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[Movie](index.md)/[uri](uri.md)
+
+# uri
+
+[androidJvm]\
+
+@Json(name = &quot;videoUri&quot;)
+
+open override var [uri](uri.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 6 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/-companion/as-movie.md

@@ -0,0 +1,6 @@
+//[app](../../../../index.md)/[org.mjdev.tvapp.data.local](../../index.md)/[TVChannel](../index.md)/[Companion](index.md)/[asMovie](as-movie.md)
+
+# asMovie
+
+[androidJvm]\
+fun [TVChannel](../index.md).[asMovie](as-movie.md)(category: [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)): [Movie](../../-movie/index.md)

+ 12 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/-companion/index.md

@@ -0,0 +1,12 @@
+//[app](../../../../index.md)/[org.mjdev.tvapp.data.local](../../index.md)/[TVChannel](../index.md)/[Companion](index.md)
+
+# Companion
+
+[androidJvm]\
+object [Companion](index.md)
+
+## Functions
+
+| Name | Summary |
+|---|---|
+| [asMovie](as-movie.md) | [androidJvm]<br>fun [TVChannel](../index.md).[asMovie](as-movie.md)(category: [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)): [Movie](../../-movie/index.md) |

+ 8 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/-t-v-channel.md

@@ -0,0 +1,8 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[TVChannel](index.md)/[TVChannel](-t-v-channel.md)
+
+# TVChannel
+
+[androidJvm]\
+constructor(stream: [Stream](../../org.mjdev.tvapp.data.remote/-stream/index.md), channel: [Channel](../../org.mjdev.tvapp.data.remote/-channel/index.md)?)
+
+constructor()

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/alt-names.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[TVChannel](index.md)/[altNames](alt-names.md)
+
+# altNames
+
+[androidJvm]\
+
+@Json(name = &quot;alt_names&quot;)
+
+var [altNames](alt-names.md): [List](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt;?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/broadcast-area.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[TVChannel](index.md)/[broadcastArea](broadcast-area.md)
+
+# broadcastArea
+
+[androidJvm]\
+
+@Json(name = &quot;broadcast_area&quot;)
+
+var [broadcastArea](broadcast-area.md): [List](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt;?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/categories.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[TVChannel](index.md)/[categories](categories.md)
+
+# categories
+
+[androidJvm]\
+
+@Json(name = &quot;categories&quot;)
+
+var [categories](categories.md): [List](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)&lt;[String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)&gt;?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/channel-id.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[TVChannel](index.md)/[channelId](channel-id.md)
+
+# channelId
+
+[androidJvm]\
+
+@Json(name = &quot;id&quot;)
+
+var [channelId](channel-id.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/city.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[TVChannel](index.md)/[city](city.md)
+
+# city
+
+[androidJvm]\
+
+@Json(name = &quot;city&quot;)
+
+var [city](city.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/closed.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[TVChannel](index.md)/[closed](closed.md)
+
+# closed
+
+[androidJvm]\
+
+@Json(name = &quot;closed&quot;)
+
+var [closed](closed.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

+ 9 - 0
wiki/documentation/app/org.mjdev.tvapp.data.local/-t-v-channel/country.md

@@ -0,0 +1,9 @@
+//[app](../../../index.md)/[org.mjdev.tvapp.data.local](../index.md)/[TVChannel](index.md)/[country](country.md)
+
+# country
+
+[androidJvm]\
+
+@Json(name = &quot;country&quot;)
+
+var [country](country.md): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)?

Неке датотеке нису приказане због велике количине промена