Explorar o código

code improvements

milan jurkulák %!s(int64=2) %!d(string=hai) anos
pai
achega
8628eff21f
Modificáronse 60 ficheiros con 773 adicións e 741 borrados
  1. 2 1
      .gitignore
  2. 2 120
      app/build.gradle.kts
  3. 34 0
      buildSrc/build.gradle.kts
  4. 1 77
      buildSrc/src/main/kotlin/org/mjdev/gradle/base/BasePlugin.kt
  5. 0 9
      buildSrc/src/main/kotlin/org/mjdev/gradle/base/BaseTask.kt
  6. 6 6
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/CustomEventLogger.kt
  7. 3 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/ExtFileFilter.kt
  8. 14 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/SigningsScope.kt
  9. 12 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/SysUtils.kt
  10. 10 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIcon.kt
  11. 0 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIconConfig.kt
  12. 0 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIconExtension.kt
  13. 0 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIconPlugin.kt
  14. 3 3
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIconTask.kt
  15. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/filter/ColorRibbonFilter.kt
  16. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/filter/GrayscaleFilter.kt
  17. 16 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/filter/LauncherIconFilter.kt
  18. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/filter/OverlayFilter.kt
  19. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/utils/Resources.kt
  20. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/ClassHelper.kt
  21. 2 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/ClassHelperImpl.kt
  22. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/Constants.kt
  23. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/FilePathHelper.kt
  24. 2 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/FilePathHelperImpl.kt
  25. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/Worker.kt
  26. 7 7
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/WorkerImpl.kt
  27. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/ClassMaker.kt
  28. 6 6
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/ClassMakerImpl.kt
  29. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinClassMaker.kt
  30. 4 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinClassMakerImpl.kt
  31. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinFileMaker.kt
  32. 3 3
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinFileMakerImpl.kt
  33. 2 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinFuctionMakerImpl.kt
  34. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinFunctionMaker.kt
  35. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinPropertyMaker.kt
  36. 1 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinPropertyMakerImpl.kt
  37. 16 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/writers/TestFileWriter.kt
  38. 7 7
      buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/writers/TestFileWriterImpl.kt
  39. 1 5
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/ApplicationExtensionExt.kt
  40. 70 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/DependencyHandlerScopeExt.kt
  41. 0 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/FileExt.kt
  42. 1 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/HashMapExt.kt
  43. 91 37
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/ProjectExt.kt
  44. 17 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/ProviderExt.kt
  45. 0 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/StringExt.kt
  46. 108 92
      buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/TaskExt.kt
  47. 0 8
      buildSrc/src/main/kotlin/org/mjdev/gradle/icons/filter/LauncherIconFilter.kt
  48. 160 34
      buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/AppPlugin.kt
  49. 133 125
      buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/LibPlugin.kt
  50. 6 0
      buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/config/AppConfig.kt
  51. 0 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/tasks/ReleaseNotesCleanTask.kt
  52. 1 3
      buildSrc/src/main/kotlin/org/mjdev/gradle/tasks/ReleaseNotesCreateTask.kt
  53. 2 2
      buildSrc/src/main/kotlin/org/mjdev/gradle/tasks/TestCaseGeneratorTask.kt
  54. 0 1
      buildSrc/src/main/kotlin/org/mjdev/gradle/tasks/ZipReleaseCreateTask.kt
  55. 0 8
      buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/writers/TestFileWriter.kt
  56. 1 1
      config/version.prop
  57. 2 2
      documentation/home.md
  58. 4 0
      gradle/libs.versions.toml
  59. 0 154
      tvlib/build.gradle.kts
  60. 10 0
      web/index.html

+ 2 - 1
.gitignore

@@ -48,4 +48,5 @@ render.experimental.xml
 google-services.json
 
 # Android Profiling
-*.hprof
+*.hprof!/release.zip
+!/documentation/release-notes-1.0.0.md

+ 2 - 120
app/build.gradle.kts

@@ -10,127 +10,9 @@ plugins {
     id("AppPlugin")
 }
 
-// todo
 appConfig {
     autoCorrectCode = false
     createDocumentation = true
-//    createReleaseNotes = true
-//    renameApkOutputByAppID = false
-//    createReleaseZip = true
-//    createInfoClass = false
-//    buildTypeInLauncherIcon = false
-}
-
-dependencies {
-    implementation(project(mapOf("path" to ":tvlib")))
-
-    // compose
-    implementation(platform(libs.androidx.compose.bom))
-    implementation(libs.androidx.compose.ui.tooling)
-    implementation(libs.androidx.compose.activity)
-    // more icons
-    implementation(libs.androidx.material.icons.extended)
-    // tv compose
-    implementation(libs.androidx.tv.foundation)
-    implementation(libs.androidx.tv.material)
-    // view model
-    implementation(libs.androidx.compose.lifecycle.viewmodel)
-    // navigation
-    implementation(libs.androidx.compose.navigation)
-    // todo remove, dynamic background & colors
-    implementation(libs.androidx.material3)
-    // previews
-    debugImplementation(libs.androidx.customview.poolingcontainer)
-    // foundation
-    implementation(libs.androidx.foundation)
-    // dagger
-    implementation(libs.dagger)
-    // dagger android
-    implementation(libs.dagger.android)
-    implementation(libs.dagger.android.support)
-    // dagger hilt
-    implementation(libs.dagger.hilt.android)
-    implementation(libs.androidx.compose.hilt.navigation)
-    // dagger annotations
-    kapt(libs.dagger.compiler)
-    kapt(libs.dagger.android.processor)
-    kapt(libs.dagger.hilt.compiler)
-    implementation(libs.moshi)
-    implementation(libs.moshi.retrofit.converter)
-    ksp(libs.moshi.kotlin.codegen)
-    // okhttp
-    implementation(platform(libs.okhttp3.bom))
-    implementation(libs.okhttp3)
-    implementation(libs.okhttp3.logging.interceptor)
-    // timber
-    implementation(libs.timber)
-    // retrofit
-    implementation(libs.retrofit)
-    implementation(libs.retrofit2.kotlin.coroutines.adapter)
-    // sandwich
-    implementation(libs.sandwich)
-    implementation(libs.sandwich.retrofit)
-    // glide
-    implementation(libs.glide.okhttp3.integration)
-    implementation(libs.glide.compose)
-    ksp(libs.glide.ksp)
-    // landscapist
-    implementation(libs.landscapist.glide)
-    implementation(libs.landscapist.transformation)
-    implementation(libs.landscapist.palette)
-    implementation(libs.landscapist.placeholder)
-    // exif
-    implementation(libs.androidx.exifinterface)
-    // exoPlayer
-    implementation(libs.androidx.media3.exoplayer)
-    implementation(libs.androidx.media3.exoplayer.dash)
-    implementation(libs.androidx.media3.exoplayer.hls)
-    implementation(libs.androidx.media3.exoplayer.rtsp)
-    implementation(libs.androidx.media3.datasource.cronet)
-    implementation(libs.androidx.media3.datasource.okhttp)
-    implementation(libs.androidx.media3.datasource.rtmp)
-    implementation(libs.androidx.media3.ui)
-    implementation(libs.androidx.media3.session)
-    implementation(libs.androidx.media3.extractor)
-    implementation(libs.androidx.media3.cast)
-    implementation(libs.androidx.media3.exoplayer.workmanager)
-    implementation(libs.androidx.media3.transformer)
-    implementation(libs.androidx.media3.database)
-    implementation(libs.androidx.media3.decoder)
-    implementation(libs.androidx.media3.datasource)
-    implementation(libs.androidx.media3.common)
-    implementation(libs.androidx.media3.exoplayer.ima)
-    implementation(libs.androidx.media3.ui.leanback)
-    // encrypt
-    implementation(libs.aescrypt)
-    // permission
-    implementation(libs.accompanist.permissions)
-    // another
-    // zxing
-    implementation(libs.zxing.core)
-    // svg
-    implementation(libs.androidsvg.aar)
-    // pallette
-    implementation(libs.androidx.palette.ktx)
-    // lottie
-    implementation(libs.compose.lottie)
-    // jsoup
-    implementation(libs.jsoup)
-    // dm
-    implementation(libs.dailymotion.sdk.android)
-    // dynamic theme
-    implementation(libs.android.material)
-    // widget
-    implementation(libs.androidx.glance.appwidget)
-    implementation(libs.androidx.glance.material)
-    implementation(libs.androidx.glance.material3)
-    // test
-    testImplementation(libs.junit)
-    androidTestImplementation(libs.androidx.junit)
-    androidTestImplementation(libs.androidx.espresso.core)
-    // anr
-    implementation(libs.anrwatchdog)
-    // oauth
-    implementation(libs.auth0)
-    implementation(libs.android.jwtdecode)
+    createReleaseNotes = true
+    createZipRelease = true
 }

+ 34 - 0
buildSrc/build.gradle.kts

@@ -24,7 +24,41 @@ plugins {
 //    id("nl.littlerobots.version-catalog-update") version "0.8.4"
 }
 
