Skip to content

Commit 552508e

Browse files
authored
Merge pull request #61 from t-regbs/cmp
CMP Refactor
2 parents 45336e4 + 06e94f5 commit 552508e

File tree

265 files changed

+7389
-961
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

265 files changed

+7389
-961
lines changed

.idea/deploymentTargetSelector.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,67 @@
33

44
![Android Build](https://github.com/t-regbs/MathAlarm/workflows/Android%20Build/badge.svg) ![My twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Ftwitter.com%2Ftimiaregbs) ![Shield](https://img.shields.io/badge/contributions-welcome-brightgreen) [![Made in Nigeria](https://img.shields.io/badge/made%20in-nigeria-008751.svg?style=flat-square)](https://github.com/acekyd/made-in-nigeria)
55

6-
An Android alarm app in which you solve math problems of varying difficulty to dismiss alarm. Built with Kotlin, Room, Coroutines, the MVVM pattern with Clean architecture, ViewModel, Jetpack compose and some other libraries from the [Android Jetpack](https://developer.android.com/jetpack) .
6+
A **Kotlin Multiplatform** alarm app for Android and iOS where you solve math problems of varying difficulty to dismiss the alarm. Built with Compose Multiplatform, Clean Architecture, and modern KMP libraries.
77

88
<a href='https://play.google.com/store/apps/details?id=com.timilehinaregbesola.mathalarm'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png' width="280"/></a>
99

10-
## Technologies used:
10+
## Architecture
1111

12-
* [Jetpack Compose](https://developer.android.com/jetpack/compose) - Android’s modern toolkit for building native UI
13-
* [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel) to store and manage UI-related data in a lifecycle conscious way.
14-
* [Navigation Material](https://google.github.io/accompanist/navigation-material) - provides Compose Material support for Jetpack Navigation Compose, features composable bottom sheet destinations.
15-
* [Timber](https://github.com/JakeWharton/timber) - a logger with a small, extensible API which provides utility on top of Android's normal Log class.
16-
* [Material Design](https://material3.io/develop/android/docs/getting-started/)
17-
* [Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) used to manage the local storage i.e. `writing to and reading from the database`. Coroutines help in managing background threads and reduces the need for callbacks.
18-
* [Room](https://developer.android.com/topic/libraries/architecture/room) persistence library which provides an abstraction layer over SQLite to allow for more robust database access while harnessing the full power of SQLite.
19-
* [Dagger Hilt](https://dagger.dev/hilt/) provides a standard way to incorporate Dagger dependency injection into an Android application.
12+
The project follows **Clean Architecture** with the **MVVM** pattern:
13+
14+
- **`:app`** - Main application module containing UI, navigation, and platform-specific implementations
15+
- **`:core`** - Shared domain logic and business rules
16+
17+
## Technologies Used
18+
19+
### Kotlin Multiplatform
20+
* [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html) - Share code between Android and iOS
21+
* [Compose Multiplatform](https://www.jetbrains.com/lp/compose-multiplatform/) - Declarative UI framework for both platforms
22+
23+
### UI & Navigation
24+
* [Material 3](https://m3.material.io/) - Modern Material Design components
25+
* [Navigation 3](https://developer.android.com/guide/navigation) - Jetpack Navigation for Compose Multiplatform
26+
* [Compottie](https://github.com/alexzhirkevich/compottie) - Lottie animations for Compose Multiplatform
27+
28+
### Data & Storage
29+
* [Room KMP](https://developer.android.com/kotlin/multiplatform/room) - Multiplatform database with SQLite
30+
* [Multiplatform Settings](https://github.com/russhwolf/multiplatform-settings) - Key-value storage across platforms
31+
* [Kotlinx Serialization](https://github.com/Kotlin/kotlinx.serialization) - JSON serialization
32+
33+
### Dependency Injection
34+
* [Koin](https://insert-koin.io/) - Lightweight dependency injection framework for KMP
35+
36+
### Async & Reactive
37+
* [Coroutines](https://kotlinlang.org/docs/coroutines-overview.html) - Asynchronous programming
38+
* [Kotlinx DateTime](https://github.com/Kotlin/kotlinx-datetime) - Multiplatform date/time library
39+
40+
### Logging & Analytics (Android)
41+
* [Kermit](https://github.com/touchlab/Kermit) - Multiplatform logging library
42+
* [Firebase Analytics](https://firebase.google.com/docs/analytics) - App analytics
43+
* [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics) - Crash reporting
44+
45+
### Localization
46+
* [Lyricist](https://github.com/adrielcafe/lyricist) - Type-safe string localization for Compose
47+
48+
### Testing
49+
* [Kotlin Test](https://kotlinlang.org/api/latest/kotlin.test/) - Multiplatform testing
50+
* [Turbine](https://github.com/cashapp/turbine) - Flow testing
51+
* [Kotest](https://kotest.io/) - Assertions library
52+
* [MockK](https://mockk.io/) - Mocking library (Android)
2053

2154
## Installation
22-
Math Alarm requires a minimum API level of 21. Clone the repository.
55+
56+
Math Alarm requires a minimum API level of **26** (Android 8.0+).
57+
58+
```bash
59+
# Clone the repository
60+
git clone https://github.com/t-regbs/MathAlarm.git
61+
62+
# Open in Android Studio or IntelliJ IDEA
63+
```
64+
65+
### Building for iOS
66+
The iOS app is located in the `iosApp/` directory. Open the Xcode project to build and run on iOS devices/simulators.
2367

2468
## Contribution
2569
All contributions are welcome. Simply make a PR!
@@ -28,7 +72,7 @@ All contributions are welcome. Simply make a PR!
2872
```
2973
MIT License
3074
31-
Copyright (c) 2023 Timilehin Aregbesola
75+
Copyright (c) 2025 Timilehin Aregbesola
3276
3377
Permission is hereby granted, free of charge, to any person obtaining a copy
3478
of this software and associated documentation files (the "Software"), to deal

app/build.gradle.kts

Lines changed: 132 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,133 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2+
13
plugins {
24
alias(libs.plugins.android.gradle)
3-
id("kotlin-android")
45
alias(libs.plugins.serialization)
5-
id("org.jetbrains.kotlin.plugin.parcelize")
66
alias(libs.plugins.google.services)
77
alias(libs.plugins.crashlytics.gradle)
88
alias(libs.plugins.ksp)
99
alias(libs.plugins.compose.compiler)
10+
alias(libs.plugins.composeMultiplatform)
11+
alias(libs.plugins.kotlinMultiplatform)
12+
alias(libs.plugins.androidx.room)
1013
}
1114

1215
ksp {
1316
arg("lyricist.generateStringsProperty", "true")
1417
}
1518

19+
// Room KMP configuration
20+
room {
21+
schemaDirectory("$projectDir/schemas")
22+
}
23+
24+
kotlin {
25+
androidTarget {
26+
compilerOptions {
27+
jvmTarget.set(JvmTarget.JVM_17)
28+
allWarningsAsErrors = false
29+
freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn", "-Xopt-in=kotlin.Experimental")
30+
}
31+
}
32+
33+
listOf(
34+
iosArm64(),
35+
iosSimulatorArm64()
36+
).forEach { iosTarget ->
37+
iosTarget.binaries.framework {
38+
baseName = "app"
39+
isStatic = true
40+
}
41+
}
42+
43+
// Swift Export configuration for AlarmKit integration
44+
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
45+
swiftExport {
46+
// Module name for Swift imports
47+
moduleName = "MathAlarmShared"
48+
49+
// Flatten package structure for cleaner Swift code
50+
flattenPackage = "com.timilehinaregbesola.mathalarm.alarm"
51+
52+
// Compiler configuration
53+
configure {
54+
freeCompilerArgs.add("-Xexpect-actual-classes")
55+
}
56+
}
57+
58+
sourceSets {
59+
androidMain.dependencies {
60+
implementation(compose.preview)
61+
implementation(libs.androidx.activity.compose)
62+
implementation(libs.androidx.sqlite.driver.android)
63+
implementation(project.dependencies.platform(libs.firebase.bom))
64+
implementation(libs.firebase.analytics)
65+
implementation(libs.firebase.crashlytics)
66+
implementation(libs.firebase.messaging)
67+
68+
implementation(libs.androidx.core.splashscreen)
69+
implementation(libs.android.material)
70+
}
71+
commonMain {
72+
kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin")
73+
dependencies {
74+
implementation(project(":core"))
75+
implementation(libs.runtime)
76+
implementation(libs.foundation)
77+
implementation(libs.material3)
78+
implementation(libs.ui)
79+
implementation(libs.components.resources)
80+
implementation(libs.ui.tooling.preview)
81+
82+
val koinBom = project.dependencies.platform(libs.koin.bom)
83+
implementation(koinBom)
84+
implementation(libs.koin.core)
85+
implementation(libs.koin.compose)
86+
implementation(libs.koin.compose.viewmodel)
87+
88+
implementation(libs.kermit)
89+
implementation(libs.kermit.crashlytics)
90+
91+
implementation(libs.kotlinx.serialization)
92+
implementation(libs.lyricist)
93+
94+
implementation(libs.jetbrains.navigation3.ui)
95+
implementation(libs.jetbrains.lifecycle.viewmodel.navigation3)
96+
implementation(libs.kotlinx.datetime)
97+
implementation(libs.multiplatform.settings.no.arg)
98+
99+
implementation(libs.androidx.room.runtime)
100+
implementation(libs.androidx.sqlite.driver.bundled)
101+
102+
implementation(libs.compottie.lite)
103+
}
104+
}
105+
106+
// iOS dependencies
107+
val iosMain by creating {
108+
dependsOn(commonMain.get())
109+
dependencies {
110+
implementation(libs.androidx.sqlite.driver.bundled)
111+
}
112+
}
113+
val iosArm64Main by getting { dependsOn(iosMain) }
114+
val iosSimulatorArm64Main by getting { dependsOn(iosMain) }
115+
116+
commonTest.dependencies {
117+
implementation(libs.kotlin.test)
118+
implementation(libs.coroutines.test)
119+
implementation(libs.turbine)
120+
implementation(libs.kotest.assertions)
121+
}
122+
}
123+
}
124+
16125
android {
17126
namespace = "com.timilehinaregbesola.mathalarm"
18127
defaultConfig {
19128
applicationId = "com.timilehinaregbesola.mathalarm"
20-
versionCode = 20
21-
versionName = "2.3.1"
129+
versionCode = 21
130+
versionName = "2.3.2"
22131
minSdk = libs.versions.android.min.sdk.get().toInt()
23132
targetSdk = libs.versions.android.target.sdk.get().toInt()
24133
compileSdk = libs.versions.android.compile.sdk.get().toInt()
@@ -37,18 +146,10 @@ android {
37146
}
38147

39148
compileOptions {
40-
// Flag to enable support for the new language APIs
41-
isCoreLibraryDesugaringEnabled = true
42-
43149
sourceCompatibility = JavaVersion.VERSION_17
44150
targetCompatibility = JavaVersion.VERSION_17
45151
}
46152

47-
kotlinOptions {
48-
allWarningsAsErrors = false
49-
freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn", "-Xopt-in=kotlin.Experimental")
50-
jvmTarget = "17"
51-
}
52153
lint {
53154
disable += setOf("LogNotTimber", "StringFormatInTimber", "ThrowableNotAtBeginning", "BinaryOperationInTimber", "TimberArgCount", "TimberArgTypes", "TimberTagLength", "TimberExceptionLogging")
54155
}
@@ -78,70 +179,32 @@ android {
78179

79180
dependencies {
80181
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
81-
implementation(project(":core"))
82-
83-
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
84182

85-
implementation(libs.android.material)
86-
implementation(libs.androidx.ktx)
87-
88-
implementation(libs.androidx.test.core.ktx)
89183
testImplementation(libs.junit)
90184
testImplementation(libs.coroutines.test)
91185
androidTestImplementation(libs.androidx.test.ext.junit)
92186
androidTestImplementation(libs.androidx.test.espresso.core)
93187
testImplementation(libs.mockk)
94188

95-
implementation(libs.androidx.room.runtime)
96-
implementation(libs.androidx.room.ktx)
97-
ksp(libs.androidx.room.compiler)
98-
99-
implementation(libs.lottie.compose)
100-
101-
implementation(libs.coroutines.core)
102-
implementation(libs.coroutines.android)
103-
104-
implementation(libs.androidx.activity.compose)
105-
106-
implementation(platform(libs.firebase.bom))
107-
implementation(libs.firebase.analytics)
108-
implementation(libs.firebase.crashlytics)
109-
implementation(libs.firebase.messaging)
110-
111-
implementation(libs.androidx.core.splashscreen)
112-
implementation(libs.androidx.datastore)
113-
implementation(libs.kotlinx.serialization)
114-
115-
val composeBom = platform(libs.compose.bom)
116-
implementation(composeBom)
117-
androidTestImplementation(composeBom)
118-
implementation(libs.androidx.compose.ui)
119-
implementation(libs.androidx.compose.material3)
120-
implementation(libs.androidx.compose.material.icons)
121-
debugImplementation(libs.androidx.compose.ui.tooling)
122-
implementation(libs.androidx.compose.ui.tooling.preview)
123-
implementation(libs.androidx.compose.runtime)
124-
implementation(libs.androidx.compose.runtime.saveable)
125-
implementation(libs.androidx.compose.runtime.livedata)
189+
// Room KMP - compiler for each platform
190+
add("kspAndroid", libs.androidx.room.compiler)
191+
add("kspIosArm64", libs.androidx.room.compiler)
192+
add("kspIosSimulatorArm64", libs.androidx.room.compiler)
126193
androidTestImplementation(libs.androidx.compose.ui.test)
127194

128-
implementation(libs.androidx.navigation3.runtime)
129-
implementation(libs.androidx.navigation3.ui)
130-
implementation(libs.androidx.lifecycle.viewmodel.navigation3)
131-
implementation(libs.androidx.adaptive.navigation3)
132-
implementation(libs.androidx.appcompat)
133-
implementation(libs.kotlinx.datetime)
134-
135-
implementation(libs.lyricist)
136-
ksp(libs.lyricist.processor)
137-
138-
val koinBom = platform(libs.koin.bom)
139-
implementation(koinBom)
140-
implementation(libs.koin.core)
141-
implementation(libs.koin.android)
142-
implementation(libs.koin.compose)
143-
implementation(libs.koin.compose.viewmodel)
144-
145-
implementation(libs.kermit)
146-
implementation(libs.kermit.crashlytics)
195+
add("kspCommonMainMetadata", libs.lyricist.processor)
196+
}
197+
198+
afterEvaluate {
199+
// Make all compilation tasks depend on KSP common metadata
200+
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>>().configureEach {
201+
if (name != "kspCommonMainKotlinMetadata") {
202+
dependsOn("kspCommonMainKotlinMetadata")
203+
}
204+
}
205+
}
206+
207+
// Ensure all KSP tasks run after common metadata KSP
208+
tasks.matching { it.name.startsWith("ksp") && it.name != "kspCommonMainKotlinMetadata" }.configureEach {
209+
dependsOn(tasks.named("kspCommonMainKotlinMetadata"))
147210
}

app/release/app-release.aab

-2.08 MB
Binary file not shown.

0 commit comments

Comments
 (0)