Skip to content

Commit 5d49800

Browse files
committed
Add spotless with ktlint and ktfmt
1 parent 161405d commit 5d49800

File tree

373 files changed

+7730
-8406
lines changed

Some content is hidden

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

373 files changed

+7730
-8406
lines changed

.editorconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[*.{kt,kts}]
2+
# Compose allows PascalCase for @Composable functions
3+
ktlint_standard_function-naming = disabled
4+
# Filename should match class name is not always desired
5+
ktlint_standard_filename = disabled

.github/workflows/pr-check.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@ on:
55
branches: [ "**" ]
66

77
jobs:
8+
spotless:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- name: Set up JDK 17
13+
uses: actions/setup-java@v4
14+
with:
15+
java-version: '17'
16+
distribution: 'temurin'
17+
- name: Setup Gradle
18+
uses: gradle/actions/setup-gradle@v4
19+
- name: Grant execute permission for gradlew
20+
run: chmod +x gradlew
21+
- name: Run Spotless Check
22+
run: ./gradlew spotlessCheck
23+
824
lint:
925
runs-on: ubuntu-latest
1026
environment: staging

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,26 @@
5353
* [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html)
5454
* Native Android/iOS View and ViewModel layer
5555

56+
### Code Quality & Formatting
57+
58+
We use **Spotless** to maintain a consistent code style across the project. It integrates two main tools:
59+
- **ktfmt (Google Style):** A deterministic formatter that ensures all Kotlin code follows a unified structure.
60+
- **ktlint:** A linter that enforces additional best practices and code smells (e.g., forbidding wildcard imports).
61+
62+
#### Formatting Commands
63+
- **Check formatting:** `./gradlew spotlessCheck`
64+
- **Apply formatting:** `./gradlew spotlessApply`
65+
66+
#### Git Hooks
67+
To ensure code is formatted before every commit, we use a pre-commit hook. You can install it by running:
68+
```bash
69+
./scripts/install-git-hooks.sh
70+
```
71+
This hook will automatically run `spotlessApply` and stage any formatting changes whenever you commit.
72+
73+
#### CI Integration
74+
Formatting is automatically verified on every Pull Request via GitHub Actions.
75+
5676
<!-- GETTING STARTED -->
5777

5878
## 📖 Getting Started

android/app-newm/build.gradle.kts

Lines changed: 131 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -2,162 +2,142 @@ import java.text.SimpleDateFormat
22
import java.util.Date
33

44
apply(from = "../../gradle_include/compose.gradle")
5+
56
apply(from = "../../gradle_include/circuit.gradle")
7+
68
apply(from = "../../gradle_include/flipper.gradle")
79

810
plugins {
9-
id("com.android.application")
10-
id("com.google.gms.google-services")
11-
id("kotlin-parcelize")
12-
kotlin("android")
13-
kotlin("kapt")
14-
id("io.sentry.android.gradle") version "5.12.1"
15-
alias(libs.plugins.compose.multiplatform)
11+
id("com.android.application")
12+
id("com.google.gms.google-services")
13+
id("kotlin-parcelize")
14+
kotlin("android")
15+
kotlin("kapt")
16+
id("io.sentry.android.gradle") version "5.12.1"
17+
alias(libs.plugins.compose.multiplatform)
1618
}
1719

