diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 6c87484..e262dba 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -36,7 +36,7 @@ jobs: needs: generate_version uses: futuredapp/.github/.github/workflows/android-cloud-nightly-build.yml@2.0.0 with: - TEST_GRADLE_TASKS: testDevEnterpriseUnitTest + TEST_GRADLE_TASKS: testDevDebugUnitTest PACKAGE_GRADLE_TASK: packageDevEnterpriseUniversalApk UPLOAD_GRADLE_TASK: appDistributionUploadDevEnterprise # TODO Verify app distribution groups diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 1f7b94f..3cfad11 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -11,7 +11,7 @@ jobs: uses: futuredapp/.github/.github/workflows/android-cloud-check.yml@2.0.0 with: LINT_GRADLE_TASKS: lintCheck - TEST_GRADLE_TASKS: testDevEnterpriseUnitTest + TEST_GRADLE_TASKS: testDevDebugUnitTest secrets: # TODO Set up `GRADLE_CACHE_ENCRYPTION_KEY` for this GitHub repository GRADLE_CACHE_ENCRYPTION_KEY: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c7366ee --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,133 @@ +# CLAUDE.md + +This file provides guidance to Claude Code when working with code in this repository. + +## Common Commands + +- `./gradlew lintCheck` - Run ktlint and detekt checks (same as CI) +- `./gradlew ktlintFormat` - Automatically fix code style issues +- `./gradlew test` - Run unit tests +- `./gradlew clean` - Remove all build artifacts + +## Module Structure + +Single-module project with the main app under `:app`. Build logic lives in `buildSrc/` and `convention-plugins/`. + +## Architecture + +**MVVM** with [Arkitekt](https://github.com/futuredapp/arkitekt) library: + +1. **ViewModel** (`*ViewModel.kt`) - extends `BaseViewModel`, implements `Actions` interface from the screen +2. **ViewState** (`*ViewState.kt`) - holds mutable Compose state (`var counter by mutableIntStateOf(0)`) +3. **Events** (`*Events.kt`) - sealed class of one-time events (navigation, toasts); collected via `EventsEffect` +4. **Screen** (`*Screen.kt`) - Composable; receives `viewState`, collects events, delegates interactions to `Actions` + +Actions are defined as a nested interface inside the Screen object: +```kotlin +object HomeScreen { + interface Actions { + fun onIncrementCounter() + fun onNavigateToDetail() + } +} +``` + +## Arkitekt API Reference + +### `BaseCoreViewModel` +- `abstract val viewState: VS` — injected ViewState +- `sendEvent(event: Event)` — sends a one-time event to the UI layer + +### `BaseViewModel` (extends `BaseCoreViewModel`, implements `CoroutineScopeOwner`) +- Provides `coroutineScope` backed by `viewModelScope` +- Inherits all `CoroutineScopeOwner` extension functions below + +### Use cases +Always extend the Arkitekt base classes — never use plain `suspend` functions with `invoke()`: + +```kotlin +// UseCase — single async operation +class SignInUseCase @Inject constructor(...) : UseCase() { + override suspend fun build(args: Unit) { /* business logic */ } +} + +// FlowUseCase — streaming operation +class ObserveSomethingUseCase @Inject constructor(...) : FlowUseCase() { + override fun build(args: Unit): Flow = /* … */ +} +``` + +### `CoroutineScopeOwner` — use-case execution in ViewModels + +```kotlin +// Async execution with callbacks (preferred; cancels previous by default) +someUseCase.execute { + onStart { /* show loading */ } + onSuccess { value -> sendEvent(MyEvent) } // sendEvent is non-suspend, safe here + onError { throwable -> /* … */ } +} + +// Suspend execution — use inside launchWithHandler for error handling +launchWithHandler { + val result = someUseCase.execute() // returns Result + result.getOrNull() // or getOrThrow(), getOrDefault(), fold(…) +} + +// Flow use case +someFlowUseCase.execute { + onStart { } + onNext { value -> } + onError { throwable -> } + onComplete { } +} +``` + +### `EventsEffect` / `onEvent` +```kotlin +EventsEffect { + onEvent { /* handle */ } +} +``` + +## Dependency Injection + +**Hilt** throughout: +- `@HiltAndroidApp` on `App`, `@AndroidEntryPoint` on `AppActivity` +- `@HiltViewModel` on ViewModels, `@ViewModelScoped` on ViewState +- Modules: `ApplicationModule` (singletons), `NetworkModule` (Retrofit/OkHttp) + +## Build Flavors + +Flavor dimension: `api` with three flavors: +- **mock** - local mock data +- **dev** - development API +- **prod** - production API + +Build types: `debug`, `enterprise` (minified, debug key), `release` (minified, release key). + +## Code Style + +- Max line length: **140 characters** +- Indent: **4 spaces**, trailing commas allowed +- Ktlint code style: `android_studio` +- Detekt config: `config/detekt.yml` + +## Naming Conventions + +- `HomeViewModel`, `HomeViewState`, `HomeEvents`, `HomeScreen` +- Event objects: `NavigateToDetailEvent`, `NavigateBackEvent` +- Action methods: `onIncrementCounter()`, `onNavigateToDetail()` (prefix `on`) +- Composable functions: PascalCase; preview functions: `private fun HomePreview()` + +## Design System + +Material3 via `MaterialTheme`. Colors, typography, shapes, and dimensions defined in `app/src/main/kotlin/.../ui/theme/`. + +Use `Dimensions.kt` tokens for spacing — avoid raw `dp` literals where theme tokens exist. + +## Testing + +- Unit tests: JUnit 4 + MockK +- Instrumented tests: AndroidJUnit4 +- Run unit tests: `./gradlew test` +- Run module tests: `./gradlew :app:test` diff --git a/app/build.gradle.kts b/app/build.gradle.kts index aa27767..8229fa5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,7 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.android.application) - alias(libs.plugins.kotlin.android) alias(libs.plugins.hilt) alias(libs.plugins.ksp) alias(libs.plugins.kotlin.serialization) @@ -26,14 +25,6 @@ android { versionName = ProjectSettings.versionName testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - - javaCompileOptions { - annotationProcessorOptions { - arguments.apply { - put("room.schemaLocation", "$projectDir/schemas") - } - } - } } packaging { @@ -56,15 +47,6 @@ android { targetCompatibility = ProjectSettings.JavaCompatibility } - sourceSets { - getByName("main").java.setSrcDirs(setOf("src/main/kotlin")) - create(ProjectSettings.Flavor.DEV).java.setSrcDirs(setOf("src/dev/kotlin")) - create(ProjectSettings.Flavor.PROD).java.setSrcDirs(setOf("src/prod/kotlin")) - create(ProjectSettings.Flavor.MOCK).java.setSrcDirs(setOf("src/mock/kotlin")) - getByName("test").java.setSrcDirs(setOf("src/test/kotlin")) - getByName("androidTest").java.setSrcDirs(setOf("src/androidTest/kotlin")) - } - signingConfigs { getByName(ProjectSettings.BuildType.DEBUG) { storeFile = rootProject.file("./keystore/debug.jks") @@ -81,26 +63,24 @@ android { } buildTypes { - buildTypes { - getByName(ProjectSettings.BuildType.DEBUG) { - isMinifyEnabled = false - isShrinkResources = false - signingConfig = signingConfigs.getByName(ProjectSettings.BuildType.DEBUG) - } - create(ProjectSettings.BuildType.ENTERPRISE) { - isMinifyEnabled = true - isShrinkResources = true - signingConfig = signingConfigs.getByName(ProjectSettings.BuildType.DEBUG) - proguardFile(getDefaultProguardFile("proguard-android.txt")) - proguardFile(file("proguard-rules.pro")) - } - getByName(ProjectSettings.BuildType.RELEASE) { - isMinifyEnabled = true - isShrinkResources = true - signingConfig = signingConfigs.getByName(ProjectSettings.BuildType.RELEASE) - proguardFile(getDefaultProguardFile("proguard-android.txt")) - proguardFile(file("proguard-rules.pro")) - } + getByName(ProjectSettings.BuildType.DEBUG) { + isMinifyEnabled = false + isShrinkResources = false + signingConfig = signingConfigs.getByName(ProjectSettings.BuildType.DEBUG) + } + create(ProjectSettings.BuildType.ENTERPRISE) { + isMinifyEnabled = true + isShrinkResources = true + signingConfig = signingConfigs.getByName(ProjectSettings.BuildType.DEBUG) + proguardFile(getDefaultProguardFile("proguard-android-optimize.txt")) + proguardFile(file("proguard-rules.pro")) + } + getByName(ProjectSettings.BuildType.RELEASE) { + isMinifyEnabled = true + isShrinkResources = true + signingConfig = signingConfigs.getByName(ProjectSettings.BuildType.RELEASE) + proguardFile(getDefaultProguardFile("proguard-android-optimize.txt")) + proguardFile(file("proguard-rules.pro")) } } @@ -163,10 +143,11 @@ dependencies { implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.runtime) + implementation(libs.androidx.compose.material.icons) debugImplementation(libs.androidx.compose.ui.tooling) - // MVVM - implementation(libs.arkitekt.usecases) + // Arkitekt + implementation(libs.arkitekt.compose) // Hilt implementation(libs.hilt.android) diff --git a/app/src/main/kotlin/app/futured/androidprojecttemplate/tools/arch/BaseViewModel.kt b/app/src/main/kotlin/app/futured/androidprojecttemplate/tools/arch/BaseViewModel.kt deleted file mode 100644 index 4eeadc1..0000000 --- a/app/src/main/kotlin/app/futured/androidprojecttemplate/tools/arch/BaseViewModel.kt +++ /dev/null @@ -1,56 +0,0 @@ -package app.futured.androidprojecttemplate.tools.arch - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import app.futured.arkitekt.core.ViewState -import app.futured.arkitekt.core.event.Event -import app.futured.arkitekt.crusecases.CoroutineScopeOwner -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.coroutines.launch - -abstract class BaseViewModel : - ViewModel(), - CoroutineScopeOwner { - abstract val viewState: VS - - override val coroutineScope: CoroutineScope = viewModelScope - - private val eventChannel = Channel>(Channel.BUFFERED) - val events = eventChannel - .receiveAsFlow() - .flowOn(Dispatchers.Main) - - fun sendEvent(event: Event) = viewModelScope.launch { - eventChannel.send(event) - } -} - -/** - * When [EventsEffect] enters composition, it will start observing the event flow from it's viewModel. - * Each event sent from ViewModel goes through [observer] lambda which can be used to react to a specific event. - * Use the [onEvent] function to filter out the event you are interested in. - * - * @param observer Event receiver lambda. - */ -@Composable -fun BaseViewModel.EventsEffect( - observer: suspend Event.() -> Unit, -) { - LaunchedEffect(this) { - events.collect { - observer(it) - } - } -} - -inline fun > Event<*>.onEvent(action: (E) -> Unit) { - if (this is E) { - action(this) - } -} diff --git a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/_templateScreen/_TEMPLATEScreen.kt b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/_templateScreen/_TEMPLATEScreen.kt index 9a946f6..c884af7 100644 --- a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/_templateScreen/_TEMPLATEScreen.kt +++ b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/_templateScreen/_TEMPLATEScreen.kt @@ -18,13 +18,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.hilt.navigation.compose.hiltViewModel +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import app.futured.androidprojecttemplate.navigation.NavRouter -import app.futured.androidprojecttemplate.tools.arch.BaseViewModel -import app.futured.androidprojecttemplate.tools.arch.EventsEffect -import app.futured.androidprojecttemplate.tools.arch.onEvent import app.futured.androidprojecttemplate.tools.compose.ScreenPreviews import app.futured.androidprojecttemplate.ui.components.Showcase +import app.futured.arkitekt.compose.BaseViewModel +import app.futured.arkitekt.compose.EventsEffect +import app.futured.arkitekt.compose.onEvent import app.futured.arkitekt.core.ViewState import app.futured.arkitekt.core.event.Event import dagger.hilt.android.lifecycle.HiltViewModel diff --git a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/detail/DetailScreen.kt b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/detail/DetailScreen.kt index ce18eeb..12328d7 100644 --- a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/detail/DetailScreen.kt +++ b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/detail/DetailScreen.kt @@ -17,13 +17,13 @@ import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.hilt.navigation.compose.hiltViewModel +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import app.futured.androidprojecttemplate.navigation.NavRouter -import app.futured.androidprojecttemplate.tools.arch.EventsEffect -import app.futured.androidprojecttemplate.tools.arch.onEvent import app.futured.androidprojecttemplate.tools.compose.ScreenPreviews import app.futured.androidprojecttemplate.ui.components.AddFloatingActionButton import app.futured.androidprojecttemplate.ui.components.Showcase +import app.futured.arkitekt.compose.EventsEffect +import app.futured.arkitekt.compose.onEvent @Composable fun DetailScreen( diff --git a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/detail/DetailViewModel.kt b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/detail/DetailViewModel.kt index cf62112..a51a113 100644 --- a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/detail/DetailViewModel.kt +++ b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/detail/DetailViewModel.kt @@ -1,6 +1,6 @@ package app.futured.androidprojecttemplate.ui.screens.detail -import app.futured.androidprojecttemplate.tools.arch.BaseViewModel +import app.futured.arkitekt.compose.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -8,6 +8,7 @@ import javax.inject.Inject class DetailViewModel @Inject constructor(override val viewState: DetailViewState) : BaseViewModel(), Detail.Actions { + override fun onNavigateBack() { sendEvent(NavigateBackEvent) } diff --git a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/home/HomeScreen.kt b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/home/HomeScreen.kt index 392c75e..93f7979 100644 --- a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/home/HomeScreen.kt +++ b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/home/HomeScreen.kt @@ -15,13 +15,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.hilt.navigation.compose.hiltViewModel +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import app.futured.androidprojecttemplate.navigation.NavRouter -import app.futured.androidprojecttemplate.tools.arch.EventsEffect -import app.futured.androidprojecttemplate.tools.arch.onEvent import app.futured.androidprojecttemplate.tools.compose.ScreenPreviews import app.futured.androidprojecttemplate.ui.components.AddFloatingActionButton import app.futured.androidprojecttemplate.ui.components.Showcase +import app.futured.arkitekt.compose.EventsEffect +import app.futured.arkitekt.compose.onEvent @Composable fun HomeScreen( diff --git a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/home/HomeViewModel.kt b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/home/HomeViewModel.kt index 2f6ad21..43dbae6 100644 --- a/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/home/HomeViewModel.kt +++ b/app/src/main/kotlin/app/futured/androidprojecttemplate/ui/screens/home/HomeViewModel.kt @@ -1,6 +1,6 @@ package app.futured.androidprojecttemplate.ui.screens.home -import app.futured.androidprojecttemplate.tools.arch.BaseViewModel +import app.futured.arkitekt.compose.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -8,6 +8,7 @@ import javax.inject.Inject class HomeViewModel @Inject constructor(override val viewState: HomeViewState) : BaseViewModel(), Home.Actions { + override fun onIncrementCounter() { viewState.counter++ } diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml index 506c586..32cfc8b 100644 --- a/app/src/main/res/values-night/styles.xml +++ b/app/src/main/res/values-night/styles.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 06bee7c..4c48330 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,17 +1,10 @@ - + diff --git a/build.gradle.kts b/build.gradle.kts index 7a31ff6..b28e566 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,6 @@ import io.gitlab.arturbosch.detekt.report.ReportMergeTask plugins { alias(libs.plugins.android.application) apply false - alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.hilt) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.ktlint) apply false diff --git a/buildSrc/src/main/kotlin/ProjectSettings.kt b/buildSrc/src/main/kotlin/ProjectSettings.kt index 85541b6..a2a0396 100644 --- a/buildSrc/src/main/kotlin/ProjectSettings.kt +++ b/buildSrc/src/main/kotlin/ProjectSettings.kt @@ -2,8 +2,8 @@ import org.gradle.api.JavaVersion object ProjectSettings { const val applicationId = "app.futured.androidprojecttemplate" - const val compileSdkVersion = 35 - const val targetSdk = 35 + const val compileSdkVersion = 36 + const val targetSdk = 36 const val minSdk = 29 val versionName = System.getenv("ANDROID_VERSION_NAME") ?: "1.0.0" val versionCode = System.getenv("ANDROID_BUILD_NUMBER")?.toIntOrNull() ?: 1 @@ -41,6 +41,4 @@ object ProjectSettings { val KEY_PASSWORD = System.getenv("ANDROID_KEY_PASSWORD") ?: "" val STORE_PASSWORD = System.getenv("ANDROID_KEYSTORE_PASSWORD") ?: "" } - - const val TASK_GROUP = "futured" } diff --git a/buildSrc/src/main/kotlin/app/futured/androidprojecttemplate/DependencyUpdates.kt b/buildSrc/src/main/kotlin/app/futured/androidprojecttemplate/DependencyUpdates.kt index cd9795c..6aa8a9d 100644 --- a/buildSrc/src/main/kotlin/app/futured/androidprojecttemplate/DependencyUpdates.kt +++ b/buildSrc/src/main/kotlin/app/futured/androidprojecttemplate/DependencyUpdates.kt @@ -2,24 +2,32 @@ package app.futured.androidprojecttemplate import ProjectSettings import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask +import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentSelectionWithCurrent +import org.gradle.api.Action @Suppress("UnnecessaryAbstractClass") abstract class DependencyUpdates : DependencyUpdatesTask() { init { - group = ProjectSettings.TASK_GROUP + group = ProjectSettings.Gradle.TaskGroup this.resolutionStrategy { componentSelection { - all { - val rejected = listOf("alpha", "beta", "rc", "cr", "m", "preview", "testing") - .map { qualifier -> Regex("(?i).*[.-]$qualifier[.\\d-]*") } - .any { it.matches(candidate.version) } - if (rejected) { - reject("Release candidate") + all( + Action { + if (isNonStable(candidate.version) && !isNonStable(currentVersion)) { + reject("Release candidate") + } } - } + ) } } } + + fun isNonStable(version: String): Boolean { + val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase().contains(it) } + val regex = "^[0-9,.v-]+(-r)?$".toRegex() + val isStable = stableKeyword || regex.matches(version) + return isStable.not() + } } diff --git a/buildSrc/src/main/kotlin/app/futured/androidprojecttemplate/LintCheck.kt b/buildSrc/src/main/kotlin/app/futured/androidprojecttemplate/LintCheck.kt index 39c5a4b..1b69eed 100644 --- a/buildSrc/src/main/kotlin/app/futured/androidprojecttemplate/LintCheck.kt +++ b/buildSrc/src/main/kotlin/app/futured/androidprojecttemplate/LintCheck.kt @@ -11,7 +11,7 @@ open class LintCheck : DefaultTask() { group = ProjectSettings.Gradle.TaskGroup /* - These tasks runs for each subproject that has applied ktlint or detekt plugins. + These tasks run for each subproject that has applied ktlint or detekt plugins. */ configure { project.subprojects diff --git a/gradle.properties b/gradle.properties index 550b14a..5b48cfc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,6 +9,3 @@ org.gradle.configuration-cache.problems=warn #Kotlin kotlin.code.style=official - -#Android -android.useAndroidX=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 747a7b2..bf7ba73 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,37 +1,37 @@ [versions] -agp = "8.11.0" -gradleVersionsPlugin = "0.50.0" -kotlin = "2.2.0" -ksp = "2.2.0-2.0.2" # Must be compatible with: `kotlin` -androidxComposeBom = "2025.06.01" -hilt = "2.56.2" -arkitekt = "5.2.2" +agp = "9.1.0" +gradleVersionsPlugin = "0.53.0" +kotlin = "2.3.0" +ksp = "2.3.4" +androidxComposeBom = "2026.03.00" +hilt = "2.59.2" +arkitekt = "6.X.X-SNAPSHOT" timber = "5.0.1" testCore = "1.6.1" testRunner = "1.6.2" junit = "1.2.1" mockk = "1.14.4" -serializationJson = "1.8.1" -okhttp = "4.12.0" +serializationJson = "1.10.0" +okhttp = "5.3.2" retrofit = "3.0.0" navigation = "2.9.0" -hiltNavigation = "1.2.0" +hiltNavigation = "1.3.0" composeLint = "1.4.2" -androidx-activity-compose = "1.10.1" +androidx-activity-compose = "1.13.0" jdkDesugaring = "2.1.5" -androidx = "1.16.0" +androidx = "1.18.0" appcompat = "1.7.1" -lifecycle = "2.9.1" -activity = "1.9.0" +lifecycle = "2.10.0" +activity = "1.13.0" detekt = "1.23.8" -ktlintGradle = "12.3.0" +ktlintGradle = "14.2.0" ktlint = "1.6.0" -google-servicesPlugin = "4.4.2" -google-firebaseAppDistributionPlugin = "5.1.1" +google-servicesPlugin = "4.4.4" +google-firebaseAppDistributionPlugin = "5.2.1" sheethappens = "1.0.3" -splash-screen = "1.0.1" -coil = "3.2.0" -datastore = "1.1.7" +splash-screen = "1.2.0" +coil = "3.4.0" +datastore = "1.2.1" [libraries] @@ -43,6 +43,7 @@ androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-toolin androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-compose-runtime = { module = "androidx.compose.runtime:runtime" } +androidx-compose-material-icons = { group = "androidx.compose.material", name = "material-icons-core" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } # https://developer.android.com/studio/write/java8-support#library-desugaring-versions @@ -64,8 +65,8 @@ androidx-splashscreen = { group = "androidx.core", name = "core-splashscreen", v # Serialization serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serializationJson" } -# MVVM -arkitekt-usecases = { group = "app.futured.arkitekt", name = "cr-usecases", version.ref = "arkitekt" } +# Arkitekt +arkitekt-compose = { group = "app.futured.arkitekt", name = "compose", version.ref = "arkitekt" } # Other timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } @@ -100,7 +101,6 @@ gradlePlugin-versions = { module = "com.github.ben-manes:gradle-versions-plugin" [plugins] android-application = { id = "com.android.application", version.ref = "agp" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } -kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } firebase-distribution = { id = "com.google.firebase.appdistribution", version.ref = "google-firebaseAppDistributionPlugin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68..c61a118 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle.kts b/settings.gradle.kts index b1a0c98..b21c7d3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven("https://central.sonatype.com/repository/maven-snapshots/") } }