From 555fc2bb082572350e2e1a6487dacb23a40bdf38 Mon Sep 17 00:00:00 2001 From: Mark Philips Date: Thu, 12 Feb 2026 22:07:32 -0500 Subject: [PATCH 1/4] Gradle 9 update and minor enhancements. --- app/build.gradle.kts | 52 ++++++++-------- .../presentation/ui/DeviceConfiguration.kt | 52 ++++++++++------ .../core/presentation/ui/ObserveAsEvents.kt | 4 +- gradle.properties | 6 +- gradle/libs.versions.toml | 59 ++++++++++--------- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle.kts | 3 + 7 files changed, 104 insertions(+), 74 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b4f8553..990dd3b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -4,7 +4,6 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.detekt) alias(libs.plugins.junit5) - alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.ksp) @@ -12,9 +11,6 @@ plugins { } android { - namespace = libs.versions.project.application.id.get() - compileSdk = libs.versions.project.compile.sdk.version.get().toInt() - buildFeatures { buildConfig = true compose = true @@ -48,6 +44,11 @@ android { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } + compileSdk { + version = release(libs.versions.project.compile.sdk.version.get().toInt()) { + minorApiLevel = 1 + } + } defaultConfig { applicationId = libs.versions.project.application.id.get() minSdk = libs.versions.project.min.sdk.version.get().toInt() @@ -57,36 +58,39 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } - detekt { - toolVersion = libs.versions.detekt.get() - config.setFrom(file("../config/detekt/detekt.yml")) - buildUponDefaultConfig = true - autoCorrect = true - } - kotlin { - compilerOptions { - optIn.add("kotlin.RequiresOptIn") - jvmTarget.set(JvmTarget.JVM_17) - } - } - room { - schemaDirectory(path = "$projectDir/schemas") - } - tasks.withType { - useJUnitPlatform() + namespace = libs.versions.project.application.id.get() +} +detekt { + toolVersion = libs.versions.detekt.get() + config.setFrom(file("../config/detekt/detekt.yml")) + buildUponDefaultConfig = true + autoCorrect = true +} +kotlin { + compilerOptions { + optIn.add("kotlin.RequiresOptIn") + jvmTarget.set(JvmTarget.JVM_17) } } +room { + schemaDirectory(path = "$projectDir/schemas") +} +tasks.withType { + useJUnitPlatform() +} dependencies { //region AndroidX Libraries - implementation(libs.annotation) - implementation(libs.appcompat) + implementation(libs.androidx.concurrent.futures) + implementation(libs.androidx.concurrent.futures.ktx) implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.splashscreen) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.navigation.compose) implementation(libs.androidx.security.crypto.ktx) implementation(libs.androidx.work) + implementation(libs.annotation) + implementation(libs.appcompat) implementation(libs.bundles.glance) implementation(libs.material) implementation(libs.room.runtime) @@ -102,7 +106,7 @@ dependencies { //region 3rd Party Libraries coreLibraryDesugaring(libs.desugar.jdk.libs) - detektPlugins(libs.detekt.compose) + //detektPlugins(libs.detekt.compose) implementation(libs.coil.compose) implementation(libs.bundles.koin) implementation(libs.bundles.koin.compose) diff --git a/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/ui/DeviceConfiguration.kt b/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/ui/DeviceConfiguration.kt index 587f5c2..690e0b5 100644 --- a/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/ui/DeviceConfiguration.kt +++ b/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/ui/DeviceConfiguration.kt @@ -1,8 +1,23 @@ +@file:Suppress("MaxLineLength") + package com.codermp.composeandroidtemplate.core.presentation.ui -import androidx.window.core.layout.WindowHeightSizeClass +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.runtime.Composable import androidx.window.core.layout.WindowSizeClass -import androidx.window.core.layout.WindowWidthSizeClass +import androidx.window.core.layout.WindowSizeClass.Companion.HEIGHT_DP_EXPANDED_LOWER_BOUND +import androidx.window.core.layout.WindowSizeClass.Companion.HEIGHT_DP_MEDIUM_LOWER_BOUND +import androidx.window.core.layout.WindowSizeClass.Companion.WIDTH_DP_EXPANDED_LOWER_BOUND +import androidx.window.core.layout.WindowSizeClass.Companion.WIDTH_DP_MEDIUM_LOWER_BOUND + +/** + * Composable function that returns the current device configuration. + */ +@Composable +fun currentDeviceConfiguration(): DeviceConfiguration { + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + return DeviceConfiguration.fromWindowSizeClass(windowSizeClass = windowSizeClass) +} /** * Represents the configuration of the device based on the window size class. @@ -17,6 +32,12 @@ enum class DeviceConfiguration { TABLET_LANDSCAPE, DESKTOP; + val isMobile: Boolean + get() = this in listOf(MOBILE_PORTRAIT, MOBILE_LANDSCAPE) + + val isWideScreen: Boolean + get() = this in listOf(TABLET_LANDSCAPE, DESKTOP) + companion object { /** * Function that returns the appropriate [DeviceConfiguration] based on the provided [windowSizeClass]. @@ -24,21 +45,18 @@ enum class DeviceConfiguration { * @return The corresponding [DeviceConfiguration] based on the window size class. */ fun fromWindowSizeClass(windowSizeClass: WindowSizeClass): DeviceConfiguration { - val widthClass = windowSizeClass.windowWidthSizeClass - val heightClass = windowSizeClass.windowHeightSizeClass - - return when { - widthClass == WindowWidthSizeClass.COMPACT && - heightClass == WindowHeightSizeClass.MEDIUM -> MOBILE_PORTRAIT - widthClass == WindowWidthSizeClass.COMPACT && - heightClass == WindowHeightSizeClass.EXPANDED -> MOBILE_PORTRAIT - widthClass == WindowWidthSizeClass.EXPANDED && - heightClass == WindowHeightSizeClass.COMPACT -> MOBILE_LANDSCAPE - widthClass == WindowWidthSizeClass.MEDIUM && - heightClass == WindowHeightSizeClass.EXPANDED -> TABLET_PORTRAIT - widthClass == WindowWidthSizeClass.EXPANDED && - heightClass == WindowHeightSizeClass.MEDIUM -> TABLET_LANDSCAPE - else -> DESKTOP + return with(receiver = windowSizeClass) { + when { + minWidthDp < WIDTH_DP_MEDIUM_LOWER_BOUND && + minHeightDp >= HEIGHT_DP_MEDIUM_LOWER_BOUND -> MOBILE_PORTRAIT + minWidthDp >= WIDTH_DP_MEDIUM_LOWER_BOUND && + minHeightDp < HEIGHT_DP_MEDIUM_LOWER_BOUND -> MOBILE_LANDSCAPE + minWidthDp in WIDTH_DP_MEDIUM_LOWER_BOUND..WIDTH_DP_EXPANDED_LOWER_BOUND && + minHeightDp >= HEIGHT_DP_MEDIUM_LOWER_BOUND -> TABLET_PORTRAIT + minWidthDp >= WIDTH_DP_EXPANDED_LOWER_BOUND && + minHeightDp in HEIGHT_DP_MEDIUM_LOWER_BOUND..HEIGHT_DP_EXPANDED_LOWER_BOUND -> TABLET_LANDSCAPE + else -> DESKTOP + } } } } diff --git a/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/ui/ObserveAsEvents.kt b/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/ui/ObserveAsEvents.kt index 76dad24..9bef0f7 100644 --- a/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/ui/ObserveAsEvents.kt +++ b/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/ui/ObserveAsEvents.kt @@ -14,14 +14,14 @@ import kotlinx.coroutines.withContext * @param flow The [Flow] to observe. * @param key1 The first key to use for the [LaunchedEffect]. * @param key2 The second key to use for the [LaunchedEffect]. - * @param onEvent The function to call when a new event is emitted. + * @param onEvent The suspend function to call when a new event is emitted. */ @Composable fun ObserveAsEvents( flow: Flow, key1: Any? = null, key2: Any? = null, - onEvent: (T) -> Unit + onEvent: suspend (T) -> Unit ) { val lifecycleOwner = LocalLifecycleOwner.current diff --git a/gradle.properties b/gradle.properties index c7b597b..a5b8b33 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,4 +23,8 @@ kotlin.code.style=official android.nonTransitiveRClass=true org.gradle.parallel=true org.gradle.caching=true -org.gradle.configureondemand=true \ No newline at end of file +org.gradle.configureondemand=true +android.uniquePackageNames=false +android.dependency.useConstraints=true +android.r8.strictFullModeForKeepRules=false +android.generateSyncIssueWhenLibraryConstraintsAreEnabled=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 602e5c2..71efde9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,46 +1,46 @@ [versions] -activity-compose = "1.10.1" -agp = "8.12.1" +activity-compose = "1.12.4" +agp = "9.0.0" annotation = "1.9.1" appcompat = "1.7.1" assert-k = "0.28.1" -bson = "5.5.1" +bson = "5.6.3" coil-compose = "2.7.0" -compose-bom = "2025.08.00" -compose-ui-test-manifest = "1.9.0" +compose-bom = "2026.02.00" +compose-ui-test-manifest = "1.10.3" +concurrent-futures = "1.3.0" core-ktx = "1.17.0" -core-splashscreen = "1.0.1" +core-splashscreen = "1.2.0" coroutines = "1.10.2" coroutines-test = "1.10.2" desugar-jdk-libs = "2.1.5" -detekt = "1.23.8" -detektCompose = "0.4.27" +detekt = "2.0.0-alpha.2" espresso-core = "3.7.0" glance = "1.1.1" junit = "4.13.2" -junit5 = "5.13.4" -junit5-compose = "1.8.0" -junit5-plugin = "1.13.1.0" +junit5 = "6.0.2" +junit5-compose = "2.0.1" +junit5-plugin = "2.0.1" junit-version = "1.3.0" -koin = "4.1.0" -kotlin = "2.2.10" -kotlinx-serialization = "1.9.0" -ksp = "2.2.10-2.0.2" -ktor = "3.2.3" -ktor-client-logging = "3.2.3" -lifecycle-runtime-ktx = "2.9.2" -material = "1.12.0" -material3 = "1.5.0-alpha02" -material-adaptive = "1.1.0" +koin = "4.1.1" +kotlin = "2.3.10" +kotlinx-serialization = "1.10.0" +ksp = "2.3.4" +ktor = "3.4.0" +ktor-client-logging = "3.4.0" +lifecycle-runtime-ktx = "2.10.0" +material = "1.13.0" +material3 = "1.5.0-alpha14" +material-adaptive = "1.2.0" material-icons-extended = "1.7.8" -mock-k = "1.14.5" -navigation-compose = "2.9.3" -org-jetbrains-kotlin-jvm = "2.2.10" -room = "2.7.2" +mock-k = "1.14.9" +navigation-compose = "2.9.7" +org-jetbrains-kotlin-jvm = "2.3.10" +room = "2.8.4" security-crypto-ktx = "1.1.0" timber = "5.0.1" turbine = "1.2.1" -work = "2.10.3" +work = "2.11.1" # Project Versions project-application-id = "com.codermp.composeandroidtemplate" @@ -57,6 +57,8 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a material = { group = "com.google.android.material", name = "material", version.ref = "material" } # AndroidX Libraries +androidx-concurrent-futures = { module = "androidx.concurrent:concurrent-futures", version.ref = "concurrent-futures" } +androidx-concurrent-futures-ktx = { module = "androidx.concurrent:concurrent-futures-ktx", version.ref = "concurrent-futures" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "core-splashscreen" } androidx-glance-appwidget = { module = "androidx.glance:glance-appwidget", version.ref = "glance" } @@ -83,7 +85,6 @@ androidx-material-icons-extended = { module = "androidx.compose.material:materia # 3rd Party Libraries coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil-compose" } desugar-jdk-libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar-jdk-libs" } -detekt-compose = { group = "io.nlopez.compose.rules", name = "detekt", version.ref = "detektCompose"} koin-android-workmanager = { group = "io.insert-koin", name = "koin-androidx-workmanager", version.ref = "koin" } koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } @@ -122,9 +123,9 @@ turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } -detekt = { id = "io.gitlab.arturbosch.detekt", version.ref= "detekt" } +detekt = { id = "dev.detekt", version.ref= "detekt" } junit5 = { id = "de.mannodermaus.android-junit5", version.ref = "junit5-plugin" } -kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version = "2.3.10" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f6d023c..218bddc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Jul 25 14:39:22 EDT 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle.kts b/settings.gradle.kts index ea17a8f..34cfd92 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,9 @@ pluginManagement { gradlePluginPortal() } } +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { From d7c33accebee54e1f57bf97cde50dc8da4d77d1b Mon Sep 17 00:00:00 2001 From: Mark Philips Date: Fri, 13 Feb 2026 16:07:07 -0500 Subject: [PATCH 2/4] Updated Detekt configuration to v2.0.0 --- app/build.gradle.kts | 17 ++++++++++++++--- .../presentation/designsystem/theme/Color.kt | 2 ++ gradle/libs.versions.toml | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 990dd3b..c62f519 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,4 @@ +import dev.detekt.gradle.Detekt import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { @@ -75,9 +76,6 @@ kotlin { room { schemaDirectory(path = "$projectDir/schemas") } -tasks.withType { - useJUnitPlatform() -} dependencies { //region AndroidX Libraries @@ -148,4 +146,17 @@ dependencies { androidTestImplementation(libs.mockk.android) androidTestImplementation(libs.turbine) //endregion +} + +tasks.withType { + useJUnitPlatform() +} + +tasks.withType().configureEach { + reports { + checkstyle.required.set(true) + html.required.set(true) + sarif.required.set(true) + markdown.required.set(true) + } } \ No newline at end of file diff --git a/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/designsystem/theme/Color.kt b/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/designsystem/theme/Color.kt index b25471a..bf7240d 100644 --- a/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/designsystem/theme/Color.kt +++ b/app/src/main/java/com/codermp/composeandroidtemplate/core/presentation/designsystem/theme/Color.kt @@ -1,3 +1,5 @@ +@file:Suppress("MagicNumber") + package com.codermp.composeandroidtemplate.core.presentation.designsystem.theme import androidx.compose.ui.graphics.Color diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 71efde9..3971eb7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -125,7 +125,7 @@ android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } detekt = { id = "dev.detekt", version.ref= "detekt" } junit5 = { id = "de.mannodermaus.android-junit5", version.ref = "junit5-plugin" } -kotlin-android = { id = "org.jetbrains.kotlin.android", version = "2.3.10" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } From 96d8ed79ac5450ee269fa727e2dcd753f35fd0fa Mon Sep 17 00:00:00 2001 From: Mark Philips Date: Fri, 13 Feb 2026 16:09:08 -0500 Subject: [PATCH 3/4] Updated Detekt configuration to v2.0.0 --- config/detekt/detekt.yml | 255 +++++++++++++++++++-------------------- 1 file changed, 124 insertions(+), 131 deletions(-) diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index d398450..b9482aa 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -1,18 +1,9 @@ -build: - maxIssues: 0 - excludeCorrectable: false - weights: - # complexity: 2 - # LongParameterList: 1 - # style: 1 - # comments: 1 - config: validation: true warningsAsErrors: false checkExhaustiveness: false - # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' - excludes: '' + # when writing own rules with new properties, exclude the property path e.g.: ['my_rule_set', '.*>.*>[my_property]'] + excludes: [] processors: active: true @@ -37,30 +28,21 @@ console-reports: - 'ProjectStatisticsReport' - 'ComplexityReport' - 'NotificationReport' - - 'FindingsReport' - - 'FileBasedFindingsReport' - # - 'LiteFindingsReport' - -output-reports: - active: true - exclude: - # - 'TxtOutputReport' - # - 'XmlOutputReport' - # - 'HtmlOutputReport' - # - 'MdOutputReport' - # - 'SarifOutputReport' + - 'IssuesReport' + - 'FileBasedIssuesReport' + # - 'LiteIssuesReport' comments: active: true AbsentOrWrongFileLicense: active: false - licenseTemplateFile: 'license.template' licenseTemplateIsRegex: false - CommentOverPrivateFunction: + licenseTemplate: '' + DeprecatedBlockTag: active: false - CommentOverPrivateProperty: + DocumentationOverPrivateFunction: active: false - DeprecatedBlockTag: + DocumentationOverPrivateProperty: active: false EndOfSentenceFormat: active: false @@ -90,27 +72,29 @@ comments: active: false excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] searchProtectedProperty: false + ignoreEnumEntries: false complexity: active: true CognitiveComplexMethod: active: false - threshold: 15 + allowedComplexity: 15 ComplexCondition: active: true - threshold: 4 + allowedConditions: 3 ComplexInterface: active: false - threshold: 10 + allowedDefinitions: 10 includeStaticDeclarations: false includePrivateDeclarations: false ignoreOverloaded: false CyclomaticComplexMethod: active: true - threshold: 15 + allowedComplexity: 14 ignoreSingleWhenExpression: false ignoreSimpleWhenEntries: false ignoreNestingFunctions: false + ignoreLocalFunctions: false nestingFunctions: - 'also' - 'apply' @@ -126,30 +110,31 @@ complexity: ignoredLabels: [] LargeClass: active: true - threshold: 600 + allowedLines: 600 LongMethod: active: true - threshold: 60 + allowedLines: 60 LongParameterList: active: true - functionThreshold: 6 - constructorThreshold: 7 + allowedFunctionParameters: 5 + allowedConstructorParameters: 6 ignoreDefaultParameters: false ignoreDataClasses: true ignoreAnnotatedParameter: [] MethodOverloading: active: false - threshold: 6 + allowedOverloads: 6 NamedArguments: active: false - threshold: 3 + allowedArguments: 3 + ignoreMethods: [] ignoreArgumentsMatchingNames: false NestedBlockDepth: active: true - threshold: 4 + allowedDepth: 4 NestedScopeFunctions: active: false - threshold: 1 + allowedDepth: 1 functions: - 'kotlin.apply' - 'kotlin.run' @@ -161,25 +146,28 @@ complexity: StringLiteralDuplication: active: false excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] - threshold: 3 + allowedDuplications: 2 ignoreAnnotation: true - excludeStringsWithLessThan5Characters: true + allowedWithLengthLessThan: 5 ignoreStringsRegex: '$^' TooManyFunctions: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] - thresholdInFiles: 11 - thresholdInClasses: 11 - thresholdInInterfaces: 11 - thresholdInObjects: 11 - thresholdInEnums: 11 + allowedFunctionsPerFile: 11 + allowedFunctionsPerClass: 11 + allowedFunctionsPerInterface: 11 + allowedFunctionsPerObject: 11 + allowedFunctionsPerEnum: 11 ignoreDeprecated: false ignorePrivate: false + ignoreInternal: false ignoreOverridden: false ignoreAnnotatedFunctions: [] coroutines: active: true + CoroutineLaunchedInTestWithoutRunTest: + active: false GlobalCoroutineUsage: active: false InjectDispatcher: @@ -192,10 +180,13 @@ coroutines: active: true SleepInsteadOfDelay: active: true + SuspendFunInFinallySection: + active: false SuspendFunSwallowedCancellation: active: false SuspendFunWithCoroutineScopeReceiver: active: false + aliases: ['SuspendFunctionOnCoroutineScope'] SuspendFunWithFlowReturnType: active: true @@ -223,7 +214,7 @@ empty-blocks: active: true EmptyInitBlock: active: true - EmptyKtFile: + EmptyKotlinFile: active: true EmptySecondaryConstructor: active: true @@ -236,6 +227,8 @@ empty-blocks: exceptions: active: true + ErrorUsageWithThrowable: + active: false ExceptionRaisedInUnexpectedLocation: active: true methodNames: @@ -312,6 +305,7 @@ naming: allowedPattern: '^(is|has|are)' ClassNaming: active: true + aliases: ['ClassName'] classPattern: '[A-Z][a-zA-Z0-9]*' ConstructorParameterNaming: active: true @@ -320,18 +314,22 @@ naming: excludeClassPattern: '$^' EnumNaming: active: true + aliases: ['EnumEntryName'] enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' ForbiddenClassName: active: false forbiddenName: [] - FunctionMaxLength: + FunctionNameMaxLength: active: false + aliases: ['FunctionMaxNameLength'] maximumFunctionNameLength: 30 - FunctionMinLength: + FunctionNameMinLength: active: false + aliases: ['FunctionMinNameLength'] minimumFunctionNameLength: 3 FunctionNaming: active: true + aliases: ['FunctionName'] excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] functionPattern: '[a-z][a-zA-Z0-9]*|[A-Z][a-zA-Z0-9]*' excludeClassPattern: '$^' @@ -341,6 +339,7 @@ naming: excludeClassPattern: '$^' InvalidPackageDeclaration: active: true + aliases: ['PackageDirectoryMismatch'] rootPackage: '' requireRootInDeclaration: false LambdaParameterNaming: @@ -369,11 +368,13 @@ naming: active: false ObjectPropertyNaming: active: true + aliases: ['ObjectPropertyName'] constantPattern: '[A-Za-z][_A-Za-z0-9]*' propertyPattern: '[A-Za-z][_A-Za-z0-9]*' privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' PackageNaming: active: true + aliases: ['PackageName'] packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' TopLevelPropertyNaming: active: true @@ -388,6 +389,7 @@ naming: minimumVariableNameLength: 1 VariableNaming: active: true + aliases: ['PropertyName'] variablePattern: '[a-z][A-Za-z0-9]*' privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' excludeClassPattern: '$^' @@ -398,17 +400,21 @@ performance: active: true CouldBeSequence: active: false - threshold: 3 + allowedOperations: 2 ForEachOnRange: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] SpreadOperator: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + UnnecessaryInitOnArray: + active: false UnnecessaryPartOfBinaryExpression: active: false UnnecessaryTemporaryInstantiation: active: true + UnnecessaryTypeCasting: + active: false potential-bugs: active: true @@ -418,14 +424,20 @@ potential-bugs: - 'kotlin.String' CastNullableToNonNullableType: active: false + ignorePlatformTypes: true CastToNullableType: active: false + CharArrayToStringCall: + active: false Deprecation: active: false + aliases: ['DEPRECATION'] + excludeImportStatements: false DontDowncastCollectionTypes: active: false DoubleMutabilityForCollection: active: true + aliases: ['DoubleMutability'] mutableTypes: - 'kotlin.collections.MutableList' - 'kotlin.collections.MutableMap' @@ -460,6 +472,7 @@ potential-bugs: - 'CanIgnoreReturnValue' - '*.CanIgnoreReturnValue' returnValueTypes: + - 'kotlin.Function*' - 'kotlin.sequences.Sequence' - 'kotlinx.coroutines.flow.*Flow' - 'java.util.stream.*Stream' @@ -484,6 +497,13 @@ potential-bugs: MissingPackageDeclaration: active: false excludes: ['**/*.kts'] + MissingSuperCall: + active: false + mustInvokeSuperAnnotations: + - 'androidx.annotation.CallSuper' + - 'javax.annotation.OverridingMethodsMustInvokeSuper' + MissingUseCall: + active: false NullCheckOnMutableProperty: active: false NullableToStringCall: @@ -492,6 +512,12 @@ potential-bugs: active: false UnconditionalJumpStatementInLoop: active: false + UnnamedParameterUse: + active: false + allowAdjacentDifferentTypeParams: true + allowSingleParamUse: true + ignoreArgumentsMatchingNames: true + ignoreFunctionCall: [] UnnecessaryNotNullCheck: active: false UnnecessaryNotNullOperator: @@ -507,6 +533,7 @@ potential-bugs: excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] UnsafeCast: active: true + aliases: ['UNCHECKED_CAST'] UnusedUnaryOperator: active: true UselessPostfixExpression: @@ -516,6 +543,10 @@ potential-bugs: style: active: true + AbstractClassCanBeConcreteClass: + active: true + AbstractClassCanBeInterface: + active: true AlsoCouldBeApply: active: false BracesOnIfStatements: @@ -545,6 +576,8 @@ style: DestructuringDeclarationWithTooManyEntries: active: true maxDestructuringEntries: 3 + DoubleNegativeExpression: + active: false DoubleNegativeLambda: active: false negativeFunctions: @@ -561,6 +594,8 @@ style: active: false ExplicitCollectionElementAccessMethod: active: false + ExplicitItLambdaMultipleParameters: + active: true ExplicitItLambdaParameter: active: true ExpressionBodySyntax: @@ -595,8 +630,8 @@ style: allowedPatterns: '' ForbiddenImport: active: false - imports: [] - forbiddenPatterns: '' + forbiddenImports: [] + allowedImports: [] ForbiddenMethodCall: active: false methods: @@ -604,6 +639,18 @@ style: value: 'kotlin.io.print' - reason: 'println does not allow you to configure the output stream. Use a logger instead.' value: 'kotlin.io.println' + - reason: 'using `BigDecimal(Double)` can result in unexpected floating point precision behavior. Use `BigDecimal.valueOf(Double)` or `String.toBigDecimalOrNull()` instead.' + value: 'java.math.BigDecimal.(kotlin.Double)' + - reason: 'using `BigDecimal(String)` can result in a `NumberFormatException`. Use `String.toBigDecimalOrNull()`' + value: 'java.math.BigDecimal.(kotlin.String)' + - reason: 'It is marked as obsolete. Use `kotlin.time.measureTime` instead.' + value: 'kotlin.system.measureTimeMillis' + ForbiddenNamedParam: + active: false + methods: [] + ForbiddenOptIn: + active: false + markerClasses: [] ForbiddenSuppress: active: false rules: [] @@ -621,7 +668,7 @@ style: maxJumpCount: 1 MagicNumber: active: true - excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts', '**/Color.kt'] + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts'] ignoreNumbers: - '-1' - '0' @@ -649,7 +696,7 @@ style: excludeImportStatements: true excludeCommentStatements: false excludeRawStrings: true - MayBeConst: + MayBeConstant: active: true ModifierOrder: active: true @@ -675,15 +722,17 @@ style: active: true OptionalUnit: active: false - PreferToOverPairSyntax: - active: false ProtectedMemberInFinalClass: active: true + RangeUntilInsteadOfRangeTo: + active: false + RedundantConstructorKeyword: + active: false RedundantExplicitType: active: false RedundantHigherOrderMapUsage: active: true - RedundantVisibilityModifierRule: + RedundantVisibilityModifier: active: false ReturnCount: active: true @@ -697,7 +746,7 @@ style: active: true SerialVersionUIDInSerializableClass: active: true - SpacingBetweenPackageAndImports: + SpacingAfterPackageDeclaration: active: false StringShouldBeRawString: active: false @@ -718,9 +767,7 @@ style: active: false acceptableLength: 4 allowNonStandardGrouping: false - UnnecessaryAbstractClass: - active: true - UnnecessaryAnnotationUseSiteTarget: + UnnecessaryAny: active: false UnnecessaryApply: active: true @@ -730,6 +777,8 @@ style: active: false UnnecessaryFilter: active: true + UnnecessaryFullyQualifiedName: + active: false UnnecessaryInheritance: active: true UnnecessaryInnerClass: @@ -739,21 +788,30 @@ style: UnnecessaryParentheses: active: false allowForUnclearPrecedence: false - UntilInsteadOfRangeTo: + UnnecessaryReversed: active: false - UnusedImports: + UnusedImport: active: false + additionalOperatorSet: [] UnusedParameter: active: true + aliases: ['UNUSED_PARAMETER', 'unused'] allowedNames: 'ignored|expected' UnusedPrivateClass: active: true - UnusedPrivateMember: + aliases: ['unused'] + UnusedPrivateFunction: active: true + aliases: ['unused'] allowedNames: '' UnusedPrivateProperty: active: true - allowedNames: '_|ignored|expected|serialVersionUID' + aliases: ['unused'] + allowedNames: 'ignored|expected|serialVersionUID' + UnusedVariable: + active: true + aliases: ['UNUSED_VARIABLE', 'unused'] + allowedNames: 'ignored|_' UseAnyOrNoneInsteadOfFind: active: true UseArrayLiteralsInAnnotations: @@ -790,74 +848,9 @@ style: active: true VarCouldBeVal: active: true + aliases: ['CanBeVal'] ignoreLateinitVar: false WildcardImport: active: true excludeImports: - 'java.util.*' - -Compose: - ComposableAnnotationNaming: - active: true - ComposableNaming: - active: true - ComposableParamOrder: - active: true - CompositionLocalAllowlist: - active: true - CompositionLocalNaming: - active: true - ContentEmitterReturningValues: - active: true - ContentSlotReused: - active: true - ContentTrailingLambda: - active: true - DefaultsVisibility: - active: true - LambdaParameterEventTrailing: - active: true - LambdaParameterInRestartableEffect: - active: true - Material2: - active: false - ModifierClickableOrder: - active: true - ModifierComposed: - active: true - ModifierMissing: - active: true - ModifierNaming: - active: true - ModifierNotUsedAtRoot: - active: true - ModifierReused: - active: true - ModifierWithoutDefault: - active: true - MultipleEmitters: - active: true - MutableParams: - active: true - MutableStateAutoboxing: - active: true - MutableStateParam: - active: true - ParameterNaming: - active: true - PreviewAnnotationNaming: - active: true - PreviewNaming: - active: false - PreviewPublic: - active: true - RememberContentMissing: - active: true - RememberMissing: - active: true - UnstableCollections: - active: false - ViewModelForwarding: - active: true - ViewModelInjection: - active: true From 93aa38106e9a811fd67f68922def5ed08ac6d21f Mon Sep 17 00:00:00 2001 From: Mark Philips Date: Fri, 13 Feb 2026 16:10:52 -0500 Subject: [PATCH 4/4] Minor cleanup in app/build.gradle.kts --- app/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c62f519..859c59e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -104,7 +104,6 @@ dependencies { //region 3rd Party Libraries coreLibraryDesugaring(libs.desugar.jdk.libs) - //detektPlugins(libs.detekt.compose) implementation(libs.coil.compose) implementation(libs.bundles.koin) implementation(libs.bundles.koin.compose)