+//versionCatalogUpdate {
+//    // sort the catalog by key (default is true)
+//    sortByKey = true
+//    // Referenced that are pinned are not automatically updated.
+//    // They are also not automatically kept however (use keep for that).
+//    pin {
+//        // pins all libraries and plugins using the given versions
+//        versions = ["my-version-name", "other-version"]
+//        // pins specific libraries that are in the version catalog
+//        libraries = [libs.my.library.reference, libs.my.other.library.reference]
+//        // pins specific plugins that are in the version catalog
+//        plugins = [libs.plugins.my.plugin, libs.plugins.my.other.plugin]
+//        // pins all libraries (not plugins) for the given groups
+//        groups = ["com.somegroup", "com.someothergroup"]
+//    }
+//    keep {
+//        // keep has the same options as pin to keep specific entries
+//        // note that for versions it will ONLY keep the specified version, not all
+//        // entries that reference it.
+//        versions = ["my-version-name", "other-version"]
+//        libraries = [libs.my.library.reference, libs.my.other.library.reference]
+//        plugins = [libs.plugins.my.plugin, libs.plugins.my.other.plugin]
+//        groups = ["com.somegroup", "com.someothergroup"]
+//
+//        // keep versions without any library or plugin reference
+//        keepUnusedVersions = true
+//        // keep all libraries that aren't used in the project
+//        keepUnusedLibraries = true
+//        // keep all plugins that aren't used in the project
+//        keepUnusedPlugins = true
+//    }
+//}
+
 dependencies {
+    implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
     implementation(gradleApi())
     implementation(gradleKotlinDsl())
     implementation(kotlin("reflect"))

+ 1 - 77
buildSrc/src/main/kotlin/org/mjdev/gradle/base/BasePlugin.kt

@@ -8,91 +8,15 @@
 
 package org.mjdev.gradle.base
 
-//import com.akuleshov7.ktoml.Toml
-import io.gitlab.arturbosch.detekt.Detekt
 import org.gradle.api.Plugin
 import org.gradle.api.Project
-import org.gradle.api.Task
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.api.internal.catalog.VersionCatalogView
-import org.gradle.internal.impldep.org.tomlj.Toml
-import org.gradle.kotlin.dsl.extra
-import org.gradle.kotlin.dsl.withType
-import org.jetbrains.dokka.gradle.DokkaTask
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-import java.io.FileReader
-import kotlin.reflect.KClass
 
-@Suppress("HasPlatformType", "MemberVisibilityCanBePrivate")
 abstract class BasePlugin : Plugin<Project> {
 
-    val IMPLEMENTATION = "implementation"
-
     override fun apply(project: Project) {
         project.work()
     }
 
     abstract fun Project.work()
 
-    inline fun <reified T> Project.extension(name: String? = null): T = run {
-        var cfg = project.extensions.findByType(T::class.java)
-        if (cfg == null && name != null) {
-            project.extensions.add(name, T::class.java)
-        }
-        cfg = project.extensions.findByType(T::class.java)
-        cfg!!
-    }
-
-    inline fun <reified T : Any> Project.extension(): T = runCatching {
-        extensions.getByType(T::class.java)
-    }.onFailure {
-        println("Config missing.")
-    }.getOrThrow()
-
-    fun <T : Plugin<*>> Project.apply(type: KClass<T>): T = plugins.apply(type.java)
-
-    fun Project.apply(id: String) = plugins.apply(id)
-
-    fun Project.kotlinCompileOptions(scoped: KotlinCompile.() -> Unit) {
-        tasks.withType<KotlinCompile>().first().also { t -> scoped(t) }
-    }
-
-    fun Project.detektTask(scoped: Detekt.() -> Unit) {
-        tasks.withType<Detekt>().first().also { t -> scoped(t) }
-    }
-
-    fun Project.dokkaTask(scoped: DokkaTask.() -> Unit) {
-        tasks.withType<DokkaTask>().first().also { t -> scoped(t) }
-    }
-
-    val Project.assembleTasks
-        get() = tasks.filter { t -> t.name.startsWith("assemble") }
-
-    fun Task.runAfterAssembleTask() {
-        project.assembleTasks.forEach { t -> t.finalizedBy(this) }
-    }
-
-    val Project.versions
-        get() = extra["versions"]
-
-    val Project.libraries
-        get() = extra["libraries"]
-
-    val Project.plugins
-        get() = extra["plugins"]
-
-    fun Project.loadVersionCatalog(path: String) {
-        val file = rootDir.resolve(path)
-        println("Parsing: $file")
-        val toml = FileReader(file).use { f ->
-            Toml.parse(f)
-        }
-        val versions = toml.getTable("versions")?.toMap()
-        val libraries = toml.getTable("libraries")
-        val plugins = toml.getTable("libraries")
-        extra["versions"] = versions
-        extra["libraries"] = libraries
-        extra["plugins"] = plugins
-    }
-
-}
+}

+ 0 - 9
buildSrc/src/main/kotlin/org/mjdev/gradle/base/BaseTask.kt

@@ -12,22 +12,16 @@ package org.mjdev.gradle.base
 
 import com.android.build.gradle.api.ApplicationVariant
 import org.gradle.api.DefaultTask
-import org.gradle.api.logging.Logging
 import org.gradle.api.tasks.Internal
 import org.gradle.api.tasks.SourceTask
 import org.mjdev.gradle.extensions.applicationId
 import org.mjdev.gradle.extensions.buildDirectory
 import org.mjdev.gradle.extensions.capitalize
 import org.mjdev.gradle.extensions.file
