First Commit
This commit is contained in:
29
plugins/build.gradle.kts
Normal file
29
plugins/build.gradle.kts
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
`kotlin-dsl-precompiled-script-plugins`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.android.gradle.plugin)
|
||||
implementation(libs.kotlin.gradle.plugin)
|
||||
implementation(libs.kover.gradle.plugin)
|
||||
implementation(platform(libs.google.firebase.bom))
|
||||
implementation(libs.firebase.appdistribution.gradle)
|
||||
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
|
||||
implementation(libs.autonomousapps.dependencyanalysis.plugin)
|
||||
implementation(libs.metro.gradle.plugin)
|
||||
implementation(libs.ksp.gradle.plugin)
|
||||
implementation(libs.compose.compiler.plugin)
|
||||
}
|
||||
20
plugins/settings.gradle.kts
Normal file
20
plugins/settings.gradle.kts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
rootProject.name = "ElementX_plugins"
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../gradle/libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
14
plugins/src/main/kotlin/Enterprise.kt
Normal file
14
plugins/src/main/kotlin/Enterprise.kt
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Are we building with the enterprise sources?
|
||||
*/
|
||||
val isEnterpriseBuild = File("enterprise/README.md").exists()
|
||||
47
plugins/src/main/kotlin/Logger.kt
Normal file
47
plugins/src/main/kotlin/Logger.kt
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import org.gradle.api.logging.Logger
|
||||
import kotlin.math.max
|
||||
|
||||
fun Logger.warnInBox(
|
||||
text: String,
|
||||
minBoxWidth: Int = 80,
|
||||
padding: Int = 4,
|
||||
) {
|
||||
val textLength = text.length
|
||||
val boxWidth = max(textLength + 2, minBoxWidth)
|
||||
val textPadding = max((boxWidth - textLength) / 2, 1)
|
||||
warn(
|
||||
buildString {
|
||||
append(" ".repeat(padding))
|
||||
append("┌")
|
||||
append("─".repeat(boxWidth))
|
||||
append("┐")
|
||||
}
|
||||
)
|
||||
warn(
|
||||
buildString {
|
||||
append(" ".repeat(padding))
|
||||
append("│")
|
||||
append(" ".repeat(textPadding))
|
||||
append(text)
|
||||
append(" ".repeat(textPadding))
|
||||
if (textLength % 2 == 1 && boxWidth == minBoxWidth) append(" ")
|
||||
append("│")
|
||||
}
|
||||
)
|
||||
warn(
|
||||
buildString {
|
||||
append(" ".repeat(padding))
|
||||
append("└")
|
||||
append("─".repeat(boxWidth))
|
||||
append("┘")
|
||||
}
|
||||
)
|
||||
}
|
||||
42
plugins/src/main/kotlin/ModulesConfig.kt
Normal file
42
plugins/src/main/kotlin/ModulesConfig.kt
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import config.AnalyticsConfig
|
||||
import config.BuildTimeConfig
|
||||
import config.PushProvidersConfig
|
||||
|
||||
object ModulesConfig {
|
||||
val pushProvidersConfig = PushProvidersConfig(
|
||||
includeFirebase = BuildTimeConfig.PUSH_CONFIG_INCLUDE_FIREBASE,
|
||||
includeUnifiedPush = BuildTimeConfig.PUSH_CONFIG_INCLUDE_UNIFIED_PUSH,
|
||||
)
|
||||
|
||||
val analyticsConfig: AnalyticsConfig = if (isEnterpriseBuild) {
|
||||
// Is Posthog configuration available?
|
||||
val withPosthog = BuildTimeConfig.SERVICES_POSTHOG_APIKEY.isNullOrEmpty().not() &&
|
||||
BuildTimeConfig.SERVICES_POSTHOG_HOST.isNullOrEmpty().not()
|
||||
// Is Sentry configuration available?
|
||||
val withSentry = BuildTimeConfig.SERVICES_SENTRY_DSN.isNullOrEmpty().not()
|
||||
if (withPosthog || withSentry) {
|
||||
println("Analytics enabled with Posthog: $withPosthog, Sentry: $withSentry")
|
||||
AnalyticsConfig.Enabled(
|
||||
withPosthog = withPosthog,
|
||||
withSentry = withSentry,
|
||||
)
|
||||
} else {
|
||||
println("Analytics disabled")
|
||||
AnalyticsConfig.Disabled
|
||||
}
|
||||
} else {
|
||||
println("Analytics enabled with Posthog and Sentry")
|
||||
AnalyticsConfig.Enabled(
|
||||
withPosthog = true,
|
||||
withSentry = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
108
plugins/src/main/kotlin/Versions.kt
Normal file
108
plugins/src/main/kotlin/Versions.kt
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||
|
||||
/**
|
||||
* Version codes are quite sensitive, because there is a mix between bundle and APKs.
|
||||
* Max versionCode allowed by the PlayStore (for information):
|
||||
* 2_100_000_000
|
||||
*
|
||||
* Also note that the versionCode is multiplied by 10 in app/build.gradle.kts:
|
||||
* ```
|
||||
* output.versionCode.set((output.versionCode.orNull ?: 0) * 10 + abiCode)
|
||||
* ```
|
||||
* We are using a CalVer-like approach to version the application. The version code is calculated as follows:
|
||||
* - 2 digits for the year
|
||||
* - 2 digits for the month
|
||||
* - 1 (or 2) digits for the release number
|
||||
* Note that the version codes need to be greater than the ones calculated for the previous releases, so we use
|
||||
* year on 4 digits for this internal value.
|
||||
* So for instance, the first release of Jan 2025 will have:
|
||||
* - the version name: 25.01.0
|
||||
* - the version code: 20250100a (202_501_00a) where `a` stands for the architecture code
|
||||
*/
|
||||
|
||||
/**
|
||||
* Year of the version on 2 digits.
|
||||
* Do not update this value. it is updated by the release script.
|
||||
*/
|
||||
private const val versionYear = 25
|
||||
|
||||
/**
|
||||
* Month of the version on 2 digits. Value must be in [1,12].
|
||||
* Do not update this value. it is updated by the release script.
|
||||
*/
|
||||
private const val versionMonth = 12
|
||||
|
||||
/**
|
||||
* Release number in the month. Value must be in [0,99].
|
||||
* Do not update this value. it is updated by the release script.
|
||||
*/
|
||||
private const val versionReleaseNumber = 0
|
||||
|
||||
object Versions {
|
||||
/**
|
||||
* Base version code that will be set in the Android Manifest.
|
||||
* The value will be modified at build time to add the ABI code when APK are build.
|
||||
* AAB will have a ABI code of 0.
|
||||
* See comment above for the calculation method.
|
||||
*/
|
||||
const val VERSION_CODE = (2000 + versionYear) * 10_000 + versionMonth * 100 + versionReleaseNumber
|
||||
val VERSION_NAME = "$versionYear.${versionMonth.toString().padStart(2, '0')}.$versionReleaseNumber"
|
||||
|
||||
/**
|
||||
* Compile SDK version. Must be updated when a new Android version is released.
|
||||
* When updating COMPILE_SDK, please also update BUILD_TOOLS_VERSION.
|
||||
*/
|
||||
const val COMPILE_SDK = 36
|
||||
|
||||
/**
|
||||
* Build tools version. Must be kept in sync with COMPILE_SDK.
|
||||
* The value is used by the release script.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
private const val BUILD_TOOLS_VERSION = "36.0.0"
|
||||
|
||||
/**
|
||||
* Target SDK version. Should be kept up to date with COMPILE_SDK.
|
||||
*/
|
||||
const val TARGET_SDK = 36
|
||||
|
||||
/**
|
||||
* Minimum SDK version for FOSS builds.
|
||||
*/
|
||||
private const val MIN_SDK_FOSS = 24
|
||||
|
||||
/**
|
||||
* Minimum SDK version for Enterprise builds.
|
||||
*/
|
||||
private const val MIN_SDK_ENTERPRISE = 33
|
||||
|
||||
/**
|
||||
* minSdkVersion that will be set in the Android Manifest.
|
||||
*/
|
||||
val minSdk = if (isEnterpriseBuild) MIN_SDK_ENTERPRISE else MIN_SDK_FOSS
|
||||
|
||||
/**
|
||||
* Java version used for compilation.
|
||||
* Update this value when you want to use a newer Java version.
|
||||
*/
|
||||
private const val JAVA_VERSION = 21
|
||||
|
||||
val javaVersion: JavaVersion = JavaVersion.toVersion(JAVA_VERSION)
|
||||
val javaLanguageVersion: JavaLanguageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
|
||||
// Perform some checks on the values to avoid releasing with bad values
|
||||
init {
|
||||
require(versionMonth in 1..12) { "versionMonth must be in [1,12]" }
|
||||
require(versionReleaseNumber in 0..99) { "versionReleaseNumber must be in [0,99]" }
|
||||
require(BUILD_TOOLS_VERSION.startsWith(COMPILE_SDK.toString())) { "When updating COMPILE_SDK, please also update BUILD_TOOLS_VERSION" }
|
||||
}
|
||||
}
|
||||
24
plugins/src/main/kotlin/config/AnalyticsConfig.kt
Normal file
24
plugins/src/main/kotlin/config/AnalyticsConfig.kt
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
sealed interface AnalyticsConfig {
|
||||
data class Enabled(
|
||||
val withPosthog: Boolean,
|
||||
val withSentry: Boolean,
|
||||
) : AnalyticsConfig {
|
||||
init {
|
||||
require(withPosthog || withSentry) {
|
||||
"At least one analytics provider must be enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Disabled : AnalyticsConfig
|
||||
}
|
||||
37
plugins/src/main/kotlin/config/BuildTimeConfig.kt
Normal file
37
plugins/src/main/kotlin/config/BuildTimeConfig.kt
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
object BuildTimeConfig {
|
||||
const val APPLICATION_ID = "io.element.android.x"
|
||||
const val APPLICATION_NAME = "Element X"
|
||||
const val GOOGLE_APP_ID_RELEASE = "1:912726360885:android:d097de99a4c23d2700427c"
|
||||
const val GOOGLE_APP_ID_DEBUG = "1:912726360885:android:def0a4e454042e9b00427c"
|
||||
const val GOOGLE_APP_ID_NIGHTLY = "1:912726360885:android:e17435e0beb0303000427c"
|
||||
|
||||
val METADATA_HOST_REVERSED: String? = null
|
||||
val URL_WEBSITE: String? = null
|
||||
val URL_LOGO: String? = null
|
||||
val URL_COPYRIGHT: String? = null
|
||||
val URL_ACCEPTABLE_USE: String? = null
|
||||
val URL_PRIVACY: String? = null
|
||||
val URL_POLICY: String? = null
|
||||
val SERVICES_MAPTILER_BASE_URL: String? = null
|
||||
val SERVICES_MAPTILER_APIKEY: String? = null
|
||||
val SERVICES_MAPTILER_LIGHT_MAPID: String? = null
|
||||
val SERVICES_MAPTILER_DARK_MAPID: String? = null
|
||||
val SERVICES_POSTHOG_HOST: String? = null
|
||||
val SERVICES_POSTHOG_APIKEY: String? = null
|
||||
val SERVICES_SENTRY_DSN: String? = null
|
||||
val BUG_REPORT_URL: String? = null
|
||||
val BUG_REPORT_APP_NAME: String? = null
|
||||
|
||||
const val PUSH_CONFIG_INCLUDE_FIREBASE = true
|
||||
const val PUSH_CONFIG_INCLUDE_UNIFIED_PUSH = true
|
||||
}
|
||||
20
plugins/src/main/kotlin/config/PushProvidersConfig.kt
Normal file
20
plugins/src/main/kotlin/config/PushProvidersConfig.kt
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
data class PushProvidersConfig(
|
||||
val includeFirebase: Boolean,
|
||||
val includeUnifiedPush: Boolean,
|
||||
) {
|
||||
init {
|
||||
require(includeFirebase || includeUnifiedPush) {
|
||||
"At least one push provider must be included"
|
||||
}
|
||||
}
|
||||
}
|
||||
47
plugins/src/main/kotlin/extension/AssetCopyTask.kt
Normal file
47
plugins/src/main/kotlin/extension/AssetCopyTask.kt
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package extension
|
||||
|
||||
import java.io.File
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
@CacheableTask
|
||||
abstract class AssetCopyTask : DefaultTask() {
|
||||
@get:OutputDirectory
|
||||
abstract val outputDirectory: DirectoryProperty
|
||||
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
@get:InputFile
|
||||
abstract val inputFile: RegularFileProperty
|
||||
|
||||
@get:Input
|
||||
abstract val targetFileName: Property<String>
|
||||
|
||||
@TaskAction
|
||||
fun action() {
|
||||
println("Copying ${inputFile.get()} to ${outputDirectory.get().asFile}/${targetFileName.get()}")
|
||||
inputFile.get().asFile.copyTo(
|
||||
target = File(
|
||||
outputDirectory.get().asFile,
|
||||
targetFileName.get(),
|
||||
),
|
||||
overwrite = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
75
plugins/src/main/kotlin/extension/CommonExtension.kt
Normal file
75
plugins/src/main/kotlin/extension/CommonExtension.kt
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package extension
|
||||
|
||||
import Versions
|
||||
import com.android.build.api.dsl.CommonExtension
|
||||
import isEnterpriseBuild
|
||||
import org.gradle.api.Project
|
||||
import java.io.File
|
||||
|
||||
fun CommonExtension<*, *, *, *, *, *>.androidConfig(project: Project) {
|
||||
defaultConfig {
|
||||
compileSdk = Versions.COMPILE_SDK
|
||||
minSdk = Versions.minSdk
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
generatedDensities()
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = Versions.javaVersion
|
||||
targetCompatibility = Versions.javaVersion
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests.isReturnDefaultValues = true
|
||||
}
|
||||
|
||||
lint {
|
||||
lintConfig = File("${project.rootDir}/tools/lint/lint.xml")
|
||||
if (isEnterpriseBuild) {
|
||||
// Disable check on ObsoleteSdkInt for Enterprise builds
|
||||
// since the min sdk is higher for Enterprise builds
|
||||
disable.add("ObsoleteSdkInt")
|
||||
}
|
||||
checkDependencies = false
|
||||
abortOnError = true
|
||||
ignoreTestSources = true
|
||||
ignoreTestFixturesSources = true
|
||||
checkGeneratedSources = false
|
||||
}
|
||||
}
|
||||
|
||||
fun CommonExtension<*, *, *, *, *, *>.composeConfig() {
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
|
||||
packaging {
|
||||
resources.excludes.apply {
|
||||
add("META-INF/AL2.0")
|
||||
add("META-INF/LGPL2.1")
|
||||
}
|
||||
}
|
||||
|
||||
lint {
|
||||
// Extra rules for compose
|
||||
// Disabled until lint stops inspecting generated ksp files...
|
||||
// error.add("ComposableLambdaParameterNaming")
|
||||
error.add("ComposableLambdaParameterPosition")
|
||||
ignoreTestFixturesSources = true
|
||||
checkGeneratedSources = false
|
||||
}
|
||||
}
|
||||
|
||||
176
plugins/src/main/kotlin/extension/DependencyHandleScope.kt
Normal file
176
plugins/src/main/kotlin/extension/DependencyHandleScope.kt
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package extension
|
||||
|
||||
import ModulesConfig
|
||||
import config.AnalyticsConfig
|
||||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.ExternalModuleDependency
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
import org.gradle.kotlin.dsl.DependencyHandlerScope
|
||||
import org.gradle.kotlin.dsl.closureOf
|
||||
import org.gradle.kotlin.dsl.project
|
||||
|
||||
private fun DependencyHandlerScope.implementation(dependency: Any) = dependencies.add("implementation", dependency)
|
||||
private fun DependencyHandlerScope.testImplementation(dependency: Any) = dependencies.add("testImplementation", dependency)
|
||||
private fun DependencyHandlerScope.testReleaseImplementation(dependency: Any) = dependencies.add("testReleaseImplementation", dependency)
|
||||
internal fun DependencyHandler.implementation(dependency: Any) = add("implementation", dependency)
|
||||
|
||||
// Implementation + config block
|
||||
private fun DependencyHandlerScope.implementation(
|
||||
dependency: Any,
|
||||
config: Action<ExternalModuleDependency>
|
||||
) = dependencies.add("implementation", dependency, closureOf<ExternalModuleDependency> { config.execute(this) })
|
||||
|
||||
private fun DependencyHandlerScope.androidTestImplementation(dependency: Any) = dependencies.add("androidTestImplementation", dependency)
|
||||
|
||||
private fun DependencyHandlerScope.debugImplementation(dependency: Any) = dependencies.add("debugImplementation", dependency)
|
||||
private fun DependencyHandlerScope.releaseImplementation(dependency: Any) = dependencies.add("releaseImplementation", dependency)
|
||||
|
||||
/**
|
||||
* Dependencies used for unit tests.
|
||||
*/
|
||||
fun DependencyHandlerScope.testCommonDependencies(
|
||||
libs: LibrariesForLibs,
|
||||
includeTestComposeView: Boolean = false,
|
||||
) {
|
||||
testImplementation(libs.androidx.test.ext.junit)
|
||||
testImplementation(libs.coroutines.test)
|
||||
testImplementation(libs.molecule.runtime)
|
||||
testImplementation(libs.test.appyx.junit)
|
||||
testImplementation(libs.test.arch.core)
|
||||
testImplementation(libs.test.junit)
|
||||
testImplementation(libs.test.mockk)
|
||||
testImplementation(libs.test.robolectric)
|
||||
testImplementation(libs.test.truth)
|
||||
testImplementation(libs.test.turbine)
|
||||
testImplementation(project(":tests:testutils"))
|
||||
if (includeTestComposeView) {
|
||||
testImplementation(libs.androidx.compose.ui.test.junit)
|
||||
testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dependencies used by all the modules
|
||||
*/
|
||||
fun DependencyHandlerScope.commonDependencies(libs: LibrariesForLibs) {
|
||||
implementation(libs.timber)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dependencies used by all the modules with composable items
|
||||
*/
|
||||
fun DependencyHandlerScope.composeDependencies(libs: LibrariesForLibs) {
|
||||
val composeBom = platform(libs.androidx.compose.bom)
|
||||
implementation(composeBom)
|
||||
androidTestImplementation(composeBom)
|
||||
implementation(libs.androidx.compose.ui)
|
||||
implementation(libs.androidx.compose.material)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.material.icons)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||
implementation(libs.kotlinx.collections.immutable)
|
||||
}
|
||||
|
||||
fun DependencyHandlerScope.allLibrariesImpl() {
|
||||
implementation(project(":libraries:androidutils"))
|
||||
implementation(project(":libraries:deeplink:impl"))
|
||||
implementation(project(":libraries:designsystem"))
|
||||
implementation(project(":libraries:matrix:impl"))
|
||||
implementation(project(":libraries:matrixui"))
|
||||
implementation(project(":libraries:matrixmedia:impl"))
|
||||
implementation(project(":libraries:network"))
|
||||
implementation(project(":libraries:core"))
|
||||
implementation(project(":libraries:eventformatter:impl"))
|
||||
implementation(project(":libraries:indicator:impl"))
|
||||
implementation(project(":libraries:permissions:impl"))
|
||||
implementation(project(":libraries:audio:impl"))
|
||||
implementation(project(":libraries:push:impl"))
|
||||
implementation(project(":libraries:featureflag:impl"))
|
||||
implementation(project(":libraries:pushstore:impl"))
|
||||
implementation(project(":libraries:preferences:impl"))
|
||||
implementation(project(":libraries:architecture"))
|
||||
implementation(project(":libraries:dateformatter:impl"))
|
||||
implementation(project(":libraries:di"))
|
||||
implementation(project(":libraries:session-storage:impl"))
|
||||
implementation(project(":libraries:mediapickers:impl"))
|
||||
implementation(project(":libraries:mediaupload:impl"))
|
||||
implementation(project(":libraries:usersearch:impl"))
|
||||
implementation(project(":libraries:textcomposer:impl"))
|
||||
implementation(project(":libraries:accountselect:impl"))
|
||||
implementation(project(":libraries:roomselect:impl"))
|
||||
implementation(project(":libraries:cryptography:impl"))
|
||||
implementation(project(":libraries:voiceplayer:impl"))
|
||||
implementation(project(":libraries:voicerecorder:impl"))
|
||||
implementation(project(":libraries:mediaplayer:impl"))
|
||||
implementation(project(":libraries:mediaviewer:impl"))
|
||||
implementation(project(":libraries:troubleshoot:impl"))
|
||||
implementation(project(":libraries:fullscreenintent:impl"))
|
||||
implementation(project(":libraries:wellknown:impl"))
|
||||
implementation(project(":libraries:oidc:impl"))
|
||||
implementation(project(":libraries:workmanager:impl"))
|
||||
implementation(project(":libraries:recentemojis:impl"))
|
||||
}
|
||||
|
||||
fun DependencyHandlerScope.allServicesImpl() {
|
||||
implementation(project(":services:analytics:compose"))
|
||||
when (ModulesConfig.analyticsConfig) {
|
||||
AnalyticsConfig.Disabled -> {
|
||||
implementation(project(":services:analytics:noop"))
|
||||
}
|
||||
is AnalyticsConfig.Enabled -> {
|
||||
implementation(project(":services:analytics:impl"))
|
||||
if (ModulesConfig.analyticsConfig.withPosthog) {
|
||||
implementation(project(":services:analyticsproviders:posthog"))
|
||||
}
|
||||
if (ModulesConfig.analyticsConfig.withSentry) {
|
||||
implementation(project(":services:analyticsproviders:sentry"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
implementation(project(":services:apperror:impl"))
|
||||
implementation(project(":services:appnavstate:impl"))
|
||||
implementation(project(":services:toolbox:impl"))
|
||||
}
|
||||
|
||||
fun DependencyHandlerScope.allEnterpriseImpl(project: Project) = addAll(
|
||||
project = project,
|
||||
modulePrefix = ":enterprise:features",
|
||||
moduleSuffix = ":impl",
|
||||
)
|
||||
|
||||
fun DependencyHandlerScope.allFeaturesImpl(project: Project) = addAll(
|
||||
project = project,
|
||||
modulePrefix = ":features",
|
||||
moduleSuffix = ":impl",
|
||||
)
|
||||
|
||||
fun DependencyHandlerScope.allFeaturesApi(project: Project) = addAll(
|
||||
project = project,
|
||||
modulePrefix = ":features",
|
||||
moduleSuffix = ":api",
|
||||
)
|
||||
|
||||
private fun DependencyHandlerScope.addAll(
|
||||
project: Project,
|
||||
modulePrefix: String,
|
||||
moduleSuffix: String,
|
||||
) {
|
||||
val subProjects = project.rootProject.subprojects.filter { it.path.startsWith(modulePrefix) && it.path.endsWith(moduleSuffix) }
|
||||
for (p in subProjects) {
|
||||
add("implementation", p)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package extension
|
||||
|
||||
import dev.zacsweers.metro.gradle.MetroPluginExtension
|
||||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.kotlin.dsl.the
|
||||
import org.gradle.plugin.use.PluginDependency
|
||||
|
||||
/**
|
||||
* Setup the Metro plugin with the shared configuration.
|
||||
* @param generateNodeFactories Whether to set up the KSP plugin and dependencies to generate Appyx Node factories.
|
||||
*/
|
||||
fun Project.setupDependencyInjection(
|
||||
generateNodeFactories: Boolean = shouldApplyAppyxCodegen(),
|
||||
) {
|
||||
if (project.path.endsWith(":api")) {
|
||||
error("api module should not use setupDependencyInjection(). Move the implementation to `:impl` module")
|
||||
}
|
||||
|
||||
val libs = the<LibrariesForLibs>()
|
||||
|
||||
// Apply Metro plugin and configure it
|
||||
applyPluginIfNeeded(libs.plugins.metro)
|
||||
|
||||
val metroExtension = extensions.getByName("metro") as MetroPluginExtension
|
||||
metroExtension.contributesAsInject.value(true)
|
||||
|
||||
if (generateNodeFactories) {
|
||||
applyPluginIfNeeded(libs.plugins.ksp)
|
||||
|
||||
// Annotations to generate DI code for Appyx nodes
|
||||
dependencies.implementation(project.project(":annotations"))
|
||||
// Code generator for the annotations above
|
||||
dependencies.add("ksp", project.project(":codegen"))
|
||||
}
|
||||
}
|
||||
|
||||
// These dependencies should only be needed for compose library or application modules
|
||||
private fun Project.shouldApplyAppyxCodegen(): Boolean {
|
||||
return project.pluginManager.hasPlugin("io.element.android-compose-library")
|
||||
|| project.pluginManager.hasPlugin("io.element.android-compose-application")
|
||||
}
|
||||
|
||||
private fun Project.applyPluginIfNeeded(plugin: Provider<PluginDependency>) {
|
||||
val pluginId = plugin.get().pluginId
|
||||
if (!pluginManager.hasPlugin(pluginId)) {
|
||||
pluginManager.apply(pluginId)
|
||||
}
|
||||
}
|
||||
247
plugins/src/main/kotlin/extension/KoverExtension.kt
Normal file
247
plugins/src/main/kotlin/extension/KoverExtension.kt
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package extension
|
||||
|
||||
import kotlinx.kover.gradle.plugin.dsl.AggregationType
|
||||
import kotlinx.kover.gradle.plugin.dsl.CoverageUnit
|
||||
import kotlinx.kover.gradle.plugin.dsl.GroupingEntityType
|
||||
import kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension
|
||||
import kotlinx.kover.gradle.plugin.dsl.KoverVariantCreateConfig
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.assign
|
||||
|
||||
enum class KoverVariant(val variantName: String) {
|
||||
Presenters("presenters"),
|
||||
States("states"),
|
||||
Views("views"),
|
||||
}
|
||||
|
||||
val koverVariants = KoverVariant.values().map { it.variantName }
|
||||
|
||||
val localAarProjects = listOf(
|
||||
":libraries:rustsdk",
|
||||
":libraries:textcomposer:lib"
|
||||
)
|
||||
|
||||
val excludedKoverSubProjects = listOf(
|
||||
":app",
|
||||
":annotations",
|
||||
":codegen",
|
||||
":tests:testutils",
|
||||
// Exclude modules which are not Android libraries
|
||||
// See https://github.com/Kotlin/kotlinx-kover/issues/312
|
||||
":appconfig",
|
||||
":libraries:core",
|
||||
":libraries:coroutines",
|
||||
":libraries:di",
|
||||
) + localAarProjects
|
||||
|
||||
private fun Project.kover(action: Action<KoverProjectExtension>) {
|
||||
(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("kover", action)
|
||||
}
|
||||
|
||||
fun Project.setupKover() {
|
||||
// Create verify all task joining all existing verification tasks
|
||||
tasks.register("koverVerifyAll") {
|
||||
group = "verification"
|
||||
description = "Verifies the code coverage of all subprojects."
|
||||
val dependencies = listOf(":app:koverVerifyGplayDebug") + koverVariants.map { ":app:koverVerify${it.replaceFirstChar(Char::titlecase)}" }
|
||||
dependsOn(dependencies)
|
||||
}
|
||||
// https://kotlin.github.io/kotlinx-kover/
|
||||
// Run `./gradlew :app:koverHtmlReport` to get report at ./app/build/reports/kover
|
||||
// Run `./gradlew :app:koverXmlReport` to get XML report
|
||||
kover {
|
||||
reports {
|
||||
filters {
|
||||
excludes {
|
||||
classes(
|
||||
// Exclude generated classes.
|
||||
"*_Module",
|
||||
"*_AssistedFactory",
|
||||
"com.airbnb.android.showkase*",
|
||||
"io.element.android.libraries.designsystem.showkase.*",
|
||||
"*ComposableSingletons$*",
|
||||
"*BuildConfig",
|
||||
// Generated by Showkase
|
||||
"*Ioelementandroid*PreviewKt$*",
|
||||
"*Ioelementandroid*PreviewKt",
|
||||
// Other
|
||||
// We do not cover Nodes (normally covered by maestro, but code coverage is not computed with maestro)
|
||||
"*Node",
|
||||
"*Node$*",
|
||||
"*Presenter\$present\$*",
|
||||
// Forked from compose
|
||||
"io.element.android.libraries.designsystem.theme.components.bottomsheet.*",
|
||||
// Konsist code to make test fails
|
||||
"io.element.android.tests.konsist.failures",
|
||||
)
|
||||
annotatedBy(
|
||||
"androidx.compose.ui.tooling.preview.Preview",
|
||||
"io.element.android.libraries.architecture.coverage.ExcludeFromCoverage",
|
||||
"io.element.android.libraries.designsystem.preview.*",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
total {
|
||||
verify {
|
||||
// General rule: minimum code coverage.
|
||||
rule("Global minimum code coverage.") {
|
||||
groupBy = GroupingEntityType.APPLICATION
|
||||
bound {
|
||||
minValue = 70
|
||||
// Setting a max value, so that if coverage is bigger, it means that we have to change minValue.
|
||||
// For instance if we have minValue = 20 and maxValue = 30, and current code coverage is now 31.32%, update
|
||||
// minValue to 25 and maxValue to 35.
|
||||
maxValue = 80
|
||||
coverageUnits = CoverageUnit.INSTRUCTION
|
||||
aggregationForGroup = AggregationType.COVERED_PERCENTAGE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
variant(KoverVariant.Presenters.variantName) {
|
||||
verify {
|
||||
// Rule to ensure that coverage of Presenters is sufficient.
|
||||
rule("Check code coverage of presenters") {
|
||||
groupBy = GroupingEntityType.CLASS
|
||||
|
||||
bound {
|
||||
minValue = 85
|
||||
coverageUnits = CoverageUnit.INSTRUCTION
|
||||
aggregationForGroup = AggregationType.COVERED_PERCENTAGE
|
||||
}
|
||||
}
|
||||
}
|
||||
filters {
|
||||
excludes.classes(
|
||||
"*Fake*Presenter*",
|
||||
"io.element.android.appnav.loggedin.LoggedInPresenter$*",
|
||||
// Some options can't be tested at the moment
|
||||
"io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*",
|
||||
// Need an Activity to use rememberMultiplePermissionsState
|
||||
"io.element.android.features.location.impl.common.permissions.DefaultPermissionsPresenter",
|
||||
"*Presenter\$present\$*",
|
||||
// Too small to be > 85% tested
|
||||
"io.element.android.libraries.fullscreenintent.impl.DefaultFullScreenIntentPermissionsPresenter",
|
||||
)
|
||||
includes.inheritedFrom("io.element.android.libraries.architecture.Presenter")
|
||||
}
|
||||
}
|
||||
variant(KoverVariant.States.variantName) {
|
||||
verify {
|
||||
// Rule to ensure that coverage of States is sufficient.
|
||||
rule("Check code coverage of states") {
|
||||
groupBy = GroupingEntityType.CLASS
|
||||
bound {
|
||||
minValue = 90
|
||||
coverageUnits = CoverageUnit.INSTRUCTION
|
||||
aggregationForGroup = AggregationType.COVERED_PERCENTAGE
|
||||
}
|
||||
}
|
||||
}
|
||||
filters {
|
||||
excludes.classes(
|
||||
"*State$*", // Exclude inner classes
|
||||
"io.element.android.appnav.root.RootNavState",
|
||||
"io.element.android.features.ftue.api.state.*",
|
||||
"io.element.android.features.ftue.impl.welcome.state.*",
|
||||
"io.element.android.features.messages.impl.timeline.model.bubble.BubbleState",
|
||||
"io.element.android.libraries.designsystem.swipe.SwipeableActionsState",
|
||||
"io.element.android.libraries.designsystem.theme.components.bottomsheet.CustomSheetState",
|
||||
"io.element.android.libraries.maplibre.compose.CameraPositionState",
|
||||
"io.element.android.libraries.maplibre.compose.SymbolState",
|
||||
"io.element.android.libraries.matrix.api.room.RoomMembershipState",
|
||||
"io.element.android.libraries.matrix.api.room.RoomMembersState",
|
||||
"io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*",
|
||||
"io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*",
|
||||
"io.element.android.libraries.mediaviewer.impl.local.pdf.PdfViewerState",
|
||||
"io.element.android.libraries.mediaviewer.impl.local.player.MediaPlayerControllerState",
|
||||
"io.element.android.libraries.textcomposer.model.TextEditorState",
|
||||
"io.element.android.libraries.textcomposer.components.FormattingOptionState",
|
||||
)
|
||||
includes.classes("*State")
|
||||
}
|
||||
}
|
||||
variant(KoverVariant.Views.variantName) {
|
||||
verify {
|
||||
// Rule to ensure that coverage of Views is sufficient (deactivated for now).
|
||||
rule("Check code coverage of views") {
|
||||
groupBy = GroupingEntityType.CLASS
|
||||
bound {
|
||||
// TODO Update this value, for now there are too many missing tests.
|
||||
minValue = 0
|
||||
coverageUnits = CoverageUnit.INSTRUCTION
|
||||
aggregationForGroup = AggregationType.COVERED_PERCENTAGE
|
||||
}
|
||||
}
|
||||
}
|
||||
filters {
|
||||
excludes.classes("*ViewKt$*") // Exclude inner classes
|
||||
includes.classes("*ViewKt")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.applyKoverPluginToAllSubProjects() = rootProject.subprojects {
|
||||
if (project.path !in localAarProjects) {
|
||||
apply(plugin = "org.jetbrains.kotlinx.kover")
|
||||
kover {
|
||||
currentProject {
|
||||
for (variant in koverVariants) {
|
||||
createVariant(variant) {
|
||||
defaultVariants(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
for (variant in koverVariants) {
|
||||
// Using the cache for coverage verification seems to be flaky, so we disable it for now.
|
||||
val taskName = "koverCachedVerify${variant.replaceFirstChar(Char::titlecase)}"
|
||||
val cachedTask = project.tasks.findByName(taskName)
|
||||
cachedTask?.let {
|
||||
it.outputs.upToDateWhen { false }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun KoverVariantCreateConfig.defaultVariants(project: Project) {
|
||||
if (project.name == "app") {
|
||||
addWithDependencies("gplayDebug")
|
||||
} else {
|
||||
addWithDependencies("debug", "jvm", optional = true)
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.koverSubprojects() = project.rootProject.subprojects
|
||||
.filter {
|
||||
it.project.projectDir.resolve("build.gradle.kts").exists()
|
||||
}
|
||||
.map { it.path }
|
||||
.sorted()
|
||||
.filter {
|
||||
it !in excludedKoverSubProjects
|
||||
}
|
||||
|
||||
fun Project.koverDependencies() {
|
||||
project.koverSubprojects()
|
||||
.forEach {
|
||||
// println("Add $it to kover")
|
||||
dependencies.add("kover", project(it))
|
||||
}
|
||||
}
|
||||
58
plugins/src/main/kotlin/extension/Utils.kt
Normal file
58
plugins/src/main/kotlin/extension/Utils.kt
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package extension
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.provider.ValueSource
|
||||
import org.gradle.api.provider.ValueSourceParameters
|
||||
import org.gradle.process.ExecOperations
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
import java.util.Properties
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class GitRevisionValueSource : ValueSource<String, ValueSourceParameters.None> {
|
||||
@get:Inject
|
||||
abstract val execOperations: ExecOperations
|
||||
|
||||
override fun obtain(): String? {
|
||||
return execOperations.runCommand("git rev-parse --short=8 HEAD")
|
||||
}
|
||||
}
|
||||
|
||||
abstract class GitBranchNameValueSource : ValueSource<String, ValueSourceParameters.None> {
|
||||
@get:Inject
|
||||
abstract val execOperations: ExecOperations
|
||||
|
||||
override fun obtain(): String? {
|
||||
return execOperations.runCommand("git rev-parse --abbrev-ref HEAD")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExecOperations.runCommand(cmd: String): String {
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
val errorStream = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = cmd.split(" ")
|
||||
standardOutput = outputStream
|
||||
errorOutput = errorStream
|
||||
}
|
||||
if (errorStream.size() > 0) {
|
||||
println("Error while running command: $cmd")
|
||||
throw IOException(String(errorStream.toByteArray()))
|
||||
}
|
||||
return String(outputStream.toByteArray()).trim()
|
||||
}
|
||||
|
||||
fun Project.readLocalProperty(name: String): String? = Properties().apply {
|
||||
try {
|
||||
load(rootProject.file("local.properties").reader())
|
||||
} catch (ignored: IOException) {
|
||||
}
|
||||
}.getProperty(name)
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package extension
|
||||
|
||||
import com.android.build.api.dsl.VariantDimension
|
||||
|
||||
fun VariantDimension.buildConfigFieldStr(
|
||||
name: String,
|
||||
value: String,
|
||||
) {
|
||||
buildConfigField(
|
||||
type = "String",
|
||||
name = name,
|
||||
value = "\"$value\""
|
||||
)
|
||||
}
|
||||
|
||||
fun VariantDimension.buildConfigFieldBoolean(
|
||||
name: String,
|
||||
value: Boolean,
|
||||
) {
|
||||
buildConfigField(
|
||||
type = "boolean",
|
||||
name = name,
|
||||
value = value.toString()
|
||||
)
|
||||
}
|
||||
19
plugins/src/main/kotlin/extension/VersionCatalog.kt
Normal file
19
plugins/src/main/kotlin/extension/VersionCatalog.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package extension
|
||||
|
||||
import org.gradle.api.artifacts.VersionCatalog
|
||||
|
||||
private fun VersionCatalog.getVersion(alias: String) = findVersion(alias).get()
|
||||
|
||||
private fun VersionCatalog.getLibrary(library: String) = findLibrary(library).get()
|
||||
|
||||
private fun VersionCatalog.getBundle(bundle: String) = findBundle(bundle).get()
|
||||
|
||||
private fun VersionCatalog.getPlugin(plugin: String) = findPlugin(plugin).get()
|
||||
42
plugins/src/main/kotlin/extension/locales.kt
Normal file
42
plugins/src/main/kotlin/extension/locales.kt
Normal file
@@ -0,0 +1,42 @@
|
||||
// File generated by importSupportedLocalesFromLocalazy.py, do not edit
|
||||
|
||||
package extension
|
||||
|
||||
val locales = setOf(
|
||||
"be",
|
||||
"bg",
|
||||
"cs",
|
||||
"cy",
|
||||
"da",
|
||||
"de",
|
||||
"el",
|
||||
"en",
|
||||
"en-rUS",
|
||||
"es",
|
||||
"et",
|
||||
"eu",
|
||||
"fa",
|
||||
"fi",
|
||||
"fr",
|
||||
"hu",
|
||||
"in",
|
||||
"it",
|
||||
"ka",
|
||||
"ko",
|
||||
"lt",
|
||||
"nb",
|
||||
"nl",
|
||||
"pl",
|
||||
"pt",
|
||||
"pt-rBR",
|
||||
"ro",
|
||||
"ru",
|
||||
"sk",
|
||||
"sv",
|
||||
"tr",
|
||||
"uk",
|
||||
"ur",
|
||||
"uz",
|
||||
"zh-rCN",
|
||||
"zh-rTW",
|
||||
)
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This will generate the plugin "io.element.android-compose-application" to use by app
|
||||
*/
|
||||
import extension.androidConfig
|
||||
import extension.commonDependencies
|
||||
import extension.composeConfig
|
||||
import extension.composeDependencies
|
||||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
|
||||
val libs = the<LibrariesForLibs>()
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
id("com.autonomousapps.dependency-analysis")
|
||||
id("org.jetbrains.kotlin.plugin.compose")
|
||||
}
|
||||
|
||||
android {
|
||||
androidConfig(project)
|
||||
composeConfig()
|
||||
compileOptions {
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain {
|
||||
languageVersion = Versions.javaLanguageVersion
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
commonDependencies(libs)
|
||||
composeDependencies(libs)
|
||||
coreLibraryDesugaring(libs.android.desugar)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This will generate the plugin "io.element.android-compose-library", used in android library with compose modules.
|
||||
*/
|
||||
import extension.androidConfig
|
||||
import extension.commonDependencies
|
||||
import extension.composeConfig
|
||||
import extension.composeDependencies
|
||||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
|
||||
val libs = the<LibrariesForLibs>()
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("kotlin-android")
|
||||
id("com.autonomousapps.dependency-analysis")
|
||||
id("org.jetbrains.kotlin.plugin.compose")
|
||||
}
|
||||
|
||||
android {
|
||||
androidConfig(project)
|
||||
composeConfig()
|
||||
compileOptions {
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain {
|
||||
languageVersion = Versions.javaLanguageVersion
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
commonDependencies(libs)
|
||||
composeDependencies(libs)
|
||||
coreLibraryDesugaring(libs.android.desugar)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This will generate the plugin "io.element.android-library", used in android library without compose modules.
|
||||
*/
|
||||
import extension.androidConfig
|
||||
import extension.commonDependencies
|
||||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
|
||||
val libs = the<LibrariesForLibs>()
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("kotlin-android")
|
||||
id("com.autonomousapps.dependency-analysis")
|
||||
}
|
||||
|
||||
android {
|
||||
androidConfig(project)
|
||||
compileOptions {
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain {
|
||||
languageVersion = Versions.javaLanguageVersion
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
commonDependencies(libs)
|
||||
coreLibraryDesugaring(libs.android.desugar)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import extension.applyKoverPluginToAllSubProjects
|
||||
|
||||
plugins {
|
||||
id("org.jetbrains.kotlinx.kover") apply false
|
||||
}
|
||||
|
||||
applyKoverPluginToAllSubProjects()
|
||||
Reference in New Issue
Block a user