18-
1920
android {
20-
compileSdk = libs.versions.android.compileSdk.get().toInt()
21-
ndkVersion = "27.0.12077973"
22-
23-
namespace = "io.newm"
24-
testNamespace = "io.newm.test"
25-
defaultConfig {
26-
applicationId = "io.newm"
27-
minSdk = libs.versions.android.minSdk.get().toInt()
28-
targetSdk = libs.versions.android.targetSdk.get().toInt()
29-
versionCode = getCurrentDateTimeVersionCode()
30-
versionName = getCustomVersionName(major = 1)
31-
testInstrumentationRunner = "io.newm.NewmAndroidJUnitRunner"
32-
testApplicationId = "io.newm.test"
21+
compileSdk = libs.versions.android.compileSdk.get().toInt()
22+
ndkVersion = "27.0.12077973"
23+
24+
namespace = "io.newm"
25+
testNamespace = "io.newm.test"
26+
defaultConfig {
27+
applicationId = "io.newm"
28+
minSdk = libs.versions.android.minSdk.get().toInt()
29+
targetSdk = libs.versions.android.targetSdk.get().toInt()
30+
versionCode = getCurrentDateTimeVersionCode()
31+
versionName = getCustomVersionName(major = 1)
32+
testInstrumentationRunner = "io.newm.NewmAndroidJUnitRunner"
33+
testApplicationId = "io.newm.test"
34+
}
35+
36+
lint { baseline = file("lint-baseline.xml") }
37+
38+
packaging {
39+
resources {
40+
merges += "META-INF/LICENSE.md"
41+
merges += "META-INF/LICENSE-notice.md"
3342
}
34-
35-
lint {
36-
baseline = file("lint-baseline.xml")
43+
jniLibs { useLegacyPackaging = true }
44+
}
45+
46+
buildTypes {
47+
release {
48+
isDebuggable = false
49+
isMinifyEnabled = false
50+
isMinifyEnabled = false
51+
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
3752
}
38-
39-
packaging {
40-
resources {
41-
merges += "META-INF/LICENSE.md"
42-
merges += "META-INF/LICENSE-notice.md"
43-
}
44-
jniLibs {
45-
useLegacyPackaging = true
46-
}
53+
debug {
54+
isDebuggable = true
55+
isMinifyEnabled = false
56+
isMinifyEnabled = false
4757
}
48-
49-
buildTypes {
50-
release {
51-
isDebuggable = false
52-
isMinifyEnabled = false
53-
isMinifyEnabled = false
54-
proguardFiles(
55-
getDefaultProguardFile("proguard-android-optimize.txt"),
56-
"proguard-rules.pro"
57-
)
58-
}
59-
debug {
60-
isDebuggable = true
61-
isMinifyEnabled = false
62-
isMinifyEnabled = false
63-
}
58+
}
59+
flavorDimensions += "version"
60+
61+
productFlavors {
62+
create("production") {
63+
namespace = "io.newm"
64+
applicationId = "io.newm"
65+
dimension = "version"
6466
}
65-
flavorDimensions += "version"
66-
67-
productFlavors {
68-
create("production") {
69-
namespace = "io.newm"
70-
applicationId = "io.newm"
71-
dimension = "version"
72-
}
73-
create("development") {
74-
namespace = "io.newm"
75-
applicationId = "io.newm"
76-
applicationIdSuffix = ".dev"
77-
dimension = "version"
78-
}
79-
all {
80-
resValue(
81-
"string",
82-
"account_type",
83-
"$applicationId${applicationIdSuffix.orEmpty()}.account"
84-
)
85-
}
67+
create("development") {
68+
namespace = "io.newm"
69+
applicationId = "io.newm"
70+
applicationIdSuffix = ".dev"
71+
dimension = "version"
8672
}
87-
88-
buildFeatures {
89-
buildConfig = true
73+
all {
74+
resValue("string", "account_type", "$applicationId${applicationIdSuffix.orEmpty()}.account")
9075
}
76+
}
9177

92-
compileOptions {
93-
sourceCompatibility = JavaVersion.VERSION_11
94-
targetCompatibility = JavaVersion.VERSION_11
95-
isCoreLibraryDesugaringEnabled = true
96-
}
78+
buildFeatures { buildConfig = true }
9779

98-
kapt {
99-
correctErrorTypes = true
100-
}
80+
compileOptions {
81+
sourceCompatibility = JavaVersion.VERSION_11
82+
targetCompatibility = JavaVersion.VERSION_11
83+
isCoreLibraryDesugaringEnabled = true
84+
}
85+
86+
kapt { correctErrorTypes = true }
10187
}
10288

10389
dependencies {
104-
105-
implementation(libs.process.phoenix)
106-
coreLibraryDesugaring(libs.desugar.jdk.libs)
107-
implementation(libs.androidx.core.ktx)
108-
implementation(libs.androidx.appcompat)
109-
implementation(libs.androidx.constraintlayout)
110-
implementation(libs.firebase.analytics)
111-
implementation(libs.androidx.lifecycle.runtime.ktx)
112-
implementation(compose.material)
113-
implementation(libs.androidx.media3.datasource)
114-
implementation(libs.androidx.media3.exoplayer)
115-
implementation(libs.androidx.media3.database)
116-
implementation(libs.androidx.navigation.ui.ktx)
117-
implementation(libs.launchdarkly.client)
118-
implementation(libs.play.services.auth)
119-
implementation(libs.recaptcha)
120-
implementation(libs.androidx.core.splashscreen)
121-
implementation(libs.koin.android)
122-
implementation(libs.kotlin.reflect)
123-
implementation(libs.cmp.image.pick.n.crop)
124-
implementation(platform(libs.firebase.bom))
125-
implementation(libs.androidx.material.icons.extended)
126-
implementation(project(Modules.barcodeScanner))
127-
implementation(project(Modules.coreAndroidImplementations))
128-
implementation(project(Modules.coreResources))
129-
implementation(project(Modules.coreTheme))
130-
implementation(project(Modules.coreUiUtils))
131-
implementation(project(Modules.login))
132-
implementation(project(Modules.musicPlayer))
133-
implementation(project(Modules.shared))
134-
implementation(project(Modules.sharedComposeFeatures))
135-
136-
testImplementation(libs.junit)
137-
testImplementation(libs.mockk)
138-
139-
androidTestImplementation(libs.androidx.espresso.core)
140-
androidTestImplementation(libs.androidx.test.junit)
141-
androidTestImplementation(libs.mockk.android)
90+
implementation(libs.process.phoenix)
91+
coreLibraryDesugaring(libs.desugar.jdk.libs)
92+
implementation(libs.androidx.core.ktx)
93+
implementation(libs.androidx.appcompat)
94+
implementation(libs.androidx.constraintlayout)
95+
implementation(libs.firebase.analytics)
96+
implementation(libs.androidx.lifecycle.runtime.ktx)
97+
implementation(compose.material)
98+
implementation(libs.androidx.media3.datasource)
99+
implementation(libs.androidx.media3.exoplayer)
100+
implementation(libs.androidx.media3.database)
101+
implementation(libs.androidx.navigation.ui.ktx)
102+
implementation(libs.launchdarkly.client)
103+
implementation(libs.play.services.auth)
104+
implementation(libs.recaptcha)
105+
implementation(libs.androidx.core.splashscreen)
106+
implementation(libs.koin.android)
107+
implementation(libs.kotlin.reflect)
108+
implementation(libs.cmp.image.pick.n.crop)
109+
implementation(platform(libs.firebase.bom))
110+
implementation(libs.androidx.material.icons.extended)
111+
implementation(project(Modules.barcodeScanner))
112+
implementation(project(Modules.coreAndroidImplementations))
113+
implementation(project(Modules.coreResources))
114+
implementation(project(Modules.coreTheme))
115+
implementation(project(Modules.coreUiUtils))
116+
implementation(project(Modules.login))
117+
implementation(project(Modules.musicPlayer))
118+
implementation(project(Modules.shared))
119+
implementation(project(Modules.sharedComposeFeatures))
120+
121+
testImplementation(libs.junit)
122+
testImplementation(libs.mockk)
123+
124+
androidTestImplementation(libs.androidx.espresso.core)
125+
androidTestImplementation(libs.androidx.test.junit)
126+
androidTestImplementation(libs.mockk.android)
142127
}
143128

144-
kotlin {
145-
compilerOptions {
146-
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
147-
}
148-
}
129+
kotlin { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11) } }
149130

150131
sentry {
151-
org.set("project-newm")
152-
projectName.set("android")
132+
org.set("project-newm")
133+
projectName.set("android")
153134

154-
// this will upload your source code to Sentry to show it as part of the stack traces
155-
// disable if you don't want to expose your sources
156-
includeSourceContext.set(true)
157-
telemetry.set(true)
135+
// this will upload your source code to Sentry to show it as part of the stack traces
136+
// disable if you don't want to expose your sources
137+
includeSourceContext.set(true)
138+
telemetry.set(true)
158139
}
159140

160-
161141
/**
162142
* Generates a version code based on the current date and time in the format `yyMMddHH`.
163143
*
@@ -167,18 +147,19 @@ sentry {
167147
* - `dd`: The current day of the month.
168148
* - `HH`: The current hour (24-hour format).
169149
*
170-
* The function formats the current date and time using `SimpleDateFormat`,
171-
* converts it into a string, and then parses it as an integer.
150+
* The function formats the current date and time using `SimpleDateFormat`, converts it into a
151+
* string, and then parses it as an integer.
172152
*
173153
* @return An integer representing the current date and time in the format `yyMMddHH`.
174154
*/
175155
fun getCurrentDateTimeVersionCode(): Int {
176-
val dateFormat = SimpleDateFormat("yyMMddHH")
177-
return dateFormat.format(Date()).toInt()
156+
val dateFormat = SimpleDateFormat("yyMMddHH")
157+
return dateFormat.format(Date()).toInt()
178158
}
179159

180160
/**
181-
* Generates a custom version name based on the provided major version and the current date and time.
161+
* Generates a custom version name based on the provided major version and the current date and
162+
* time.
182163
*
183164
* The version name follows the format: `major.yyMMdd.HHmm`, where:
184165
* - `major`: The major version number passed as a parameter.
@@ -187,23 +168,24 @@ fun getCurrentDateTimeVersionCode(): Int {
187168
* - `HH`: The current hour in 24-hour format.
188169
* - `mm`: The current minute.
189170
*
190-
* The function retrieves the current date and time using `SimpleDateFormat` to format each component.
171+
* The function retrieves the current date and time using `SimpleDateFormat` to format each
172+
* component.
191173
*
192174
* Example output for `major = 1` on October 1st, 2024 at 13:45 would be: `1.241001.1345`.
193175
*
194176
* @param major The major version number to be used as the first part of the version name.
195177
* @return A custom version name string in the format: `major.yyMMdd.HHmm`.
196178
*/
197179
fun getCustomVersionName(major: Int): String {
198-
val yearFormat = SimpleDateFormat("yy")
199-
val monthDayFormat = SimpleDateFormat("MMdd")
200-
val hourFormat = SimpleDateFormat("HH")
201-
val minuteFormat = SimpleDateFormat("mm")
202-
203-
val year = yearFormat.format(Date())
204-
val monthDay = monthDayFormat.format(Date())
205-
val hour = hourFormat.format(Date())
206-
val minute = minuteFormat.format(Date())
207-
208-
return "$major.$year$monthDay.$hour$minute"
209-
}
180+
val yearFormat = SimpleDateFormat("yy")
181+
val monthDayFormat = SimpleDateFormat("MMdd")
182+
val hourFormat = SimpleDateFormat("HH")
183+
val minuteFormat = SimpleDateFormat("mm")
184+
185+
val year = yearFormat.format(Date())
186+
val monthDay = monthDayFormat.format(Date())
187+
val hour = hourFormat.format(Date())
188+
val minute = minuteFormat.format(Date())
189+
190+
return "$major.$year$monthDay.$hour$minute"
191+
}

0 commit comments

Comments
 (0)