-import org.mjdev.gradle.extensions.packageName
 import java.net.URL
 
 open class BaseTask : DefaultTask() {
 
-    private val log by lazy {
-        Logging.getLogger(this::class.java)
-    }
-
     @Internal
     lateinit var variant: ApplicationVariant
 
@@ -76,7 +70,4 @@ open class BaseTask : DefaultTask() {
         get() = project.tasks
             .findByName("compile${variant.name.capitalize()}Kotlin") as? SourceTask
 
-
-    fun println(message: String) = log.lifecycle(message)
-
 }

+ 6 - 6
buildSrc/src/main/kotlin/org/mjdev/gradle/logger/CustomEventLogger.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/CustomEventLogger.kt

@@ -1,14 +1,14 @@
 /*
- * Copyright (c) Milan Jurkulák 2023.
- * Contact:
- * e: mimoccc@gmail.com
- * e: mj@mjdev.org
- * w: https://mjdev.org
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
  */
 
 @file:Suppress("DEPRECATION")
 
-package org.mjdev.gradle.logger
+package org.mjdev.gradle.custom
 
 import org.gradle.BuildAdapter
 import org.gradle.BuildResult

+ 3 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/ExtFileFilter.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/ExtFileFilter.kt

@@ -6,13 +6,14 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.extensions
+package org.mjdev.gradle.custom
 
 import java.io.File
 import java.io.FilenameFilter
 
+@Suppress("unused")
 class ExtFileFilter(extension: String?) : FilenameFilter {
-    var extension: String = String.format(".%s", extension)
+    private var extension: String = String.format(".%s", extension)
 
     override fun accept(dir: File?, fileName: String?): Boolean {
         return fileName?.endsWith(extension) ?: false

+ 14 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/custom/SigningsScope.kt

@@ -0,0 +1,14 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.custom
+
+class SigningsScope(
+    var debugKeyFile: String = "",
+    var releaseKeyFile: String = ""
+)

+ 12 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/SysUtils.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/SysUtils.kt

@@ -1,10 +1,18 @@
-package org.mjdev.gradle.extensions
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.custom
 
 import org.gradle.api.Project
 import java.io.ByteArrayOutputStream
 import java.io.PrintStream
 
-@Suppress("unused")
+@Suppress("unused", "MemberVisibilityCanBePrivate")
 class SysUtils {
     companion object {
 
@@ -42,8 +50,10 @@ class SysUtils {
 
         var text: String = ""
             private set
+
         var exitCode: Int = 0
             private set
+
         var error: Throwable? = null
             private set
 

+ 10 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/LauncherIcon.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIcon.kt

@@ -1,6 +1,14 @@
-package org.mjdev.gradle.icons
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
 
-import org.mjdev.gradle.icons.filter.LauncherIconFilter
+package org.mjdev.gradle.custom.icons
+
+import org.mjdev.gradle.custom.icons.filter.LauncherIconFilter
 import java.awt.image.BufferedImage
 import java.io.File
 import java.io.IOException

+ 0 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/LauncherIconConfig.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIconConfig.kt


+ 0 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/LauncherIconExtension.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIconExtension.kt


+ 0 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/LauncherIconPlugin.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIconPlugin.kt


+ 3 - 3
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/LauncherIconTask.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/LauncherIconTask.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.icons
+package org.mjdev.gradle.custom.icons
 
 import org.gradle.api.tasks.OutputDirectory
 import org.gradle.api.tasks.TaskAction
@@ -14,8 +14,8 @@ import org.mjdev.gradle.base.BaseTask
 import org.mjdev.gradle.extensions.androidManifestFiles
 import org.mjdev.gradle.extensions.fileTree
 import org.mjdev.gradle.extensions.resOutputDirectory
-import org.mjdev.gradle.icons.filter.LauncherIconFilter
-import org.mjdev.gradle.icons.utils.Resources
+import org.mjdev.gradle.custom.icons.filter.LauncherIconFilter
+import org.mjdev.gradle.custom.icons.utils.Resources
 import java.io.File
 
 @Suppress("MemberVisibilityCanBePrivate")

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/filter/ColorRibbonFilter.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/filter/ColorRibbonFilter.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.icons.filter
+package org.mjdev.gradle.custom.icons.filter
 
 import java.awt.Color
 import java.awt.Font

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/filter/GrayscaleFilter.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/filter/GrayscaleFilter.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.icons.filter
+package org.mjdev.gradle.custom.icons.filter
 
 import java.awt.image.BufferedImage
 

+ 16 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/filter/LauncherIconFilter.kt

@@ -0,0 +1,16 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.custom.icons.filter
+
+import java.awt.image.BufferedImage
+
+interface LauncherIconFilter {
+    fun setAdaptiveLauncherMode(enable: Boolean)
+    fun apply(image: BufferedImage)
+}

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/filter/OverlayFilter.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/filter/OverlayFilter.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.icons.filter
+package org.mjdev.gradle.custom.icons.filter
 
 import java.awt.Image
 import java.awt.image.BufferedImage

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/utils/Resources.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/icons/utils/Resources.kt

@@ -8,7 +8,7 @@
 
 @file:Suppress("DEPRECATION")
 
-package org.mjdev.gradle.icons.utils
+package org.mjdev.gradle.custom.icons.utils
 
 import groovy.util.XmlSlurper
 import groovy.util.slurpersupport.GPathResult

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/ClassHelper.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/ClassHelper.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest
+package org.mjdev.gradle.custom.unittest
 
 import java.lang.reflect.Method
 

+ 2 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/ClassHelperImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/ClassHelperImpl.kt

@@ -6,9 +6,9 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest
+package org.mjdev.gradle.custom.unittest
 
-import org.mjdev.gradle.unittest.Constants.Companion.TEST_OBJECT_NAME
+import org.mjdev.gradle.custom.unittest.Constants.Companion.TEST_OBJECT_NAME
 import java.lang.reflect.Method
 import java.lang.reflect.Modifier
 

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/Constants.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/Constants.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest
+package org.mjdev.gradle.custom.unittest
 
 internal class Constants {
     companion object {

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/FilePathHelper.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/FilePathHelper.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest
+package org.mjdev.gradle.custom.unittest
 
 import java.nio.file.Path
 

+ 2 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/FilePathHelperImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/FilePathHelperImpl.kt

@@ -6,9 +6,9 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest
+package org.mjdev.gradle.custom.unittest
 
-import org.mjdev.gradle.unittest.Constants.Companion.KOTLIN_FILE_EXTENSION
+import org.mjdev.gradle.custom.unittest.Constants.Companion.KOTLIN_FILE_EXTENSION
 import java.nio.file.Files
 import java.nio.file.Path
 import java.nio.file.Paths

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/Worker.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/Worker.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest
+package org.mjdev.gradle.custom.unittest
 
 internal interface Worker {
     fun work()

+ 7 - 7
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/WorkerImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/WorkerImpl.kt

@@ -6,14 +6,14 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest
+package org.mjdev.gradle.custom.unittest
 
-import org.mjdev.gradle.unittest.makers.ClassMakerImpl
-import org.mjdev.gradle.unittest.makers.KotlinFileMakerImpl
-import org.mjdev.gradle.unittest.makers.ClassMaker
-import org.mjdev.gradle.unittest.makers.KotlinFileMaker
-import org.mjdev.gradle.unittest.writers.TestFileWriter
-import org.mjdev.gradle.unittest.writers.TestFileWriterImpl
+import org.mjdev.gradle.custom.unittest.makers.ClassMakerImpl
+import org.mjdev.gradle.custom.unittest.makers.KotlinFileMakerImpl
+import org.mjdev.gradle.custom.unittest.makers.ClassMaker
+import org.mjdev.gradle.custom.unittest.makers.KotlinFileMaker
+import org.mjdev.gradle.custom.unittest.writers.TestFileWriter
+import org.mjdev.gradle.custom.unittest.writers.TestFileWriterImpl
 import java.net.URL
 
 internal class WorkerImpl(

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/ClassMaker.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/ClassMaker.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import java.nio.file.Path
 

+ 6 - 6
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/ClassMakerImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/ClassMakerImpl.kt

@@ -8,16 +8,16 @@
 
 @file:Suppress("LocalVariableName")
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import org.mjdev.gradle.extensions.file
 import java.net.URL
 
-import org.mjdev.gradle.unittest.Constants.Companion.DIRECTORY_SEPARATOR
-import org.mjdev.gradle.unittest.Constants.Companion.JAVA_DIRECTORY
-import org.mjdev.gradle.unittest.Constants.Companion.JAVA_FILE_EXTENSION
-import org.mjdev.gradle.unittest.Constants.Companion.KOTLIN_FILE_EXTENSION
-import org.mjdev.gradle.unittest.Constants.Companion.PACKAGE_SEPARATOR
+import org.mjdev.gradle.custom.unittest.Constants.Companion.DIRECTORY_SEPARATOR
+import org.mjdev.gradle.custom.unittest.Constants.Companion.JAVA_DIRECTORY
+import org.mjdev.gradle.custom.unittest.Constants.Companion.JAVA_FILE_EXTENSION
+import org.mjdev.gradle.custom.unittest.Constants.Companion.KOTLIN_FILE_EXTENSION
+import org.mjdev.gradle.custom.unittest.Constants.Companion.PACKAGE_SEPARATOR
 import java.io.File
 import java.net.URLClassLoader
 import java.nio.file.Path

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/KotlinClassMaker.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinClassMaker.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import com.squareup.kotlinpoet.TypeSpec
 

+ 4 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/KotlinClassMakerImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinClassMakerImpl.kt

@@ -6,12 +6,14 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import com.squareup.kotlinpoet.TypeSpec
+import org.mjdev.gradle.custom.unittest.ClassHelper
+import org.mjdev.gradle.custom.unittest.ClassHelperImpl
 
 internal class KotlinClassMakerImpl(
-    private val classHelper: org.mjdev.gradle.unittest.ClassHelper = org.mjdev.gradle.unittest.ClassHelperImpl(),
+    private val classHelper: ClassHelper = ClassHelperImpl(),
     private val kotlinFunctionMaker: KotlinFunctionMaker = KotlinFunctionMakerImpl(),
     private val kotlinPropertyMaker: KotlinPropertyMaker = KotlinPropertyMakerImpl()
 ) : KotlinClassMaker {

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/KotlinFileMaker.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinFileMaker.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import com.squareup.kotlinpoet.FileSpec
 

+ 3 - 3
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/KotlinFileMakerImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinFileMakerImpl.kt

@@ -6,11 +6,11 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import com.squareup.kotlinpoet.FileSpec
-import org.mjdev.gradle.unittest.Constants.Companion.PACKAGE_SEPARATOR
-import org.mjdev.gradle.unittest.Constants.Companion.TEST_FILE_SUFFIX
+import org.mjdev.gradle.custom.unittest.Constants.Companion.PACKAGE_SEPARATOR
+import org.mjdev.gradle.custom.unittest.Constants.Companion.TEST_FILE_SUFFIX
 
 internal class KotlinFileMakerImpl(
     private val kotlinClassMaker: KotlinClassMaker = KotlinClassMakerImpl()

+ 2 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/KotlinFuctionMakerImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinFuctionMakerImpl.kt

@@ -8,9 +8,9 @@
 
 @file:Suppress("SpellCheckingInspection")
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
-import org.mjdev.gradle.unittest.Constants.Companion.TEST_OBJECT_NAME
+import org.mjdev.gradle.custom.unittest.Constants.Companion.TEST_OBJECT_NAME
 import com.squareup.kotlinpoet.FunSpec
 import com.squareup.kotlinpoet.MemberName
 import net.bytebuddy.utility.RandomString

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/KotlinFunctionMaker.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinFunctionMaker.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import com.squareup.kotlinpoet.FunSpec
 import java.lang.reflect.Method

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/KotlinPropertyMaker.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinPropertyMaker.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import com.squareup.kotlinpoet.PropertySpec
 

+ 1 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/makers/KotlinPropertyMakerImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/makers/KotlinPropertyMakerImpl.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.makers
+package org.mjdev.gradle.custom.unittest.makers
 
 import com.squareup.kotlinpoet.KModifier
 import com.squareup.kotlinpoet.PropertySpec

+ 16 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/writers/TestFileWriter.kt

@@ -0,0 +1,16 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.custom.unittest.writers
+
+import com.squareup.kotlinpoet.FileSpec
+import java.nio.file.Path
+
+internal interface TestFileWriter {
+    fun writeFile(file: FileSpec, sourceCodePath: Path)
+}

+ 7 - 7
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/writers/TestFileWriterImpl.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/custom/unittest/writers/TestFileWriterImpl.kt

@@ -6,14 +6,14 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.gradle.unittest.writers
+package org.mjdev.gradle.custom.unittest.writers
 
-import org.mjdev.gradle.unittest.Constants.Companion.DIRECTORY_SEPARATOR
-import org.mjdev.gradle.unittest.Constants.Companion.JAVA_DIRECTORY
-import org.mjdev.gradle.unittest.Constants.Companion.MAIN_DIRECTORY
-import org.mjdev.gradle.unittest.Constants.Companion.PACKAGE_SEPARATOR
-import org.mjdev.gradle.unittest.Constants.Companion.TEST_DIRECTORY
-import org.mjdev.gradle.unittest.Constants.Companion.TEST_FILE_SUFFIX
+import org.mjdev.gradle.custom.unittest.Constants.Companion.DIRECTORY_SEPARATOR
+import org.mjdev.gradle.custom.unittest.Constants.Companion.JAVA_DIRECTORY
+import org.mjdev.gradle.custom.unittest.Constants.Companion.MAIN_DIRECTORY
+import org.mjdev.gradle.custom.unittest.Constants.Companion.PACKAGE_SEPARATOR
+import org.mjdev.gradle.custom.unittest.Constants.Companion.TEST_DIRECTORY
+import org.mjdev.gradle.custom.unittest.Constants.Companion.TEST_FILE_SUFFIX
 import com.squareup.kotlinpoet.FileSpec
 import java.io.File
 import java.nio.file.Path

+ 1 - 5
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/SigningConfigs.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/ApplicationExtensionExt.kt

@@ -15,11 +15,7 @@ import org.gradle.api.Project
 import java.io.FileInputStream
 import java.util.*
 import kotlin.String
-
-class SigningsScope(
-    var debugKeyFile: String = "",
-    var releaseKeyFile: String = ""
-)
+import org.mjdev.gradle.custom.SigningsScope
 
 fun ApplicationExtension.setSigningConfigs(
     project: Project,

+ 70 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/DependencyHandlerScopeExt.kt

@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.extensions
+
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.MinimalExternalModuleDependency
+import org.gradle.api.internal.catalog.ExternalModuleDependencyFactory
+import org.gradle.api.provider.Provider
+import org.gradle.kotlin.dsl.DependencyHandlerScope
+
+private const val IMPLEMENTATION = "implementation"
+private const val DEBUG_IMPLEMENTATION = "debugImplementation"
+private const val ANDROID_TEST_IMPLEMENTATION = "androidTestImplementation"
+private const val TEST_IMPLEMENTATION = "testImplementation"
+private const val KAPT_IMPLEMENTATION = "kapt"
+private const val KSP_IMPLEMENTATION = "ksp"
+
+fun DependencyHandlerScope.implementation(
+    dependency: Provider<MinimalExternalModuleDependency>
+) {
+    add(IMPLEMENTATION, dependency.get())
+}
+
+fun DependencyHandlerScope.implementation(
+    dependency: ExternalModuleDependencyFactory.DependencyNotationSupplier
+) {
+    add(IMPLEMENTATION, dependency.asProvider().get())
+}
+
+fun DependencyHandlerScope.implementation(
+    dependency: Dependency
+) {
+    add(IMPLEMENTATION, dependency)
+}
+
+fun DependencyHandlerScope.debugImplementation(
+    dependency: Provider<MinimalExternalModuleDependency>
+) {
+    add(DEBUG_IMPLEMENTATION, dependency.get())
+}
+
+fun DependencyHandlerScope.androidTestImplementation(
+    dependency: Provider<MinimalExternalModuleDependency>
+) {
+    add(ANDROID_TEST_IMPLEMENTATION, dependency.get())
+}
+
+fun DependencyHandlerScope.testImplementation(
+    dependency: Provider<MinimalExternalModuleDependency>
+) {
+    add(TEST_IMPLEMENTATION, dependency.get())
+}
+
+fun DependencyHandlerScope.ksp(
+    dependency: Provider<MinimalExternalModuleDependency>
+) {
+    add(KSP_IMPLEMENTATION, dependency.get())
+}
+
+fun DependencyHandlerScope.kapt(
+    dependency: Provider<MinimalExternalModuleDependency>
+) {
+    add(KAPT_IMPLEMENTATION, dependency.get())
+}

+ 0 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/File.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/FileExt.kt


+ 1 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/HashMapExt.kt

@@ -8,6 +8,7 @@
 
 package org.mjdev.gradle.extensions
 
+@Suppress("unused")
 fun <T, V> HashMap<T, V>.onKeyExists(
     key: T,
     block: ((key: T, value: V?) -> (Unit))

+ 91 - 37
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/Project.kt → buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/ProjectExt.kt

@@ -15,10 +15,14 @@ import com.android.build.api.variant.AndroidComponentsExtension
 import com.android.build.gradle.AppExtension
 import com.android.build.gradle.api.ApplicationVariant
 import com.android.build.gradle.api.BaseVariant
+import io.gitlab.arturbosch.detekt.Detekt
 import org.gradle.TaskExecutionRequest
-import org.gradle.api.Action
+import org.gradle.accessors.dm.LibrariesForLibs
+import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.api.Task
+import org.gradle.api.logging.Logger
+import org.gradle.api.logging.Logging
 import org.gradle.api.tasks.SourceSet
 import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
 import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME
@@ -26,10 +30,13 @@ import org.gradle.api.tasks.SourceSetContainer
 import org.gradle.api.tasks.TaskProvider
 import org.gradle.kotlin.dsl.extra
 import org.gradle.kotlin.dsl.findByType
+import org.gradle.kotlin.dsl.the
+import org.gradle.kotlin.dsl.withType
+import org.jetbrains.dokka.gradle.DokkaTask
 import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 import java.io.File
-import org.mjdev.gradle.base.BaseTask
-import kotlin.reflect.full.isSubclassOf
+import kotlin.reflect.KClass
 
 private const val VERSION_TAG_MAJOR = "majorVersion"
 private const val VERSION_TAG_MINOR = "minorVersion"
@@ -149,15 +156,15 @@ val Project.androidExtension: AppExtension
 val Project.kotlinExtension: KotlinProjectExtension
     get() = extensions.getByName("kotlin") as KotlinProjectExtension
 
-val Project.assembleTasks: List<Task>
-    get() = mutableListOf<Task>().apply {
-        androidExtension.apply {
-            applicationVariants.all { variant ->
-                val task = project.tasks.getByName("assemble${variant.name.capitalize()}")
-                add(task)
-            }
-        }
-    }
+//val Project.assembleTasks: List<Task>
+//    get() = mutableListOf<Task>().apply {
+//        androidExtension.apply {
+//            applicationVariants.all { variant ->
+//                val task = project.tasks.getByName("assemble${variant.name.capitalize()}")
+//                add(task)
+//            }
+//        }
+//    }
 
 val Project.variants: List<ApplicationVariant>
     get() = androidExtension.applicationVariants.toList()
@@ -165,35 +172,82 @@ val Project.variants: List<ApplicationVariant>
 val Project.unitTestDir: File
     get() = file("src").file("test").file("java")
 
+val Project.assembleTasks
+    get() = tasks.filter { t -> t.name.startsWith("assemble") }
+
+val Project.libs
+    get() = the<LibrariesForLibs>()
+
+val Project.log: Logger
+    get() = Logging.getLogger(this::class.java)
+
+//inline fun <reified T : Task> Project.registerTask(
+//    name: String,
+//    configurationAction: Action<T> = Action<T> {}
+//): List<T> = if (T::class.isSubclassOf(BaseTask::class)) {
+//    mutableListOf<T>().apply {
+//        variants.forEach { variant ->
+//            registerTask<T>(
+//                "$name${variant.name.capitalize()}"
+//            ).apply {
+//                (this.get() as BaseTask).variant = variant
+//            }.get().also { task ->
+//                task.apply {
+//                    configurationAction.execute(this)
+//                    add(this)
+//                }
+//            }
+//        }
+//    }
+//} else {
+//    listOf(registerTask<T>(name).get().apply {
+//        configurationAction.execute(this)
+//    })
+//}
+
+inline fun <reified T> Project.extension(name: String? = null): T = runCatching {
+    var cfg: T? = project.extensions.findByType(T::class.java)
+    if (cfg == null && name != null) {
+        project.extensions.add(name, T::class.java)
+    }
+    cfg = project.extensions.findByType(T::class.java)
+    cfg!!
+}.getOrThrow()
+
+inline fun <reified T : Any> Project.extension(): T = runCatching {
+    extensions.getByType(T::class.java)
+}.onFailure {
+    println("Config missing.")
+}.getOrThrow()
+
 inline fun <reified T : Task> Project.registerTask(
-    name: String,
-    configurationAction: Action<T> = Action<T> {}
-): List<T> = if (T::class.isSubclassOf(BaseTask::class)) {
-    mutableListOf<T>().apply {
-        variants.forEach { variant ->
-            registerTask<T>(
-                "$name${variant.name.capitalize()}"
-            ).apply {
-                (this.get() as BaseTask).variant = variant
-            }.get().also { task ->
-                task.apply {
-                    configurationAction.execute(this)
-                    add(this)
-                }
-            }
-        }
+    name: String? = null,
+    fn: T.() -> Unit = {}
+): T {
+    val taskName = name
+        ?: T::class.java.simpleName.replace("Task", "").unCapitalize()
+    tasks.register(taskName, T::class.java)
+    return tasks.findByName(taskName).let { task ->
+        task as T
+    }.apply {
+        fn(this)
     }
-} else {
-    listOf(registerTask<T>(name).get().apply {
-        configurationAction.execute(this)
-    })
 }
 
-inline fun <reified T : Task> Project.registerTask(
-    name: String
-): TaskProvider<T> {
-//    println("> Registering task : $name[${T::class.simpleName}]")
-    return tasks.register(name, T::class.java)
+fun <T : Plugin<*>> Project.apply(type: KClass<T>): T = plugins.apply(type.java)
+
+fun Project.apply(id: String): Plugin<*> = plugins.apply(id)
+
+fun Project.kotlinCompileOptions(scoped: KotlinCompile.() -> Unit) {
+    tasks.withType<KotlinCompile>().first().also { t -> scoped(t) }
+}
+
+fun Project.detektTask(scoped: Detekt.() -> Unit) {
+    tasks.withType<Detekt>().first().also { t -> scoped(t) }
+}
+
+fun Project.dokkaTask(scoped: DokkaTask.() -> Unit) {
+    tasks.withType<DokkaTask>().first().also { t -> scoped(t) }
 }
 
 fun Project.registerSources(outDir: File, variant: BaseVariant) {

+ 17 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/ProviderExt.kt

@@ -0,0 +1,17 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.gradle.extensions
+
+import org.gradle.api.provider.Provider
+
+val <T> Provider<T>.int: Int
+    get() = get().toString().toInt()
+
+val <T> Provider<T>.string: String
+    get() = get().toString()

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


+ 108 - 92
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/TaskExt.kt

@@ -17,6 +17,8 @@ import com.android.build.gradle.api.BaseVariant
 import org.gradle.StartParameter
 import org.gradle.api.GradleException
 import org.gradle.api.Task
+import org.gradle.api.logging.Logger
+import org.gradle.api.logging.Logging
 import org.gradle.api.plugins.AppliedPlugin
 import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
 import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME
@@ -30,17 +32,82 @@ val Task.projectName: String
 val Task.projectVersion: String
     get() = project.versionName
 
-val Task.tasks: TaskContainer
-    get() = project.tasks
-
 val Task.assembleTasks
     get() = project.assembleTasks
 
+val Task.androidComponents: AndroidComponentsExtension<*, *, *>
+    get() = project.extensions.getByType(AndroidComponentsExtension::class.java)
+
+val Task.android: AppExtension
+    get() = project.extensions.getByType(AppExtension::class.java)
+
+val Task.packageName: String
+    get() = android.defaultConfig.applicationId ?: ""
+
+val Task.variants: List<BaseVariant>
+    get() = android.applicationVariants.toTypedArray().toList()
+
+val Task.taskName: String
+    get() = this.name
+
+val Task.tasks: TaskContainer
+    get() = project.tasks
+
 val Task.cleanTask: Task
     get() = tasks.byName<Task>("clean")
 
-val Task.androidComponents: AndroidComponentsExtension<*, *, *>
-    get() = project.extensions.getByType(AndroidComponentsExtension::class.java)
+val Task.taskGroup: String
+    get() = this.group.toString()
+
+val Task.gradleParams: StartParameter
+    get() = project.gradle.startParameter
+
+val Task.taskParameters: Map<String, String>
+    get() = gradleParams.projectProperties
+
+val Task.runningTasks: List<String>
+    get() = gradleParams.taskNames
+
+val Task.hasAssembleTask: Boolean
+    get() = runningTasks.any { task -> task.lowercase().contains("assemble") }
+
+val Task.normalizedClassName: String
+    get() = this::class.simpleName!!.replace("_Decorated", "")
+
+val Task.resOutputDirectory
+    get() =
+        project.buildDirectory
+            .file("generated")
+            .file("res")
+            .file(normalizedClassName)
+            .file(variantName.lowercase())
+
+val Task.variantName: String
+    get() = (this as? BaseTask)?.variantName ?: ""
+
+val Task.srcOutputDirectory
+    get() = project.buildDirectory
+        .file("generated")
+        .file("source")
+        .file(normalizedClassName)
+        .file(variantName.lowercase())
+
+val Task.log: Logger
+    get() = Logging.getLogger(this::class.java)
+
+val BaseTask.androidManifestFiles: List<File>
+    get() = project.androidExtension.let { app ->
+        listOfNotNull(
+            "main",
+            variant.name,
+            variant.buildType?.name,
+            variant.flavorName
+        ).filterNotEmpty().distinct().map { variantName ->
+            project.file(app.sourceSets.getByName(variantName).manifest.srcFile)
+        }.filter { manifestFile ->
+            manifestFile.exists()
+        }
+    }
 
 @Suppress("UnstableApiUsage")
 fun Task.finalizeDsl(block: CommonExtension<*, *, *, *, *>.() -> Unit) {
@@ -55,10 +122,9 @@ fun Task.finalizeDsl(block: CommonExtension<*, *, *, *, *>.() -> Unit) {
 //    sourceSets.findByName("main")!!.kotlin.srcDirs(dir)
 //}
 
-//fun Task.registerSources(outDir: File, variant: BaseVariant) =
-//    project.registerSources(outDir, variant)
+fun Task.registerSources(outDir: File, variant: BaseVariant) =
+    project.registerSources(outDir, variant)
 
-//@Suppress("UnstableApiUsage")
 fun Task.registerSourceDirectory(outDir: File) {
     android.sourceSets.findByName(MAIN_SOURCE_SET_NAME)?.kotlin?.srcDirs(outDir)
     android.sourceSets.findByName(MAIN_SOURCE_SET_NAME)?.java?.srcDirs(outDir)
@@ -77,7 +143,6 @@ fun Task.registerResourceDirectory(outDir: File) {
 //    }
 }
 
-//@Suppress("UnstableApiUsage")
 fun Task.registerTestSourceDirectory(outDir: File) {
     android.sourceSets.findByName(TEST_SOURCE_SET_NAME)?.kotlin?.srcDirs(outDir)
     android.sourceSets.findByName(TEST_SOURCE_SET_NAME)?.java?.srcDirs(outDir)
@@ -104,23 +169,17 @@ fun Task.registerTestSourceDirectory(outDir: File) {
 //    }
 //}
 
-
-fun Task.runAfterCleanTask() {
+//fun Task.runBeforeCleanTask() {
 //    println("> Task order ${cleanTask.name} -> $name")
-    cleanTask.finalizedBy(this)
-}
-
-fun Task.runBeforeCleanTask() {
-    println("> Task order ${cleanTask.name} -> $name")
-    cleanTask.dependsOn(this)
-}
+//    cleanTask.dependsOn(this)
+//}
 
-fun Task.runAfterPreBuildTask() {
-    val variantName = (this as? BaseTask)?.variantName ?: ""
-    val task = tasks.byName<Task>("pre${variantName}Build")
-//    println("> Task order ${task.name} -> $name")
-    task.finalizedBy(this)
-}
+//fun Task.runAfterPreBuildTask() {
+//    val variantName = (this as? BaseTask)?.variantName ?: ""
+//    val task = tasks.byName<Task>("pre${variantName}Build")
+////    println("> Task order ${task.name} -> $name")
+//    task.finalizedBy(this)
+//}
 
 //fun Task.runAfterAssembleTask() {
 //    val variantName = (this as? BaseTask)?.variantName ?: ""
@@ -130,12 +189,12 @@ fun Task.runAfterPreBuildTask() {
 //    mustRunAfter(task)
 //}
 
-fun Task.runBeforeAssembleTask() {
-    val variantName = (this as? BaseTask)?.variantName ?: ""
-    val task = tasks.byName<Task>("assemble${variantName}")
-//    println("> Task order ${task.name} -> $name")
-    task.dependsOn(this)
-}
+//fun Task.runBeforeAssembleTask() {
+//    val variantName = (this as? BaseTask)?.variantName ?: ""
+//    val task = tasks.byName<Task>("assemble${variantName}")
+////    println("> Task order ${task.name} -> $name")
+//    task.dependsOn(this)
+//}
 
 fun Task.findPlugin(
     name: String
@@ -168,10 +227,6 @@ inline fun <reified T : Task> TaskContainer.byType(): T =
     withType(T::class.java).firstOrNull()
         ?: throw GradleException("Task ${T::class.java} not found")
 
-inline fun <reified T : Task> TaskContainer.byName(name: String): T =
-    findByName(name) as T?
-        ?: throw GradleException("Task $name not found")
-
 inline fun <reified T : Task> Task.runAfter() = tasks.forEach { task ->
     if (task is T) {
         task.finalizedBy(this)
@@ -184,6 +239,19 @@ inline fun <reified T : Task> Task.shouldRunAfter() = tasks.forEach { task ->
     }
 }
 
+
+fun Task.runAfterAssembleTask() {
+    project.assembleTasks.forEach { t -> t.finalizedBy(this) }
+}
+
+fun Task.runAfterCleanTask() {
+    cleanTask.finalizedBy(this)
+}
+
+inline fun <reified T : Task> TaskContainer.byName(name: String): T =
+    findByName(name) as T?
+        ?: throw GradleException("Task $name not found")
+
 fun Task.runAfterAllAssembleVariants(vararg exclude: String) = assembleTasks.map { task ->
     var excluded = false
     exclude.forEach { exclude ->
@@ -202,66 +270,14 @@ fun Task.setTaskDescription(description: String?): Task = this.apply {
     description?.let { this.description = it }
 }
 
-val Task.android: AppExtension
-    get() = project.extensions.getByType(AppExtension::class.java)
-
-val Task.packageName: String
-    get() = android.defaultConfig.applicationId ?: ""
-
-val Task.variants: List<BaseVariant>
-    get() = android.applicationVariants.toTypedArray().toList()
-
-val Task.taskName: String
-    get() = this.name
-
-val Task.taskGroup: String
-    get() = this.group.toString()
+fun Task.println(message: String) = this.log.lifecycle(message)
 
-val Task.gradleParams: StartParameter
-    get() = project.gradle.startParameter
+fun Task.println(exception: Throwable) = this.log.lifecycle(exception.message)
 
-val Task.taskParameters: Map<String, String>
-    get() = gradleParams.projectProperties
+fun Task.printError(message: String) = this.log.error(message)
 
-val Task.runningTasks: List<String>
-    get() = gradleParams.taskNames
-
-val Task.hasAssembleTask: Boolean
-    get() = runningTasks.any { task -> task.lowercase().contains("assemble") }
-
-val Task.normalizedClassName: String
-    get() = this::class.simpleName!!.replace("_Decorated", "")
-
-val Task.resOutputDirectory
-    get() =
-        project.buildDirectory
-            .file("generated")
-            .file("res")
-            .file(normalizedClassName)
-            .file(variantName.lowercase())
-
-val Task.variantName: String
-    get() = (this as? BaseTask)?.variantName ?: ""
-
-val Task.srcOutputDirectory
-    get() = project.buildDirectory
-        .file("generated")
-        .file("source")
-        .file(normalizedClassName)
-        .file(variantName.lowercase())
-
-val BaseTask.androidManifestFiles: List<File>
-    get() = project.androidExtension.let { app ->
-        listOfNotNull(
-            "main",
-            variant.name,
-            variant.buildType?.name,
-            variant.flavorName
-        ).filterNotEmpty().distinct().map { variantName ->
-            project.file(app.sourceSets.getByName(variantName).manifest.srcFile)
-        }.filter { manifestFile ->
-            manifestFile.exists()
-        }
-    }
+fun Task.printError(exception: Throwable) = this.log.error(exception.message)
 
+fun Task.printWarning(message: String) = this.log.warn(message)
 
+fun Task.printWarning(exception: Throwable) = this.log.warn(exception.message)

+ 0 - 8
buildSrc/src/main/kotlin/org/mjdev/gradle/icons/filter/LauncherIconFilter.kt

@@ -1,8 +0,0 @@
-package org.mjdev.gradle.icons.filter
-
-import java.awt.image.BufferedImage
-
-interface LauncherIconFilter {
-    fun setAdaptiveLauncherMode(enable: Boolean)
-    fun apply(image: BufferedImage)
-}

+ 160 - 34
buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/AppPlugin.kt

@@ -15,26 +15,44 @@ import org.gradle.api.JavaVersion
 import org.gradle.api.Project
 import org.gradle.kotlin.dsl.apply
 import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.dependencies
+import org.jetbrains.dokka.Platform
+import org.jmailen.gradle.kotlinter.KotlinterExtension
+import org.jmailen.gradle.kotlinter.KotlinterPlugin
+import org.mjdev.gradle.base.BasePlugin
 import org.mjdev.gradle.extensions.addSyncProviderAuthString
+import org.mjdev.gradle.extensions.asInt
+import org.mjdev.gradle.extensions.registerTask
+import org.mjdev.gradle.extensions.runAfterCleanTask
+import org.mjdev.gradle.extensions.runAfterAssembleTask
 import org.mjdev.gradle.extensions.buildConfigString
+import org.mjdev.gradle.extensions.extension
+import org.mjdev.gradle.extensions.libs
+import org.mjdev.gradle.extensions.string
+import org.mjdev.gradle.extensions.int
 import org.mjdev.gradle.extensions.manifestPlaceholders
+import org.mjdev.gradle.extensions.implementation
+import org.mjdev.gradle.extensions.debugImplementation
+import org.mjdev.gradle.extensions.kapt
+import org.mjdev.gradle.extensions.testImplementation
+import org.mjdev.gradle.extensions.androidTestImplementation
+import org.mjdev.gradle.extensions.ksp
 import org.mjdev.gradle.extensions.setSigningConfigs
 import org.mjdev.gradle.extensions.stringRes
 import org.mjdev.gradle.extensions.versionCode
 import org.mjdev.gradle.extensions.versionName
-import org.gradle.kotlin.dsl.dependencies
-import org.jetbrains.dokka.Platform
-import org.jmailen.gradle.kotlinter.KotlinterExtension
-import org.jmailen.gradle.kotlinter.KotlinterPlugin
-import org.mjdev.gradle.base.BasePlugin
+import org.mjdev.gradle.extensions.kotlinCompileOptions
+import org.mjdev.gradle.extensions.detektTask
+import org.mjdev.gradle.extensions.dokkaTask
+import org.mjdev.gradle.extensions.apply
 import org.mjdev.gradle.plugin.config.AppConfig
-import org.mjdev.gradle.extensions.asInt
+import org.mjdev.gradle.tasks.ReleaseNotesCleanTask
+import org.mjdev.gradle.tasks.ReleaseNotesCreateTask
+import org.mjdev.gradle.tasks.ZipReleaseClearTask
+import org.mjdev.gradle.tasks.ZipReleaseCreateTask
 
 @Suppress("UnstableApiUsage")
 class AppPlugin : BasePlugin() {
-    private val projectNamespace = "org.mjdev.tvapp"
-    private val projectCompileSdk = 34
-    private val projectMinSdk = 21
     private val projectJavaVersion = JavaVersion.VERSION_17
     private val projectKotlinCompilerVersion = "1.5.8"
     private val projectExcludes = listOf(
@@ -51,11 +69,9 @@ class AppPlugin : BasePlugin() {
     private val projectProguardFile = "proguard-android-optimize.txt"
     private val projectProguardRulesFile = "proguard-rules.pro"
     private val projectJacocoVersion = "0.8.8"
-    private val projectLibVersionsFile = "gradle/libs.versions.toml"
     private val configFieldName = "appConfig"
 
     override fun Project.work() {
-        loadVersionCatalog(projectLibVersionsFile)
         extension<AppConfig>(configFieldName)
         apply(plugin = "version-catalog")
         apply(plugin = "kotlin-android")
@@ -66,15 +82,21 @@ class AppPlugin : BasePlugin() {
         apply(plugin = "com.google.dagger.hilt.android")
         apply(plugin = "dagger.hilt.android.plugin")
         apply(plugin = "io.objectbox")
+        apply("org.jetbrains.dokka")
         apply(DetektPlugin::class)
         apply(KotlinterPlugin::class)
-        apply("org.jetbrains.dokka")
+        registerTask<ReleaseNotesCleanTask> {
+            runAfterCleanTask()
+        }
+        registerTask<ZipReleaseClearTask> {
+            runAfterCleanTask()
+        }
         configure<ApplicationExtension> {
-            namespace = projectNamespace
-            compileSdk = projectCompileSdk
+            namespace = libs.versions.app.namespace.string
+            compileSdk = libs.versions.compileSdk.int
             setSigningConfigs(project) {
-                debugKeyFile = "config/signing.prop"
-                releaseKeyFile = "config/signing.prop"
+                debugKeyFile = libs.versions.debug.keyfile.string
+                releaseKeyFile = libs.versions.release.keyfile.string
             }
             buildFeatures {
                 compose = true
@@ -88,9 +110,9 @@ class AppPlugin : BasePlugin() {
                 kotlinCompilerExtensionVersion = projectKotlinCompilerVersion
             }
             defaultConfig {
-                applicationId = projectNamespace
-                minSdk = projectMinSdk
-                targetSdk = projectCompileSdk
+                applicationId = libs.versions.app.namespace.string
+                minSdk = libs.versions.minSdk.int
+                targetSdk = libs.versions.compileSdk.int
                 versionCode = project.versionCode
                 versionName = project.versionName
                 multiDexEnabled = true
@@ -154,9 +176,6 @@ class AppPlugin : BasePlugin() {
                     )
                 }
             }
-//            kotlinOptions {
-//                jvmTarget = JavaVersion.VERSION_17.toString()
-//            }
             sourceSets {
                 getByName("main") { jniLibs.srcDirs() }
             }
@@ -169,12 +188,6 @@ class AppPlugin : BasePlugin() {
                 warningsAsErrors = true
                 disable += "UnusedIds"
             }
-//            kapt {
-//                correctErrorTypes = true
-//            }
-//            hilt {
-//                enableAggregatingTask = true
-//            }
             testOptions {
                 unitTests.isReturnDefaultValues = true
             }
@@ -200,9 +213,9 @@ class AppPlugin : BasePlugin() {
                 suppressObviousFunctions.set(false)
                 dokkaSourceSets.configureEach {
                     offlineMode.set(false)
-                    includeNonPublic.set(true)
+                    includeNonPublic.set(false)
                     skipDeprecated.set(false)
-                    reportUndocumented.set(true)
+                    reportUndocumented.set(false)
                     skipEmptyPackages.set(false)
                     platform.set(Platform.jvm)
                     jdkVersion.set(projectJavaVersion.asInt())
@@ -212,6 +225,13 @@ class AppPlugin : BasePlugin() {
                 }
                 if (appConfig.createDocumentation) runAfterAssembleTask()
             }
+            val rnTask = registerTask<ReleaseNotesCreateTask> {
+                if (appConfig.createReleaseNotes) runAfterAssembleTask()
+            }
+            registerTask<ZipReleaseCreateTask> {
+                mustRunAfter(rnTask)
+                if (appConfig.createZipRelease) runAfterAssembleTask()
+            }
             configure<DetektExtension> {
                 @Suppress("DEPRECATION")
                 config = files(project.rootDir.resolve(appConfig.detectConfigFile))
@@ -239,10 +259,116 @@ class AppPlugin : BasePlugin() {
 //            lockMode.set(LockMode.STRICT)
         }
         dependencies {
-//            add(IMPLEMENTATION, libs.androidx.compose.ui.tooling)
-//            add(IMPLEMENTATION, Dependencies.AndroidX.ANNOTATION)
-//            add(IMPLEMENTATION, Dependencies.AndroidX.APPCOMPAT)
-//            add(IMPLEMENTATION, Dependencies.Kotlin.STD_LIB)
+            implementation(project(mapOf("path" to ":tvlib")))
+            // compose
+            implementation(platform(libs.androidx.compose.bom))
+            implementation(libs.androidx.compose.ui.tooling)
+            implementation(libs.androidx.compose.activity)
+            // more icons
+            implementation(libs.androidx.material.icons.extended)
+            // tv compose
+            implementation(libs.androidx.tv.foundation)
+            implementation(libs.androidx.tv.material)
+            // view model
+            implementation(libs.androidx.compose.lifecycle.viewmodel)
+            // navigation
+            implementation(libs.androidx.compose.navigation)
+            // todo remove, dynamic background & colors
+            implementation(libs.androidx.material3)
+            // previews
+            debugImplementation(libs.androidx.customview.poolingcontainer)
+            // foundation
+            implementation(libs.androidx.foundation)
+            // dagger
+            implementation(libs.dagger)
+            // dagger android
+            implementation(libs.dagger.android)
+            implementation(libs.dagger.android.support)
+            // dagger hilt
+            implementation(libs.dagger.hilt.android)
+            implementation(libs.androidx.compose.hilt.navigation)
+            // dagger annotations
+            kapt(libs.dagger.compiler)
+            kapt(libs.dagger.android.processor)
+            kapt(libs.dagger.hilt.compiler)
+            implementation(libs.moshi)
+            implementation(libs.moshi.retrofit.converter)
+            ksp(libs.moshi.kotlin.codegen)
+            // okhttp
+            implementation(platform(libs.okhttp3.bom))
+            implementation(libs.okhttp3)
+            implementation(libs.okhttp3.logging.interceptor)
+            // timber
+            implementation(libs.timber)
+            // retrofit
+            implementation(libs.retrofit)
+            implementation(libs.retrofit2.kotlin.coroutines.adapter)
+            // sandwich
+            implementation(libs.sandwich)
+            implementation(libs.sandwich.retrofit)
+            // glide
+            implementation(libs.glide.okhttp3.integration)
+            implementation(libs.glide.compose)
+            ksp(libs.glide.ksp)
+            // landscapist
+            implementation(libs.landscapist.glide)
+            implementation(libs.landscapist.transformation)
+            implementation(libs.landscapist.palette)
+            implementation(libs.landscapist.placeholder)
+            // exif
+            implementation(libs.androidx.exifinterface)
+            // exoPlayer
+            implementation(libs.androidx.media3.exoplayer)
+            implementation(libs.androidx.media3.exoplayer.dash)
+            implementation(libs.androidx.media3.exoplayer.hls)
+            implementation(libs.androidx.media3.exoplayer.rtsp)
+            implementation(libs.androidx.media3.datasource.cronet)
+            implementation(libs.androidx.media3.datasource.okhttp)
+            implementation(libs.androidx.media3.datasource.rtmp)
+            implementation(libs.androidx.media3.ui)
+            implementation(libs.androidx.media3.session)
+            implementation(libs.androidx.media3.extractor)
+            implementation(libs.androidx.media3.cast)
+            implementation(libs.androidx.media3.exoplayer.workmanager)
+            implementation(libs.androidx.media3.transformer)
+            implementation(libs.androidx.media3.database)
+            implementation(libs.androidx.media3.decoder)
+            implementation(libs.androidx.media3.datasource)
+            implementation(libs.androidx.media3.common)
+            implementation(libs.androidx.media3.exoplayer.ima)
+            implementation(libs.androidx.media3.ui.leanback)
+            // encrypt
+            implementation(libs.aescrypt)
+            // permission
+            implementation(libs.accompanist.permissions)
+            // another
+            // zxing
+            implementation(libs.zxing.core)
+            // svg
+            implementation(libs.androidsvg.aar)
+            // pallette
+            implementation(libs.androidx.palette.ktx)
+            // lottie
+            implementation(libs.compose.lottie)
+            // jsoup
+            implementation(libs.jsoup)
+            // dm
+            implementation(libs.dailymotion.sdk.android)
+            // dynamic theme
+            implementation(libs.android.material)
+            // widget
+            implementation(libs.androidx.glance.appwidget)
+            implementation(libs.androidx.glance.material)
+            implementation(libs.androidx.glance.material3)
+            // test
+            testImplementation(libs.junit)
+            androidTestImplementation(libs.androidx.junit)
+            androidTestImplementation(libs.androidx.espresso.core)
+            // anr
+            implementation(libs.anrwatchdog)
+            // oauth
+            implementation(libs.auth0)
+            implementation(libs.android.jwtdecode)
         }
     }
 }

+ 133 - 125
buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/LibPlugin.kt

@@ -22,6 +22,19 @@ import org.jmailen.gradle.kotlinter.KotlinterPlugin
 import org.mjdev.gradle.base.BasePlugin
 import org.mjdev.gradle.plugin.config.LibConfig
 import org.mjdev.gradle.extensions.asInt
+import org.mjdev.gradle.extensions.runAfterAssembleTask
+import org.mjdev.gradle.extensions.extension
+import org.mjdev.gradle.extensions.libs
+import org.mjdev.gradle.extensions.implementation
+import org.mjdev.gradle.extensions.debugImplementation
+import org.mjdev.gradle.extensions.kapt
+import org.mjdev.gradle.extensions.testImplementation
+import org.mjdev.gradle.extensions.androidTestImplementation
+import org.mjdev.gradle.extensions.ksp
+import org.mjdev.gradle.extensions.kotlinCompileOptions
+import org.mjdev.gradle.extensions.detektTask
+import org.mjdev.gradle.extensions.dokkaTask
+import org.mjdev.gradle.extensions.apply
 
 @Suppress("UnstableApiUsage")
 class LibPlugin : BasePlugin() {
@@ -44,11 +57,9 @@ class LibPlugin : BasePlugin() {
     private val projectProguardFile = "proguard-android-optimize.txt"
     private val projectProguardRulesFile = "proguard-rules.pro"
     private val projectJacocoVersion = "0.8.8"
-    private val projectLibVersionsFile = "gradle/libs.versions.toml"
     private val configFieldName = "libConfig"
 
     override fun Project.work() {
-        loadVersionCatalog(projectLibVersionsFile)
         extension<LibConfig>(configFieldName)
         apply(plugin ="version-catalog")
         apply(plugin = "kotlin-android")
@@ -140,9 +151,9 @@ class LibPlugin : BasePlugin() {
                 suppressObviousFunctions.set(false)
                 dokkaSourceSets.configureEach {
                     offlineMode.set(false)
-                    includeNonPublic.set(true)
+                    includeNonPublic.set(false)
                     skipDeprecated.set(false)
-                    reportUndocumented.set(true)
+                    reportUndocumented.set(false)
                     skipEmptyPackages.set(false)
                     platform.set(Platform.jvm)
                     jdkVersion.set(projectJavaVersion.asInt())
@@ -171,127 +182,124 @@ class LibPlugin : BasePlugin() {
 //            lockMode.set(LockMode.STRICT)
         }
         dependencies {
-//            add(IMPLEMENTATION, Dependencies.AndroidX.ANNOTATION)
-//            add(IMPLEMENTATION, Dependencies.AndroidX.APPCOMPAT)
-//            add(IMPLEMENTATION, Dependencies.Kotlin.STD_LIB)
-//            // core
-//            implementation(libs.androidx.ktx)
-//            implementation(libs.kotlinx.coroutines.android)
-//            implementation(libs.kotlinx.coroutines.core)
-//            // reflect / todo : remove
-//            implementation(libs.kotlin.reflect)
-//            // window manager
-//            implementation(libs.androidx.window)
-//            // fix duplicates
-//            implementation(libs.androidx.work.runtime.ktx)
-//            // compose
-//            implementation(platform(libs.androidx.compose.bom))
-//            implementation(libs.androidx.compose.ui.tooling)
-//            implementation(libs.androidx.compose.activity)
-//            // more icons
-//            implementation(libs.androidx.material.icons.extended)
-//            // tv compose
-//            implementation(libs.androidx.tv.foundation)
-//            implementation(libs.androidx.tv.material)
-//            // view model
-//            implementation(libs.androidx.compose.lifecycle.viewmodel)
-//            // navigation
-//            implementation(libs.androidx.compose.navigation)
-//            // todo remove, dynamic background & colors
-//            implementation(libs.androidx.material3)
-//            // previews
-//            debugImplementation(libs.androidx.customview.poolingcontainer)
-//            // foundation
-//            implementation(libs.androidx.foundation)
-//            // dagger
-//            implementation(libs.dagger)
-//            // dagger android
-//            implementation(libs.dagger.android)
-//            implementation(libs.dagger.android.support)
-//            // dagger hilt
-//            implementation(libs.dagger.hilt.android)
-//            implementation(libs.androidx.compose.hilt.navigation)
-//            kapt(libs.dagger.compiler)
-//            kapt(libs.dagger.android.processor)
-//            kapt(libs.dagger.hilt.compiler)
-//            // moshi
-//            implementation(libs.moshi)
-//            implementation(libs.moshi.retrofit.converter)
-//            ksp(libs.moshi.kotlin.codegen)
-//            // okhttp
-//            implementation(platform(libs.okhttp3.bom))
-//            implementation(libs.okhttp3)
-//            implementation(libs.okhttp3.logging.interceptor)
-//            // timber
-//            implementation(libs.timber)
-//            // retrofit
-//            implementation(libs.retrofit)
-//            implementation(libs.retrofit2.kotlin.coroutines.adapter)
-//            // sandwich
-//            implementation(libs.sandwich)
-//            implementation(libs.sandwich.retrofit)
-//            // glide
-//            implementation(libs.glide.okhttp3.integration)
-//            implementation(libs.glide.compose)
-//            ksp(libs.glide.ksp)
-//            // landscapist
-//            implementation(libs.landscapist.glide)
-//            implementation(libs.landscapist.transformation)
-//            implementation(libs.landscapist.palette)
-//            implementation(libs.landscapist.placeholder)
-//            // exif
-//            implementation(libs.androidx.exifinterface)
-//            // exoPlayer
-//            implementation(libs.androidx.media3.exoplayer)
-//            implementation(libs.androidx.media3.exoplayer.dash)
-//            implementation(libs.androidx.media3.exoplayer.hls)
-//            implementation(libs.androidx.media3.exoplayer.rtsp)
-//            implementation(libs.androidx.media3.datasource.cronet)
-//            implementation(libs.androidx.media3.datasource.okhttp)
-//            implementation(libs.androidx.media3.datasource.rtmp)
-//            implementation(libs.androidx.media3.ui)
-//            implementation(libs.androidx.media3.session)
-//            implementation(libs.androidx.media3.extractor)
-//            implementation(libs.androidx.media3.cast)
-//            implementation(libs.androidx.media3.exoplayer.workmanager)
-//            implementation(libs.androidx.media3.transformer)
-//            implementation(libs.androidx.media3.database)
-//            implementation(libs.androidx.media3.decoder)
-//            implementation(libs.androidx.media3.datasource)
-//            implementation(libs.androidx.media3.common)
-//            implementation(libs.androidx.media3.exoplayer.ima)
-//            implementation(libs.androidx.media3.ui.leanback)
-//            // encrypt
-//            implementation(libs.aescrypt)
-//            // permission
-//            implementation(libs.accompanist.permissions)
-//            // zxing
-//            implementation(libs.zxing.core)
-//            // svg
-//            implementation(libs.androidsvg.aar)
-//            // pallette
-//            implementation(libs.androidx.palette.ktx)
-//            // lottie
-//            implementation(libs.compose.lottie)
-//            // jsoup
-//            implementation(libs.jsoup)
-//            // dm
-//            implementation(libs.dailymotion.sdk.android)
-//            // dynamic theme
-//            implementation(libs.android.material)
-//            // widget
-//            implementation(libs.androidx.glance.appwidget)
-//            implementation(libs.androidx.glance.material)
-//            implementation(libs.androidx.glance.material3)
-//            // test
-//            testImplementation(libs.junit)
-//            androidTestImplementation(libs.androidx.junit)
-//            androidTestImplementation(libs.androidx.espresso.core)
-//            // anr
-//            implementation(libs.anrwatchdog)
-//            // oauth
-//            implementation(libs.auth0)
-//            implementation(libs.android.jwtdecode)
+            // core
+            implementation(libs.androidx.ktx)
+            implementation(libs.kotlinx.coroutines.android)
+            implementation(libs.kotlinx.coroutines.core)
+            // reflect / todo : remove
+            implementation(libs.kotlin.reflect)
+            // window manager
+            implementation(libs.androidx.window)
+            // fix duplicates
+            implementation(libs.androidx.work.runtime.ktx)
+            // compose
+            implementation(platform(libs.androidx.compose.bom))
+            implementation(libs.androidx.compose.ui.tooling)
+            implementation(libs.androidx.compose.activity)
+            // more icons
+            implementation(libs.androidx.material.icons.extended)
+            // tv compose
+            implementation(libs.androidx.tv.foundation)
+            implementation(libs.androidx.tv.material)
+            // view model
+            implementation(libs.androidx.compose.lifecycle.viewmodel)
+            // navigation
+            implementation(libs.androidx.compose.navigation)
+            // todo remove, dynamic background & colors
+            implementation(libs.androidx.material3)
+            // previews
+            debugImplementation(libs.androidx.customview.poolingcontainer)
+            // foundation
+            implementation(libs.androidx.foundation)
+            // dagger
+            implementation(libs.dagger)
+            // dagger android
+            implementation(libs.dagger.android)
+            implementation(libs.dagger.android.support)
+            // dagger hilt
+            implementation(libs.dagger.hilt.android)
+            implementation(libs.androidx.compose.hilt.navigation)
+            kapt(libs.dagger.compiler)
+            kapt(libs.dagger.android.processor)
+            kapt(libs.dagger.hilt.compiler)
+            // moshi
+            implementation(libs.moshi)
+            implementation(libs.moshi.retrofit.converter)
+            ksp(libs.moshi.kotlin.codegen)
+            // okhttp
+            implementation(platform(libs.okhttp3.bom))
+            implementation(libs.okhttp3)
+            implementation(libs.okhttp3.logging.interceptor)
+            // timber
+            implementation(libs.timber)
+            // retrofit
+            implementation(libs.retrofit)
+            implementation(libs.retrofit2.kotlin.coroutines.adapter)
+            // sandwich
+            implementation(libs.sandwich)
+            implementation(libs.sandwich.retrofit)
+            // glide
+            implementation(libs.glide.okhttp3.integration)
+            implementation(libs.glide.compose)
+            ksp(libs.glide.ksp)
+            // landscapist
+            implementation(libs.landscapist.glide)
+            implementation(libs.landscapist.transformation)
+            implementation(libs.landscapist.palette)
+            implementation(libs.landscapist.placeholder)
+            // exif
+            implementation(libs.androidx.exifinterface)
+            // exoPlayer
+            implementation(libs.androidx.media3.exoplayer)
+            implementation(libs.androidx.media3.exoplayer.dash)
+            implementation(libs.androidx.media3.exoplayer.hls)
+            implementation(libs.androidx.media3.exoplayer.rtsp)
+            implementation(libs.androidx.media3.datasource.cronet)
+            implementation(libs.androidx.media3.datasource.okhttp)
+            implementation(libs.androidx.media3.datasource.rtmp)
+            implementation(libs.androidx.media3.ui)
+            implementation(libs.androidx.media3.session)
+            implementation(libs.androidx.media3.extractor)
+            implementation(libs.androidx.media3.cast)
+            implementation(libs.androidx.media3.exoplayer.workmanager)
+            implementation(libs.androidx.media3.transformer)
+            implementation(libs.androidx.media3.database)
+            implementation(libs.androidx.media3.decoder)
+            implementation(libs.androidx.media3.datasource)
+            implementation(libs.androidx.media3.common)
+            implementation(libs.androidx.media3.exoplayer.ima)
+            implementation(libs.androidx.media3.ui.leanback)
+            // encrypt
+            implementation(libs.aescrypt)
+            // permission
+            implementation(libs.accompanist.permissions)
+            // zxing
+            implementation(libs.zxing.core)
+            // svg
+            implementation(libs.androidsvg.aar)
+            // pallette
+            implementation(libs.androidx.palette.ktx)
+            // lottie
+            implementation(libs.compose.lottie)
+            // jsoup
+            implementation(libs.jsoup)
+            // dm
+            implementation(libs.dailymotion.sdk.android)
+            // dynamic theme
+            implementation(libs.android.material)
+            // widget
+            implementation(libs.androidx.glance.appwidget)
+            implementation(libs.androidx.glance.material)
+            implementation(libs.androidx.glance.material3)
+            // test
+            testImplementation(libs.junit)
+            androidTestImplementation(libs.androidx.junit)
+            androidTestImplementation(libs.androidx.espresso.core)
+            // anr
+            implementation(libs.anrwatchdog)
+            // oauth
+            implementation(libs.auth0)
+            implementation(libs.android.jwtdecode)
         }
     }
 }

+ 6 - 0
buildSrc/src/main/kotlin/org/mjdev/gradle/plugin/config/AppConfig.kt

@@ -11,6 +11,12 @@ package org.mjdev.gradle.plugin.config
 open class AppConfig {
     open var autoCorrectCode = false
     open var createDocumentation = false
+    open var createReleaseNotes = false
+    open var createZipRelease = false
+
+//    open var renameApkOutputByAppID = false
+//    open var createInfoClass = false
+//    open var buildTypeInLauncherIcon = false
 
     open var documentationDir = "documentation/app"
     open var detectConfigFile = "config/detekt.ym"

+ 0 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/tasks/ReleaseNotesCleanTask.kt

@@ -23,8 +23,6 @@ open class ReleaseNotesCleanTask : BaseTask() {
     private val docDir: File
         get() = project.rootProject
             .file("documentation")
-            .file(projectName)
-            .file("documentation")
 
     private val outputFiles = listOf(
         docDir.file(fileName)

+ 1 - 3
buildSrc/src/main/kotlin/org/mjdev/gradle/tasks/ReleaseNotesCreateTask.kt

@@ -32,9 +32,7 @@ open class ReleaseNotesCreateTask : BaseTask() {
         get() = "release-notes-$projectVersion.md"
 
     private val docDir: File
-        get() = project.rootProject
-            .file("documentation")
-            .file(projectName)
+        get() = project.rootProject.file("documentation")
 
     private val outputFiles = listOf(
         docDir.file(fileName)

+ 2 - 2
buildSrc/src/main/kotlin/org/mjdev/gradle/tasks/TestCaseGeneratorTask.kt

@@ -10,8 +10,8 @@ package org.mjdev.gradle.tasks
 
 import org.gradle.api.tasks.TaskAction
 import org.mjdev.gradle.base.BaseTask
-import org.mjdev.gradle.unittest.Worker
-import org.mjdev.gradle.unittest.WorkerImpl
+import org.mjdev.gradle.custom.unittest.Worker
+import org.mjdev.gradle.custom.unittest.WorkerImpl
 
 abstract class TestCaseGeneratorTask : BaseTask() {
 

+ 0 - 1
buildSrc/src/main/kotlin/org/mjdev/gradle/tasks/ZipReleaseCreateTask.kt

@@ -17,7 +17,6 @@ open class ZipReleaseCreateTask : Zip() {
 
     private val releaseFile = project.rootProject
         .file("documentation")
-        .file("app")
         .file("release-notes-$projectVersion.md")
 
     private val readmeFile = project.rootProject

+ 0 - 8
buildSrc/src/main/kotlin/org/mjdev/gradle/unittest/writers/TestFileWriter.kt

@@ -1,8 +0,0 @@
-package org.mjdev.gradle.unittest.writers
-
-import com.squareup.kotlinpoet.FileSpec
-import java.nio.file.Path
-
-internal interface TestFileWriter {
-    fun writeFile(file: FileSpec, sourceCodePath: Path)
-}

+ 1 - 1
config/version.prop

@@ -7,4 +7,4 @@
 #
 majorVersion=1
 minorVersion=2
-patchVersion=5
+patchVersion=6

+ 2 - 2
documentation/home.md

@@ -29,8 +29,8 @@
 
 ## Project documentation
 
-- [App code documentation](https://github.com/mimoccc/tvapp/blob/main/wiki/documentation/app/index.md)
-- [Lib code documentation](https://github.com/mimoccc/tvapp/blob/main/wiki/documentation/lib/index.md)
+- [App code documentation](https://github.com/mimoccc/tvapp/blob/main/documentation/app/index.md)
+- [Lib code documentation](https://github.com/mimoccc/tvapp/blob/main/documentation/lib/index.md)
 
 Documentation contains all the classes in project.
 

+ 4 - 0
gradle/libs.versions.toml

@@ -1,4 +1,8 @@
 [versions]
+app-namespace = "org.mjdev.tvapp"
+debug-keyfile = "config/signing.prop"
+release-keyfile = "config/signing.prop"
+#lib-namespace = ""
 minSdk = "21"
 compileSdk = "34"
 targetSdk = "34"

+ 0 - 154
tvlib/build.gradle.kts

@@ -14,157 +14,3 @@ libConfig {
     autoCorrectCode = false
     createDocumentation = true
 }
-
-//versionCatalogUpdate {
-//    // sort the catalog by key (default is true)
-//    sortByKey = true
-//    // Referenced that are pinned are not automatically updated.
-//    // They are also not automatically kept however (use keep for that).
-//    pin {
-//        // pins all libraries and plugins using the given versions
-//        versions = ["my-version-name", "other-version"]
-//        // pins specific libraries that are in the version catalog
-//        libraries = [libs.my.library.reference, libs.my.other.library.reference]
-//        // pins specific plugins that are in the version catalog
-//        plugins = [libs.plugins.my.plugin, libs.plugins.my.other.plugin]
-//        // pins all libraries (not plugins) for the given groups
-//        groups = ["com.somegroup", "com.someothergroup"]
-//    }
-//    keep {
-//        // keep has the same options as pin to keep specific entries
-//        // note that for versions it will ONLY keep the specified version, not all
-//        // entries that reference it.
-//        versions = ["my-version-name", "other-version"]
-//        libraries = [libs.my.library.reference, libs.my.other.library.reference]
-//        plugins = [libs.plugins.my.plugin, libs.plugins.my.other.plugin]
-//        groups = ["com.somegroup", "com.someothergroup"]
-//
-//        // keep versions without any library or plugin reference
-//        keepUnusedVersions = true
-//        // keep all libraries that aren't used in the project
-//        keepUnusedLibraries = true
-//        // keep all plugins that aren't used in the project
-//        keepUnusedPlugins = true
-//    }
-//}
-
-dependencies {
-    // core
-    implementation(libs.androidx.ktx)
-    implementation(libs.kotlinx.coroutines.android)
-    implementation(libs.kotlinx.coroutines.core)
-    // reflect / todo : remove
-    implementation(libs.kotlin.reflect)
-    // window manager
-    implementation(libs.androidx.window)
-    // fix duplicates
-    implementation(libs.androidx.work.runtime.ktx)
-    // compose
-    implementation(platform(libs.androidx.compose.bom))
-    implementation(libs.androidx.compose.ui.tooling)
-    implementation(libs.androidx.compose.activity)
-    // more icons
-    implementation(libs.androidx.material.icons.extended)
-    // tv compose
-    implementation(libs.androidx.tv.foundation)
-    implementation(libs.androidx.tv.material)
-    // view model
-    implementation(libs.androidx.compose.lifecycle.viewmodel)
-    // navigation
-    implementation(libs.androidx.compose.navigation)
-    // todo remove, dynamic background & colors
-    implementation(libs.androidx.material3)
-    // previews
-    debugImplementation(libs.androidx.customview.poolingcontainer)
-    // foundation
-    implementation(libs.androidx.foundation)
-    // dagger
-    implementation(libs.dagger)
-    // dagger android
-    implementation(libs.dagger.android)
-    implementation(libs.dagger.android.support)
-    // dagger hilt
-    implementation(libs.dagger.hilt.android)
-    implementation(libs.androidx.compose.hilt.navigation)
-    kapt(libs.dagger.compiler)
-    kapt(libs.dagger.android.processor)
-    kapt(libs.dagger.hilt.compiler)
-    // moshi
-    implementation(libs.moshi)
-    implementation(libs.moshi.retrofit.converter)
-    ksp(libs.moshi.kotlin.codegen)
-    // okhttp
-    implementation(platform(libs.okhttp3.bom))
-    implementation(libs.okhttp3)
-    implementation(libs.okhttp3.logging.interceptor)
-    // timber
-    implementation(libs.timber)
-    // retrofit
-    implementation(libs.retrofit)
-    implementation(libs.retrofit2.kotlin.coroutines.adapter)
-    // sandwich
-    implementation(libs.sandwich)
-    implementation(libs.sandwich.retrofit)
-    // glide
-    implementation(libs.glide.okhttp3.integration)
-    implementation(libs.glide.compose)
-    ksp(libs.glide.ksp)
-    // landscapist
-    implementation(libs.landscapist.glide)
-    implementation(libs.landscapist.transformation)
-    implementation(libs.landscapist.palette)
-    implementation(libs.landscapist.placeholder)
-    // exif
-    implementation(libs.androidx.exifinterface)
-    // exoPlayer
-    implementation(libs.androidx.media3.exoplayer)
-    implementation(libs.androidx.media3.exoplayer.dash)
-    implementation(libs.androidx.media3.exoplayer.hls)
-    implementation(libs.androidx.media3.exoplayer.rtsp)
-    implementation(libs.androidx.media3.datasource.cronet)
-    implementation(libs.androidx.media3.datasource.okhttp)
-    implementation(libs.androidx.media3.datasource.rtmp)
-    implementation(libs.androidx.media3.ui)
-    implementation(libs.androidx.media3.session)
-    implementation(libs.androidx.media3.extractor)
-    implementation(libs.androidx.media3.cast)
-    implementation(libs.androidx.media3.exoplayer.workmanager)
-    implementation(libs.androidx.media3.transformer)
-    implementation(libs.androidx.media3.database)
-    implementation(libs.androidx.media3.decoder)
-    implementation(libs.androidx.media3.datasource)
-    implementation(libs.androidx.media3.common)
-    implementation(libs.androidx.media3.exoplayer.ima)
-    implementation(libs.androidx.media3.ui.leanback)
-    // encrypt
-    implementation(libs.aescrypt)
-    // permission
-    implementation(libs.accompanist.permissions)
-    // zxing
-    implementation(libs.zxing.core)
-    // svg
-    implementation(libs.androidsvg.aar)
-    // pallette
-    implementation(libs.androidx.palette.ktx)
-    // lottie
-    implementation(libs.compose.lottie)
-    // jsoup
-    implementation(libs.jsoup)
-    // dm
-    implementation(libs.dailymotion.sdk.android)
-    // dynamic theme
-    implementation(libs.android.material)
-    // widget
-    implementation(libs.androidx.glance.appwidget)
-    implementation(libs.androidx.glance.material)
-    implementation(libs.androidx.glance.material3)
-    // test
-    testImplementation(libs.junit)
-    androidTestImplementation(libs.androidx.junit)
-    androidTestImplementation(libs.androidx.espresso.core)
-    // anr
-    implementation(libs.anrwatchdog)
-    // oauth
-    implementation(libs.auth0)
-    implementation(libs.android.jwtdecode)
-}

+ 10 - 0
web/index.html

@@ -0,0 +1,10 @@
+<!--
+  ~  Copyright (c) Milan Jurkulák 2024.
+  ~  Contact:
+  ~  e: mimoccc@gmail.com
+  ~  e: mj@mjdev.org
+  ~  w: https://mjdev.org
+  -->
+
+<html>
+</html>