diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml deleted file mode 100644 index 38b8bf71b..000000000 --- a/.github/workflows/android.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: Android CI - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -concurrency: - group: build-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - cache: gradle - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - name: Build with Gradle - run: ./gradlew build - - - name: Archive production artifacts - uses: actions/upload-artifact@v2 - with: - name: app - path: app/build/outputs/apk/ - - test: - runs-on: ubuntu-latest - needs: build - steps: - - name: Checkout code - uses: actions/checkout@v4.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.13.0 - with: - distribution: 'adopt' - java-version: '17' - - - name: Grant execute permissions for gradlew - run: chmod +x ./gradlew - - - name: Run Tests with Gradle - run: ./gradlew test - - lint: - runs-on: ubuntu-latest - needs: build - steps: - - name: Checkout code - uses: actions/checkout@v4.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.13.0 - with: - distribution: 'temurin' - java-version: '17' - cache: gradle - - - name: Grant execute permissions for gradlew - run: chmod +x ./gradlew - - name: Run Lint with Gradle - run: ./gradlew lint - - name: Upload lint results - uses: actions/upload-artifact@v2 - with: - name: lint-results - path: '**/build/reports/lint-results-*.html' - - dokka: - runs-on: ubuntu-latest - needs: [ build, test ] - steps: - - name: Checkout code - uses: actions/checkout@v4.1.0 - - - name: Set up JDK 17 - uses: actions/setup-java@v3.13.0 - with: - distribution: 'temurin' - java-version: '17' - cache: gradle - - - name: Grant execute permissions for gradlew - run: chmod +x ./gradlew - - name: Run Dokka with Gradle - run: ./gradlew dokkaHtmlMultiModule - - - name: Deploy to GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4 - with: - branch: gh-pages - folder: build/dokka/htmlMultiModule \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 000000000..ec2ee2e6e --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,60 @@ +name: Pull Request + +on: + pull_request: + branches: [ "main" ] + +concurrency: + group: build-${{ github.ref }} + cancel-in-progress: true + +jobs: + detekt: + name: Detekt review + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1 + ref: ${{ github.head_ref }} + - name: Detekt PR Check + uses: alaegin/Detekt-Action@v1.23.6 + with: + reviewdog_reporter: github-pr-check + github_token: ${{ secrets.github_token }} + fail_on_error: true + detekt_config: internal/detekt-config.yml + + buildtestanalyze: + name: Build, test and analyze + runs-on: ubuntu-latest + timeout-minutes: 120 + permissions: # needed for CodeQL steps + security-events: write + packages: read + actions: read + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4.1.0 + - name: Initialize CodeQL # CodeQL init should happen before project build! + uses: github/codeql-action/init@v3 + with: + languages: java-kotlin + build-mode: manual + - name: Set up JDK 17 + uses: actions/setup-java@v3.13.0 + with: + distribution: 'temurin' + java-version: '17' + cache: gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + - name: Build and test + run: ./gradlew build + - name: Perform CodeQL Analysis # CodeQL analysis needs project build! + uses: github/codeql-action/analyze@v3 + with: + category: "/language:java-kotlin" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..0e52b4925 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,49 @@ +name: Merge + +on: + push: + branches: [ "main" ] + +concurrency: + group: build-${{ github.ref }} + cancel-in-progress: true + +jobs: + buildtestanalyze: + uses: ./.github/workflows/build-and-test.yml + secrets: inherit + + uploadartifacts: + name: Archive production artifacts + runs-on: ubuntu-latest + needs: buildtestanalyze + steps: + - name: Checkout code + uses: actions/checkout@v4.1.0 + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: app + path: app/build/outputs/apk/ + + dokka: + runs-on: ubuntu-latest + needs: buildtestanalyze + steps: + - name: Checkout code + uses: actions/checkout@v4.1.0 + - name: Set up JDK 17 + uses: actions/setup-java@v3.13.0 + with: + distribution: 'temurin' + java-version: '17' + cache: gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + - name: Run Dokka with Gradle + run: ./gradlew dokkaHtmlMultiModule + - name: Deploy to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: gh-pages + folder: build/dokka/htmlMultiModule diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 82d3b0a61..934657ac6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -36,4 +36,4 @@ dependencies { implementation(libs.hilt.navigation.compose) implementation(project(":core:bluetooth")) -} \ No newline at end of file +} diff --git a/app/src/androidTest/kotlin/edu/stanford/spezi/app/ExampleInstrumentedTest.kt b/app/src/androidTest/kotlin/edu/stanford/spezi/app/ExampleInstrumentedTest.kt deleted file mode 100644 index baf2c0341..000000000 --- a/app/src/androidTest/kotlin/edu/stanford/spezi/app/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package edu.stanford.spezi.app - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("edu.stanford.spezi.app", appContext.packageName) - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/edu/stanford/spezi/app/MainActivity.kt b/app/src/main/kotlin/edu/stanford/spezi/app/MainActivity.kt index 17ea9fcaf..5deaf237b 100644 --- a/app/src/main/kotlin/edu/stanford/spezi/app/MainActivity.kt +++ b/app/src/main/kotlin/edu/stanford/spezi/app/MainActivity.kt @@ -13,8 +13,8 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { SpeziTheme { - BluetoothScreen() + BluetoothScreen() } } } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/edu/stanford/spezi/app/MainApplication.kt b/app/src/main/kotlin/edu/stanford/spezi/app/MainApplication.kt index df674256a..9cddacef5 100644 --- a/app/src/main/kotlin/edu/stanford/spezi/app/MainApplication.kt +++ b/app/src/main/kotlin/edu/stanford/spezi/app/MainApplication.kt @@ -12,4 +12,4 @@ class MainApplication : Application() { SpeziLogger.setLoggingEnabled(enabled = BuildConfig.DEBUG) } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/BluetoothViewModel.kt b/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/BluetoothViewModel.kt index deef80c7d..7cda4e2b3 100644 --- a/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/BluetoothViewModel.kt +++ b/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/BluetoothViewModel.kt @@ -72,4 +72,4 @@ class BluetoothViewModel @Inject internal constructor( object EnableBluetooth : Event data class RequestPermissions(val permissions: List) : Event } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/data/mapper/BluetoothUiStateMapper.kt b/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/data/mapper/BluetoothUiStateMapper.kt index 43688f560..be7248ec7 100644 --- a/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/data/mapper/BluetoothUiStateMapper.kt +++ b/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/data/mapper/BluetoothUiStateMapper.kt @@ -30,4 +30,4 @@ class BluetoothUiStateMapper @Inject constructor() { } private fun format(value: Number?): String = String.format(Locale.US, "%.2f", value) -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/data/models/DeviceUiModel.kt b/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/data/models/DeviceUiModel.kt index 3a7ff1ab7..792e9bb74 100644 --- a/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/data/models/DeviceUiModel.kt +++ b/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/data/models/DeviceUiModel.kt @@ -4,4 +4,4 @@ data class DeviceUiModel( val address: String, val measurementsCount: Int, val summary: String, -) \ No newline at end of file +) diff --git a/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/screen/BluetoothScreen.kt b/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/screen/BluetoothScreen.kt index 69cb548fd..7aad644cd 100644 --- a/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/screen/BluetoothScreen.kt +++ b/app/src/main/kotlin/edu/stanford/spezi/app/bluetooth/screen/BluetoothScreen.kt @@ -71,7 +71,6 @@ private fun AdditionalInfo(uiState: BluetoothUiState) { Text(text = text) } - @Composable fun DeviceComposable(device: DeviceUiModel) { ElevatedCard(modifier = Modifier.fillMaxWidth()) { @@ -102,4 +101,4 @@ private fun BluetoothEvents(events: Flow) { } } } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/edu/stanford/spezi/app/bluetooth/BluetoothViewModelTest.kt b/app/src/test/kotlin/edu/stanford/spezi/app/bluetooth/BluetoothViewModelTest.kt index 0e890b2cc..b271f56ec 100644 --- a/app/src/test/kotlin/edu/stanford/spezi/app/bluetooth/BluetoothViewModelTest.kt +++ b/app/src/test/kotlin/edu/stanford/spezi/app/bluetooth/BluetoothViewModelTest.kt @@ -189,4 +189,4 @@ class BluetoothViewModelTest { uiStateMapper = uiStateMapper ) } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/edu/stanford/spezi/app/bluetooth/data/mapper/BluetoothUiStateMapperTest.kt b/app/src/test/kotlin/edu/stanford/spezi/app/bluetooth/data/mapper/BluetoothUiStateMapperTest.kt index bdefe5333..0f9b05f2d 100644 --- a/app/src/test/kotlin/edu/stanford/spezi/app/bluetooth/data/mapper/BluetoothUiStateMapperTest.kt +++ b/app/src/test/kotlin/edu/stanford/spezi/app/bluetooth/data/mapper/BluetoothUiStateMapperTest.kt @@ -87,4 +87,4 @@ class BluetoothUiStateMapperTest { const val WEIGHT = 4.56 const val ADDRESS = "some device address" } -} \ No newline at end of file +} diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index b79cc93e0..39020075d 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -48,4 +48,4 @@ gradlePlugin { conventionPlugin(id = "hilt", className = "HiltConventionPlugin") conventionPlugin(id = "library", className = "SpeziLibraryConventionPlugin") } -} \ No newline at end of file +} diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/extensions/DependencyHandler.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/extensions/DependencyHandler.kt index 1fc3f96e2..28adcd2e5 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/extensions/DependencyHandler.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/extensions/DependencyHandler.kt @@ -16,4 +16,4 @@ internal fun DependencyHandler.debugImplementation(dependency: Any) { internal fun DependencyHandler.androidTestImplementation(dependency: Any) { add("androidTestImplementation", dependency) -} \ No newline at end of file +} diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/extensions/Project.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/extensions/Project.kt index 9f5aa08b7..e527396bd 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/extensions/Project.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/extensions/Project.kt @@ -34,4 +34,4 @@ internal fun Project.commonExtensions(configBlock: CommonExtension<*,*,*,*,*,*>. isLibrary() -> extension(configBlock) else -> error("commonExtensions was called before setting the module type plugin") } -} \ No newline at end of file +} diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/model/PluginId.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/model/PluginId.kt index 6bee74d3e..79e659e0d 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/model/PluginId.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/model/PluginId.kt @@ -7,4 +7,4 @@ enum class PluginId(val id: String) { HILT(id = "com.google.dagger.hilt.android"), KSP(id = "com.google.devtools.ksp"), COMPOSE_COMPILER("org.jetbrains.kotlin.plugin.compose") -} \ No newline at end of file +} diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/HiltConventionPlugin.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/HiltConventionPlugin.kt index 16242b876..4cf7a4cf4 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/HiltConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/HiltConventionPlugin.kt @@ -29,4 +29,4 @@ class HiltConventionPlugin : Plugin { enableAggregatingTask = true } } -} \ No newline at end of file +} diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziAbstractConfigPlugin.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziAbstractConfigPlugin.kt index ea6f2fa4f..a75413ca6 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziAbstractConfigPlugin.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziAbstractConfigPlugin.kt @@ -23,4 +23,4 @@ abstract class SpeziAbstractConfigPlugin(private val modulePlugin: PluginId) : P testImplementation(project(":core:testing")) } } -} \ No newline at end of file +} diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziApplicationConventionPlugin.kt index 5de1cf6ec..0fd075597 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziApplicationConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziApplicationConventionPlugin.kt @@ -2,4 +2,4 @@ package edu.stanford.spezi.build.logic.convention.plugins import edu.stanford.spezi.build.logic.convention.model.PluginId -class SpeziApplicationConventionPlugin : SpeziAbstractConfigPlugin(modulePlugin = PluginId.ANDROID_APPLICATION) \ No newline at end of file +class SpeziApplicationConventionPlugin : SpeziAbstractConfigPlugin(modulePlugin = PluginId.ANDROID_APPLICATION) diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziBaseConfigConventionPlugin.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziBaseConfigConventionPlugin.kt index 23da820d2..66d94e773 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziBaseConfigConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziBaseConfigConventionPlugin.kt @@ -59,4 +59,4 @@ class SpeziBaseConfigConventionPlugin : Plugin { } } } -} \ No newline at end of file +} diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziComposeConventionPlugin.kt index 45330e54e..976f83fd5 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziComposeConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziComposeConventionPlugin.kt @@ -36,4 +36,4 @@ class SpeziComposeConventionPlugin : Plugin { } } } -} \ No newline at end of file +} diff --git a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziLibraryConventionPlugin.kt index 017533eb7..4694e9954 100644 --- a/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/edu/stanford/spezi/build/logic/convention/plugins/SpeziLibraryConventionPlugin.kt @@ -2,4 +2,4 @@ package edu.stanford.spezi.build.logic.convention.plugins import edu.stanford.spezi.build.logic.convention.model.PluginId -class SpeziLibraryConventionPlugin : SpeziAbstractConfigPlugin(modulePlugin = PluginId.ANDROID_LIBRARY) \ No newline at end of file +class SpeziLibraryConventionPlugin : SpeziAbstractConfigPlugin(modulePlugin = PluginId.ANDROID_LIBRARY) diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts index b8c2f72bd..a0a40c169 100644 --- a/build-logic/settings.gradle.kts +++ b/build-logic/settings.gradle.kts @@ -12,4 +12,4 @@ dependencyResolutionManagement { } rootProject.name = "build-logic" -include(":convention") \ No newline at end of file +include(":convention") diff --git a/build.gradle.kts b/build.gradle.kts index 6e1952940..2662735e4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,18 +1,30 @@ +import io.gitlab.arturbosch.detekt.Detekt import org.jetbrains.dokka.gradle.DokkaTaskPartial plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false - alias(libs.plugins.jetbrains.kotlin.android) apply false - alias(libs.plugins.hilt.android) version libs.versions.hiltVersion apply false - alias(libs.plugins.google.devtools.ksp) version libs.versions.kspVersion apply false alias(libs.plugins.compose.compiler) version libs.versions.kotlin apply false + alias(libs.plugins.detekt) version libs.versions.detekt alias(libs.plugins.dokka) version libs.versions.dokka + alias(libs.plugins.google.devtools.ksp) version libs.versions.kspVersion apply false + alias(libs.plugins.hilt.android) version libs.versions.hiltVersion apply false + alias(libs.plugins.jetbrains.kotlin.android) apply false } subprojects { - apply(plugin = "org.jetbrains.dokka") + setupDokka() + setupDetekt() +} + +installCustomTasks() + +tasks.dokkaHtmlMultiModule { + moduleName.set("Spezi Documentation") +} +fun Project.setupDokka() { + apply(plugin = rootProject.libs.plugins.dokka.get().pluginId) if (this != rootProject) { rootProject.tasks.named("dokkaHtmlMultiModule") { @@ -26,7 +38,7 @@ subprojects { skipDeprecated.set(true) skipEmptyPackages.set(true) includeNonPublic.set(false) - jdkVersion.set(17) + jdkVersion.set(JavaVersion.VERSION_17.majorVersion.toInt()) if (file("README.md").exists()) { includes.from("README.md") } @@ -42,6 +54,44 @@ subprojects { } } -tasks.dokkaHtmlMultiModule { - moduleName.set("Spezi Documentation") -} \ No newline at end of file +fun Project.setupDetekt() { + val libs = rootProject.libs + apply(plugin = libs.plugins.detekt.get().pluginId) + detekt { + toolVersion = libs.versions.detekt.get() + config.setFrom("$rootDir/internal/detekt-config.yml") + autoCorrect = true + ignoreFailures = false + source.setFrom( + files( + "src/main", + "src/test", + "src/androidTest", + "build.gradle.kts" + ) + ) + } + + dependencies { + detektPlugins(libs.detekt.formatting) + } + + tasks.withType { + reports { + xml.required.set(true) + html.required.set(true) + txt.required.set(true) + sarif.required.set(true) + } + } +} + +/** + * Installs all custom tasks defined in /gradle/tasks + */ +fun Project.installCustomTasks() { + val tasksDir = File("$rootDir/gradle/tasks") + if (tasksDir.exists() && tasksDir.isDirectory) { + tasksDir.listFiles { file -> file.extension == "kts" }?.forEach { file -> apply(from = file) } + } +} diff --git a/core/bluetooth/build.gradle.kts b/core/bluetooth/build.gradle.kts index b1eb3cfd5..379ecaf65 100644 --- a/core/bluetooth/build.gradle.kts +++ b/core/bluetooth/build.gradle.kts @@ -10,4 +10,4 @@ android { dependencies { implementation(project(":core:utils")) implementation(project(":core:coroutines")) -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/BloodPressureMapper.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/BloodPressureMapper.kt index 9025fb677..54409a1bb 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/BloodPressureMapper.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/BloodPressureMapper.kt @@ -1,3 +1,4 @@ +@file:Suppress("MagicNumber") package edu.stanford.spezi.core.bluetooth.data.mapper import android.bluetooth.BluetoothGattCharacteristic @@ -78,4 +79,4 @@ internal class BloodPressureMapper @Inject constructor() : MeasurementMapper.Chi measurementStatus = measurementStatus ) } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/MeasurementMapper.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/MeasurementMapper.kt index 95c170420..a489a806e 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/MeasurementMapper.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/MeasurementMapper.kt @@ -61,4 +61,4 @@ internal class MeasurementMapperImpl @Inject constructor( override suspend fun map(characteristic: BluetoothGattCharacteristic?, data: ByteArray): Measurement? = withContext(ioDispatcher) { children.find { it.recognises(characteristic) }?.map(characteristic, data) } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/WeightMeasurementMapper.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/WeightMeasurementMapper.kt index 3f7c80c2a..64a3cb2b4 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/WeightMeasurementMapper.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/WeightMeasurementMapper.kt @@ -1,3 +1,4 @@ +@file:Suppress("MagicNumber") package edu.stanford.spezi.core.bluetooth.data.mapper import android.bluetooth.BluetoothGattCharacteristic @@ -35,10 +36,9 @@ internal class WeightMeasurementMapper @Inject constructor() : MeasurementMapper return if (recognises(characteristic).not()) null else runCatching { interpretWeightMeasurement(data) }.getOrNull() } - private fun interpretWeightMeasurement(data: ByteArray): Measurement.Weight { val flags = data[0] - val unitKg = (flags and 0b00000001).toInt() == 0 // Check if bit 0 is 0 for kg, 1 for lb + val unitKg = (flags and 0b00000001).toInt() == 0 // Check if bit 0 is 0 for kg, 1 for lb val weight = if (unitKg) { // Kilograms, resolution of 0.005 kg @@ -49,26 +49,30 @@ internal class WeightMeasurementMapper @Inject constructor() : MeasurementMapper } val zonedDateTime = if (flags and 0b00000010 > 0) { - val year = data[3].toInt() and 0xFF or (data[4].toInt() and 0xFF shl 8) val month = data[5].toInt() val day = data[6].toInt() val hour = data[7].toInt() val minute = data[8].toInt() val second = data[9].toInt() - if (year == 0 || month == 0 || day == 0) null - else { + if (year == 0 || month == 0 || day == 0) { + null + } else { val localDateTime = LocalDateTime.of(year, month, day, hour, minute, second) val zoneId = ZoneId.systemDefault() ZonedDateTime.of(localDateTime, zoneId) } - } else null + } else { + null + } val userId = if (flags and 0b00000100 > 0) data[10].toInt() else null - val bmi = - if (flags and 0b00001000 > 0) (data[11].toInt() and 0xFF or (data[12].toInt() and 0xFF shl 8)) * 0.1 else null - val height = - if (flags and 0b00001000 > 0) (data[13].toInt() and 0xFF or (data[14].toInt() and 0xFF shl 8)) * (if (unitKg) 0.005 else 0.1) else null + val bmi = if (flags and 0b00001000 > 0) (data[11].toInt() and 0xFF or (data[12].toInt() and 0xFF shl 8)) * 0.1 else null + val height = if (flags and 0b00001000 > 0) { + (data[13].toInt() and 0xFF or (data[14].toInt() and 0xFF shl 8)) * (if (unitKg) 0.005 else 0.1) + } else { + null + } return Measurement.Weight( weight = weight, @@ -78,4 +82,4 @@ internal class WeightMeasurementMapper @Inject constructor() : MeasurementMapper height = height ) } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEDeviceSession.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEDeviceSession.kt index e7ff1df27..602afd9e7 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEDeviceSession.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEDeviceSession.kt @@ -12,5 +12,5 @@ import android.bluetooth.BluetoothDevice */ data class BLEDeviceSession( val device: BluetoothDevice, - val measurements: List -) \ No newline at end of file + val measurements: List, +) diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceEvent.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceEvent.kt index ac4cabaa3..30ebfd5be 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceEvent.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceEvent.kt @@ -59,4 +59,4 @@ sealed interface BLEServiceEvent { * @property measurement The measurement received from the device. */ data class MeasurementReceived(val device: BluetoothDevice, val measurement: Measurement) : BLEServiceEvent -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceState.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceState.kt index 601f64855..67fd72bbb 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceState.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceState.kt @@ -18,4 +18,4 @@ sealed interface BLEServiceState { * @property sessions The list of BLE device sessions being scanned. */ data class Scanning(val sessions: List) : BLEServiceState -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceType.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceType.kt index 0222b0fda..ee0d67c3f 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceType.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceType.kt @@ -15,7 +15,7 @@ internal enum class BLEServiceType( /** * The UUID of the characteristic associated with the BLE service. */ - val characteristic: UUID + val characteristic: UUID, ) { /** * Represents the Weight service. @@ -31,5 +31,5 @@ internal enum class BLEServiceType( BLOOD_PRESSURE( service = UUID("00001810-0000-1000-8000-00805f9b34fb"), characteristic = UUID("00002a35-0000-1000-8000-00805f9b34fb") - ) + ), } diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/Measurement.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/Measurement.kt index b048290df..87c21885a 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/Measurement.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/Measurement.kt @@ -23,7 +23,7 @@ sealed interface Measurement { val timeStampSecond: Int, // 0-59 val pulseRate: Float, // pulse rate value bpm val userId: Int, - val measurementStatus: Status + val measurementStatus: Status, ) : Measurement { /** @@ -34,7 +34,7 @@ sealed interface Measurement { val timeStampFlag: Boolean, // false: no timestamp, true: timestamp present val pulseRateFlag: Boolean, // false: no pulse rate, true: pulse rate present val userIdFlag: Boolean, // false: no user ID, true: user ID present - val measurementStatusFlag: Boolean // false: no measurement status, true: measurement status present + val measurementStatusFlag: Boolean, // false: no measurement status, true: measurement status present ) /** @@ -45,7 +45,7 @@ sealed interface Measurement { val cuffFitDetectionFlag: Boolean, // 0: fit properly, 1: too loose val irregularPulseDetectionFlag: Boolean, // 0: no irregular pulse detected, 1: irregular pulse detected val pulseRateRangeDetectionFlags: Int, // - always 0 - val measurementPositionDetectionFlag: Boolean // false: proper, true: improper + val measurementPositionDetectionFlag: Boolean, // false: proper, true: improper ) } @@ -57,6 +57,6 @@ sealed interface Measurement { val zonedDateTime: ZonedDateTime?, val userId: Int?, val bmi: Double?, - val height: Double? + val height: Double?, ) : Measurement } diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/SupportedServices.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/SupportedServices.kt index c447d96c0..4f7a3d446 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/SupportedServices.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/data/model/SupportedServices.kt @@ -5,4 +5,4 @@ package edu.stanford.spezi.core.bluetooth.data.model * * @param services The list of supported BLE service types. */ -internal class SupportedServices(services: List): List by services +internal class SupportedServices(services: List) : List by services diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/di/BluetoothModule.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/di/BluetoothModule.kt index 906ee88eb..1b7b5a8ff 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/di/BluetoothModule.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/di/BluetoothModule.kt @@ -68,4 +68,4 @@ class BluetoothModule { @Binds internal abstract fun bindSpeziBLEService(impl: BLEServiceImpl): BLEService } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceConnector.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceConnector.kt index 6f2dcee55..a0d5486e8 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceConnector.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceConnector.kt @@ -134,4 +134,4 @@ internal class BLEDeviceConnector @AssistedInject constructor( private companion object { val DESCRIPTOR_UUID = UUID("00002902-0000-1000-8000-00805f9b34fb") } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceScanner.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceScanner.kt index 0b4631462..615755475 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceScanner.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceScanner.kt @@ -103,7 +103,7 @@ internal class BLEDeviceScanner @Inject constructor( /** * Event indicating that a BLE device was found during scanning. */ - data class DeviceFound(val device: BluetoothDevice): Event + data class DeviceFound(val device: BluetoothDevice) : Event /** * Event indicating a failure during scanning. @@ -111,4 +111,4 @@ internal class BLEDeviceScanner @Inject constructor( */ data class Failure(val errorCode: Int) : Event } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEServiceImpl.kt b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEServiceImpl.kt index b434e8feb..2f8d281d6 100644 --- a/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEServiceImpl.kt +++ b/core/bluetooth/src/main/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEServiceImpl.kt @@ -184,4 +184,4 @@ internal class BLEServiceImpl @Inject constructor( Manifest.permission.BLUETOOTH_SCAN, ) } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/BloodPressureMapperTest.kt b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/BloodPressureMapperTest.kt index 62f6fab67..fd185a9f4 100644 --- a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/BloodPressureMapperTest.kt +++ b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/BloodPressureMapperTest.kt @@ -118,4 +118,4 @@ class BloodPressureMapperTest { // then assertThat(result).isNull() } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/MeasurementMapperTest.kt b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/MeasurementMapperTest.kt index 02875fed0..d0707d32b 100644 --- a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/MeasurementMapperTest.kt +++ b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/MeasurementMapperTest.kt @@ -72,4 +72,4 @@ class MeasurementMapperTest { // then assertThat(result).isEqualTo(measurement) } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/WeightMeasurementMapperTest.kt b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/WeightMeasurementMapperTest.kt index 51bb929e7..40e33312b 100644 --- a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/WeightMeasurementMapperTest.kt +++ b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/mapper/WeightMeasurementMapperTest.kt @@ -90,4 +90,4 @@ class WeightMeasurementMapperTest { // then assertThat(result).isNull() } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceTypeTest.kt b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceTypeTest.kt index 7e1a92962..1f98be489 100644 --- a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceTypeTest.kt +++ b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/data/model/BLEServiceTypeTest.kt @@ -32,4 +32,4 @@ class BLEServiceTypeTest { assertThat(service.toString()).isEqualTo("00001810-0000-1000-8000-00805f9b34fb") assertThat(characteristic.toString()).isEqualTo("00002a35-0000-1000-8000-00805f9b34fb") } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceConnectorTest.kt b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceConnectorTest.kt index c032c65e4..e85879b7b 100644 --- a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceConnectorTest.kt +++ b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceConnectorTest.kt @@ -197,4 +197,4 @@ class BLEDeviceConnectorTest { private suspend fun assertEvent(event: BLEServiceEvent) { assertThat(bleDeviceConnector.events.first()).isEqualTo(event) } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceScannerTest.kt b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceScannerTest.kt index 6028c9852..e93765535 100644 --- a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceScannerTest.kt +++ b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEDeviceScannerTest.kt @@ -172,4 +172,4 @@ class BLEDeviceScannerTest { verify { bluetoothLeScanner.startScan(any>(), any(), capture(callbackSlot)) } return callbackSlot.captured } -} \ No newline at end of file +} diff --git a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEServiceTest.kt b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEServiceTest.kt index 23da54342..226539859 100644 --- a/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEServiceTest.kt +++ b/core/bluetooth/src/test/kotlin/edu/stanford/spezi/core/bluetooth/domain/BLEServiceTest.kt @@ -258,4 +258,4 @@ class BLEServiceTest { private fun assertState(state: BLEServiceState) { assertThat(bleService.state.value).isEqualTo(state) } -} \ No newline at end of file +} diff --git a/core/coroutines/build.gradle.kts b/core/coroutines/build.gradle.kts index da2ca8997..b2613fd50 100644 --- a/core/coroutines/build.gradle.kts +++ b/core/coroutines/build.gradle.kts @@ -9,4 +9,4 @@ android { dependencies { api(libs.bundles.ktx.coroutines) -} \ No newline at end of file +} diff --git a/core/coroutines/src/main/kotlin/edu/stanford/spezi/core/coroutines/DispatchersProvider.kt b/core/coroutines/src/main/kotlin/edu/stanford/spezi/core/coroutines/DispatchersProvider.kt index 9c98720db..2702e61e7 100644 --- a/core/coroutines/src/main/kotlin/edu/stanford/spezi/core/coroutines/DispatchersProvider.kt +++ b/core/coroutines/src/main/kotlin/edu/stanford/spezi/core/coroutines/DispatchersProvider.kt @@ -77,4 +77,4 @@ internal class DispatchersProviderImpl @Inject constructor() : DispatchersProvid * @return The unconfined [CoroutineDispatcher] from [Dispatchers.Unconfined]. */ override fun unconfined(): CoroutineDispatcher = Dispatchers.Unconfined -} \ No newline at end of file +} diff --git a/core/coroutines/src/main/kotlin/edu/stanford/spezi/core/coroutines/di/CoroutinesModule.kt b/core/coroutines/src/main/kotlin/edu/stanford/spezi/core/coroutines/di/CoroutinesModule.kt index 6e214ed81..3f42b3434 100644 --- a/core/coroutines/src/main/kotlin/edu/stanford/spezi/core/coroutines/di/CoroutinesModule.kt +++ b/core/coroutines/src/main/kotlin/edu/stanford/spezi/core/coroutines/di/CoroutinesModule.kt @@ -175,5 +175,7 @@ class CoroutinesModule { * @return The [CoroutineScope] instance. */ @VisibleForTesting - internal fun buildCoroutine(dispatcher: CoroutineDispatcher) = CoroutineScope(context = dispatcher + SupervisorJob()) + internal fun buildCoroutine( + dispatcher: CoroutineDispatcher, + ): CoroutineScope = CoroutineScope(context = dispatcher + SupervisorJob()) } diff --git a/core/coroutines/src/test/kotlin/edu/stanford/spezi/core/coroutines/di/CoroutinesModuleTest.kt b/core/coroutines/src/test/kotlin/edu/stanford/spezi/core/coroutines/di/CoroutinesModuleTest.kt index bb4d3e7c9..cbc1f753e 100644 --- a/core/coroutines/src/test/kotlin/edu/stanford/spezi/core/coroutines/di/CoroutinesModuleTest.kt +++ b/core/coroutines/src/test/kotlin/edu/stanford/spezi/core/coroutines/di/CoroutinesModuleTest.kt @@ -126,4 +126,4 @@ class CoroutinesModuleTest { assertThat(result).isEqualTo(coroutineScope) verify { sut.buildCoroutine(dispatcher) } } -} \ No newline at end of file +} diff --git a/core/design/build.gradle.kts b/core/design/build.gradle.kts index a8d811114..919e7347f 100644 --- a/core/design/build.gradle.kts +++ b/core/design/build.gradle.kts @@ -25,4 +25,4 @@ dependencies { debugImplementation(libs.compose.ui.tooling) debugImplementation(libs.compose.ui.test.manifest) -} \ No newline at end of file +} diff --git a/core/design/src/androidTest/kotlin/edu/stanford/spezi/core/design/ExampleInstrumentedTest.kt b/core/design/src/androidTest/kotlin/edu/stanford/spezi/core/design/ExampleInstrumentedTest.kt deleted file mode 100644 index 71113246c..000000000 --- a/core/design/src/androidTest/kotlin/edu/stanford/spezi/core/design/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package edu.stanford.spezi.core.design - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("edu.stanford.spezi.core.design.test", appContext.packageName) - } -} \ No newline at end of file diff --git a/core/design/src/androidTest/kotlin/edu/stanford/spezi/core/design/SpeziButtonKtTest.kt b/core/design/src/androidTest/kotlin/edu/stanford/spezi/core/design/SpeziButtonKtTest.kt index 477587615..e56dbbde1 100644 --- a/core/design/src/androidTest/kotlin/edu/stanford/spezi/core/design/SpeziButtonKtTest.kt +++ b/core/design/src/androidTest/kotlin/edu/stanford/spezi/core/design/SpeziButtonKtTest.kt @@ -84,4 +84,4 @@ class SpeziButtonKtTest { assert(clicked) } -} \ No newline at end of file +} diff --git a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/component/SpeziButton.kt b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/component/SpeziButton.kt index 48bcdfe27..9677945d0 100644 --- a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/component/SpeziButton.kt +++ b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/component/SpeziButton.kt @@ -58,4 +58,3 @@ fun SpeziButtonDarkPreview() { } } } - diff --git a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Colors.kt b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Colors.kt index afaf8d88d..c11cb3ddc 100644 --- a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Colors.kt +++ b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Colors.kt @@ -41,7 +41,6 @@ object Colors { @ReadOnlyComposable get() = scheme.onPrimary - val onSecondary @Composable @ReadOnlyComposable @@ -52,7 +51,6 @@ object Colors { @ReadOnlyComposable get() = scheme.onTertiary - val onBackground @Composable @ReadOnlyComposable @@ -79,4 +77,4 @@ internal val Black40 = Color(0xFFABABA9) internal val Black20 = Color(0xFFD5D5D4) internal val Black10 = Color(0xFFEAEAEA) -internal val RectangleBlue = Color(0xFFEBF2FC) \ No newline at end of file +internal val RectangleBlue = Color(0xFFEBF2FC) diff --git a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Sizes.kt b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Sizes.kt index 0dfdcd96c..c82e4e473 100644 --- a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Sizes.kt +++ b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Sizes.kt @@ -10,4 +10,4 @@ object Sizes { @Composable @ReadOnlyComposable get() = 48.dp -} \ No newline at end of file +} diff --git a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Spacings.kt b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Spacings.kt index 6e58fc1a7..79ecea13c 100644 --- a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Spacings.kt +++ b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/Spacings.kt @@ -20,4 +20,4 @@ object Spacings { @Composable @ReadOnlyComposable get() = 24.dp -} \ No newline at end of file +} diff --git a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/SpeziKtTheme.kt b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/SpeziKtTheme.kt index 1882edcb0..1d9801ac6 100644 --- a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/SpeziKtTheme.kt +++ b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/SpeziKtTheme.kt @@ -52,7 +52,7 @@ private val LightColorScheme = lightColorScheme( fun SpeziTheme( darkTheme: Boolean = isSystemInDarkTheme(), dynamicColor: Boolean = true, - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { val colorScheme = when { dynamicColor -> { @@ -85,4 +85,4 @@ fun SpeziTheme( typography = typography, content = surface ) -} \ No newline at end of file +} diff --git a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/TextStyles.kt b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/TextStyles.kt index 870f4d5c6..4d7a64aa8 100644 --- a/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/TextStyles.kt +++ b/core/design/src/main/kotlin/edu/stanford/spezi/core/design/theme/TextStyles.kt @@ -129,4 +129,4 @@ private fun TypographyPreview() { ) } } -} \ No newline at end of file +} diff --git a/core/design/src/test/kotlin/edu/stanford/spezi/core/design/ExampleUnitTest.kt b/core/design/src/test/kotlin/edu/stanford/spezi/core/design/ExampleUnitTest.kt index 15c29f4ed..c5ef9e08d 100644 --- a/core/design/src/test/kotlin/edu/stanford/spezi/core/design/ExampleUnitTest.kt +++ b/core/design/src/test/kotlin/edu/stanford/spezi/core/design/ExampleUnitTest.kt @@ -13,4 +13,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/core/logging/build.gradle.kts b/core/logging/build.gradle.kts index e67ea28dd..5a8a29af9 100644 --- a/core/logging/build.gradle.kts +++ b/core/logging/build.gradle.kts @@ -11,4 +11,4 @@ android { dependencies { implementation(libs.timber) testImplementation(libs.bundles.unit.testing) -} \ No newline at end of file +} diff --git a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/Api.kt b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/Api.kt index 12a4eaf85..555bd95c8 100644 --- a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/Api.kt +++ b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/Api.kt @@ -46,5 +46,5 @@ fun groupLogger(tag: String, config: LoggerConfig.() -> Unit = {}) = object : Re */ fun speziLogger( tag: String, - config: LoggerConfig.() -> Unit = {} + config: LoggerConfig.() -> Unit = {}, ) = lazy { SpeziLogger(tag, LoggerConfig().apply(config)) } diff --git a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/SpeziLogger.kt b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/SpeziLogger.kt index 120174c6e..3452ea7dd 100644 --- a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/SpeziLogger.kt +++ b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/SpeziLogger.kt @@ -185,4 +185,4 @@ class SpeziLogger internal constructor(private val tag: String, private val conf _IS_LOGGING_ENABLED.set(enabled) } } -} \ No newline at end of file +} diff --git a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/LogLogger.kt b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/LogLogger.kt index 38395e074..e9f3bc7fd 100644 --- a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/LogLogger.kt +++ b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/LogLogger.kt @@ -27,4 +27,4 @@ internal class LogLogger( override fun e(throwable: Throwable?, message: () -> String) { Log.d(getCurrentTag(), getMessage(message), throwable) } -} \ No newline at end of file +} diff --git a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/PrintLogger.kt b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/PrintLogger.kt index a908997cd..17e543d13 100644 --- a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/PrintLogger.kt +++ b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/PrintLogger.kt @@ -31,9 +31,9 @@ internal class PrintLogger( ) = buildString { append("($level) ") append("${getCurrentTag()} - ") - append(getMessage(message) ) + append(getMessage(message)) throwable?.let { append(" Error: $it") } } -} \ No newline at end of file +} diff --git a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/TimberLogger.kt b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/TimberLogger.kt index 94767851c..2cf63c3d5 100644 --- a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/TimberLogger.kt +++ b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/TimberLogger.kt @@ -36,4 +36,4 @@ internal class TimberLogger( if (PLANTED_DEBUG_TREE.getAndSet(true).not()) Timber.plant(Timber.DebugTree()) } } -} \ No newline at end of file +} diff --git a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/_Logger.kt b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/_Logger.kt index 2aa2b03dc..7cd5d0c58 100644 --- a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/_Logger.kt +++ b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/internal/_Logger.kt @@ -11,6 +11,7 @@ import edu.stanford.spezi.core.logging.SpeziLogger * of [SpeziLogger] which requires it to be visible outside of the component for the inline function to access it. * @see [SpeziLogger] for the reasoning behind inline functions. */ +@Suppress("ClassNaming") sealed interface _Logger { val tag: String val messagePrefix: String? @@ -66,4 +67,4 @@ internal fun _Logger.getMessage(message: () -> String) = if (messagePrefix != nu "$messagePrefix - ${message()}" } else { message() -} \ No newline at end of file +} diff --git a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/models/LoggerConfig.kt b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/models/LoggerConfig.kt index 453fcfbc2..b428e1cc6 100644 --- a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/models/LoggerConfig.kt +++ b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/models/LoggerConfig.kt @@ -38,4 +38,3 @@ class LoggerConfig internal constructor() { SpeziLogger.GLOBAL_CONFIG?.invoke(this) } } - diff --git a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/models/LoggingStrategy.kt b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/models/LoggingStrategy.kt index 072efa47c..33316206f 100644 --- a/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/models/LoggingStrategy.kt +++ b/core/logging/src/main/kotlin/edu/stanford/spezi/core/logging/models/LoggingStrategy.kt @@ -19,5 +19,5 @@ enum class LoggingStrategy { /** * The logging strategy that logs messages using the Log utility. */ - LOG -} \ No newline at end of file + LOG, +} diff --git a/core/logging/src/test/kotlin/edu/stanford/spezi/core/logging/SpeziLoggerTest.kt b/core/logging/src/test/kotlin/edu/stanford/spezi/core/logging/SpeziLoggerTest.kt index 431713837..6d1373a48 100644 --- a/core/logging/src/test/kotlin/edu/stanford/spezi/core/logging/SpeziLoggerTest.kt +++ b/core/logging/src/test/kotlin/edu/stanford/spezi/core/logging/SpeziLoggerTest.kt @@ -9,4 +9,4 @@ class SpeziLoggerTest { fun `GLOBAL_CONFIG must be set to null`() { assertThat(SpeziLogger.GLOBAL_CONFIG).isNull() } -} \ No newline at end of file +} diff --git a/core/testing/build.gradle.kts b/core/testing/build.gradle.kts index c71b82acc..4d103c57c 100644 --- a/core/testing/build.gradle.kts +++ b/core/testing/build.gradle.kts @@ -11,4 +11,4 @@ android { dependencies { implementation(project(":core:coroutines")) api(libs.bundles.unit.testing) -} \ No newline at end of file +} diff --git a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/CoroutineTestRule.kt b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/CoroutineTestRule.kt index 5f571bc27..60f6aed2f 100644 --- a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/CoroutineTestRule.kt +++ b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/CoroutineTestRule.kt @@ -37,7 +37,7 @@ import org.junit.runner.Description * */ class CoroutineTestRule( - private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher() + private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), ) : TestWatcher() { /** @@ -57,4 +57,4 @@ class CoroutineTestRule( override fun finished(description: Description?) { Dispatchers.resetMain() } -} \ No newline at end of file +} diff --git a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/Mockk.kt b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/Mockk.kt index 75c3e1836..73b85879f 100644 --- a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/Mockk.kt +++ b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/Mockk.kt @@ -19,7 +19,6 @@ import io.mockk.verify */ fun verifyNever(verifyBlock: MockKVerificationScope.() -> Unit) = verify(exactly = 0, verifyBlock = verifyBlock) - /** * Verifies that a specific interaction with a mock object in a coroutine context never occurred. * @@ -33,4 +32,6 @@ fun verifyNever(verifyBlock: MockKVerificationScope.() -> Unit) = verify(exactly * * @param verifyBlock The suspendable block of code containing the interaction to verify. */ -fun coVerifyNever(verifyBlock: suspend MockKVerificationScope.() -> Unit) = coVerify(exactly = 0, verifyBlock = verifyBlock) +fun coVerifyNever( + verifyBlock: suspend MockKVerificationScope.() -> Unit, +) = coVerify(exactly = 0, verifyBlock = verifyBlock) diff --git a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/RunTest.kt b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/RunTest.kt index 1e1068ba2..6501166c0 100644 --- a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/RunTest.kt +++ b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/RunTest.kt @@ -26,4 +26,4 @@ import kotlinx.coroutines.test.runTest * @param testBody The suspending function containing the test code to be executed. */ fun runTestUnconfined(testBody: suspend TestScope.() -> Unit) = - runTest(context = UnconfinedTestDispatcher(), testBody = testBody) \ No newline at end of file + runTest(context = UnconfinedTestDispatcher(), testBody = testBody) diff --git a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/SpeziTestScope.kt b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/SpeziTestScope.kt index 027d31268..a9a3fbde8 100644 --- a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/SpeziTestScope.kt +++ b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/SpeziTestScope.kt @@ -21,4 +21,5 @@ import kotlin.coroutines.CoroutineContext * } * ``` */ -fun SpeziTestScope(context: CoroutineContext = UnconfinedTestDispatcher()): TestScope = TestScope(context = context) \ No newline at end of file +@Suppress("FunctionNaming") +fun SpeziTestScope(context: CoroutineContext = UnconfinedTestDispatcher()): TestScope = TestScope(context = context) diff --git a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/TestDispatchersProvider.kt b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/TestDispatchersProvider.kt index 389b44933..b8be01837 100644 --- a/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/TestDispatchersProvider.kt +++ b/core/testing/src/main/kotlin/edu/stanford/spezi/core/testing/TestDispatchersProvider.kt @@ -12,7 +12,7 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher * @property testDispatcher The [CoroutineDispatcher] to be used for all dispatcher contexts. Defaults to [UnconfinedTestDispatcher]. */ class TestDispatchersProvider( - private val testDispatcher: CoroutineDispatcher = UnconfinedTestDispatcher() + private val testDispatcher: CoroutineDispatcher = UnconfinedTestDispatcher(), ) : DispatchersProvider { /** diff --git a/core/utils/build.gradle.kts b/core/utils/build.gradle.kts index 89b0c2bf0..1c0364848 100644 --- a/core/utils/build.gradle.kts +++ b/core/utils/build.gradle.kts @@ -10,4 +10,4 @@ dependencies { val composeBom = platform(libs.compose.bom) implementation(composeBom) implementation(libs.compose.runtime) -} \ No newline at end of file +} diff --git a/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/Typealiases.kt b/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/Typealiases.kt index 8ea37bfd6..895b4b501 100644 --- a/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/Typealiases.kt +++ b/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/Typealiases.kt @@ -1,3 +1,4 @@ +@file:Suppress("Filename") package edu.stanford.spezi.core.utils import androidx.compose.runtime.Composable @@ -22,4 +23,4 @@ import androidx.compose.runtime.Composable * } * ``` */ -typealias ComposableBlock = @Composable () -> Unit \ No newline at end of file +typealias ComposableBlock = @Composable () -> Unit diff --git a/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/UUID.kt b/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/UUID.kt index c1f182bfc..c5da7f320 100644 --- a/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/UUID.kt +++ b/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/UUID.kt @@ -9,4 +9,4 @@ import java.util.UUID * @return The [UUID] instance parsed from the string. * @throws IllegalArgumentException if the specified string does not conform to the string representation format. */ -fun UUID(string: String): UUID = UUID.fromString(string) \ No newline at end of file +fun UUID(string: String): UUID = UUID.fromString(string) diff --git a/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/extensions/List.kt b/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/extensions/List.kt index f865d95ad..882203970 100644 --- a/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/extensions/List.kt +++ b/core/utils/src/main/kotlin/edu/stanford/spezi/core/utils/extensions/List.kt @@ -6,4 +6,4 @@ package edu.stanford.spezi.core.utils.extensions * @param item The item to append to the list. If null, it will not be added. * @return A new list containing the original items and the appended item, if not null. */ -fun List.append(item: T?): List = this + listOfNotNull(item) \ No newline at end of file +fun List.append(item: T?): List = this + listOfNotNull(item) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94846ab13..9b4cd5842 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ composeBom = "2024.05.00" coreKtx = "1.13.1" coreTestingVersion = "2.2.0" coroutinesVersion = "1.8.0" +detekt = "1.23.6" # please adjust github action version as well in case of version change dokka = "1.9.20" espressoCore = "3.5.1" hiltNavigation = "1.2.0" @@ -49,6 +50,7 @@ compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutinesVersion" } coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutinesVersion" } coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutinesVersion" } +detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } google-truth = { group = "com.google.truth", name = "truth", version.ref = "truth" } hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hiltVersion" } hilt-core = { group = "com.google.dagger", name = "hilt-android", version.ref = "hiltVersion" } @@ -69,6 +71,7 @@ timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "tim android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } google-devtools-ksp = { id = "com.google.devtools.ksp", version.ref = "kspVersion" } hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hiltVersion" } @@ -84,4 +87,4 @@ spezi-library = { id = "spezi.library", version = "unspecified" } compose = ["compose-ui", "compose-material3", "compose-ui-tooling-preview", "compose-ui-tooling", "androidx-core-ktx", "androidx-appcompat", "androidx-activity-compose"] compose-androidTest = ["junit", "androidx-espresso-core", "compose-ui-test", "mockk-agent-core", "mockk-android", "google-truth"] ktx-coroutines = ["coroutines-core", "coroutines-android"] -unit-testing = ["junit", "mockk-core", "google-truth", "coroutines-test", "androidx-core-testing"] \ No newline at end of file +unit-testing = ["junit", "mockk-core", "google-truth", "coroutines-test", "androidx-core-testing"] diff --git a/gradle/tasks/git-hooks.gradle.kts b/gradle/tasks/git-hooks.gradle.kts new file mode 100644 index 000000000..25e8115ee --- /dev/null +++ b/gradle/tasks/git-hooks.gradle.kts @@ -0,0 +1,25 @@ +import org.gradle.api.tasks.Copy + +/** + * A gradle task that registers the git hooks from internal/git-hooks to the .git folder + */ +val installGitHooks by tasks.registering(Copy::class) { + group = "spezi" + description = "Copies and installs the git hooks from internal/git-hooks to the .git folder." + + val gitHooksDir = file("$rootDir/.git/hooks") + + from("$rootDir/internal/git-hooks/") { + include("**/*.sh") + rename("(.*).sh", "$1") + } + + into(gitHooksDir) + + doLast { + gitHooksDir.listFiles()?.forEach { file -> + file.setExecutable(true) + logger.info("Git hook ${file.name} copied and installed successfully.") + } + } +} diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/internal/detekt-config.yml b/internal/detekt-config.yml new file mode 100644 index 000000000..79fbe0f0b --- /dev/null +++ b/internal/detekt-config.yml @@ -0,0 +1,756 @@ +build: + maxIssues: 0 + excludeCorrectable: false + weights: + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 + excludes: ['**/*.kts'] + +config: + validation: true + warningsAsErrors: true + # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' + excludes: '' + +processors: + active: true + exclude: + - 'DetektProgressListener' + # - 'KtFileCountProcessor' + # - 'PackageCountProcessor' + # - 'ClassCountProcessor' + # - 'FunctionCountProcessor' + # - 'PropertyCountProcessor' + # - 'ProjectComplexityProcessor' + # - 'ProjectCognitiveComplexityProcessor' + # - 'ProjectLLOCProcessor' + # - 'ProjectCLOCProcessor' + # - 'ProjectLOCProcessor' + # - 'ProjectSLOCProcessor' + # - 'LicenseHeaderLoaderExtension' + +console-reports: + active: true + exclude: + - 'ProjectStatisticsReport' + - 'ComplexityReport' + - 'NotificationReport' + # - 'FindingsReport' + - 'FileBasedFindingsReport' + +output-reports: + active: true + exclude: + # - 'TxtOutputReport' + # - 'XmlOutputReport' + # - 'HtmlOutputReport' + +comments: + active: true + AbsentOrWrongFileLicense: + active: false + licenseTemplateFile: 'license.template' + licenseTemplateIsRegex: false + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + DeprecatedBlockTag: + active: false + EndOfSentenceFormat: + active: false + endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' + UndocumentedPublicClass: + active: false + searchInNestedClass: true + searchInInnerClass: true + searchInInnerObject: true + searchInInnerInterface: true + UndocumentedPublicFunction: + active: false + UndocumentedPublicProperty: + active: false + +complexity: + active: true + ComplexCondition: + active: true + threshold: 4 + ComplexInterface: + active: false + threshold: 10 + includeStaticDeclarations: false + includePrivateDeclarations: false + CyclomaticComplexMethod: + active: true + threshold: 15 + ignoreSingleWhenExpression: false + ignoreSimpleWhenEntries: false + ignoreNestingFunctions: false + nestingFunctions: + - 'also' + - 'apply' + - 'forEach' + - 'isNotNull' + - 'ifNull' + - 'let' + - 'run' + - 'use' + - 'with' + LabeledExpression: + active: false + ignoredLabels: [] + LargeClass: + active: true + threshold: 600 + LongMethod: + active: true + threshold: 60 + ignoreAnnotated: + - 'Composable' + LongParameterList: + active: true + functionThreshold: 7 + constructorThreshold: 7 + ignoreDefaultParameters: false + ignoreDataClasses: true + ignoreAnnotated: [] + excludes: ['**/test/**', '**/androidTest/**'] + MethodOverloading: + active: false + threshold: 6 + NamedArguments: + active: true + threshold: 3 + NestedBlockDepth: + active: true + threshold: 5 + ReplaceSafeCallChainWithRun: + active: false + StringLiteralDuplication: + active: false + excludes: ['**/test/**', '**/androidTest/**'] + threshold: 3 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + TooManyFunctions: + active: true + excludes: ['**/test/**', '**/androidTest/**'] + thresholdInFiles: 15 + thresholdInClasses: 15 + thresholdInInterfaces: 11 + thresholdInObjects: 11 + thresholdInEnums: 11 + ignoreDeprecated: false + ignorePrivate: false + ignoreOverridden: false + +coroutines: + active: true + GlobalCoroutineUsage: + active: false + RedundantSuspendModifier: + active: false + SleepInsteadOfDelay: + active: false + SuspendFunWithFlowReturnType: + active: false + +empty-blocks: + active: true + EmptyCatchBlock: + active: true + allowedExceptionNameRegex: '_|(ignore|expected).*' + EmptyClassBlock: + active: true + EmptyDefaultConstructor: + active: true + EmptyDoWhileBlock: + active: true + EmptyElseBlock: + active: true + EmptyFinallyBlock: + active: true + EmptyForBlock: + active: true + EmptyFunctionBlock: + active: true + ignoreOverridden: false + EmptyIfBlock: + active: true + EmptyInitBlock: + active: true + EmptyKtFile: + active: true + EmptySecondaryConstructor: + active: true + EmptyTryBlock: + active: true + EmptyWhenBlock: + active: true + EmptyWhileBlock: + active: true + +exceptions: + active: true + ExceptionRaisedInUnexpectedLocation: + active: true + methodNames: + - 'equals' + - 'finalize' + - 'hashCode' + - 'toString' + InstanceOfCheckForException: + active: false + excludes: ['**/test/**', '**/androidTest/**'] + NotImplementedDeclaration: + active: false + ObjectExtendsThrowable: + active: false + PrintStackTrace: + active: true + RethrowCaughtException: + active: true + ReturnFromFinally: + active: true + ignoreLabeled: false + SwallowedException: + active: true + ignoredExceptionTypes: + - 'InterruptedException' + - 'MalformedURLException' + - 'NumberFormatException' + - 'ParseException' + allowedExceptionNameRegex: '_|(ignore|expected).*' + ThrowingExceptionFromFinally: + active: true + ThrowingExceptionInMain: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: true + excludes: ['**/test/**', '**/androidTest/**'] + exceptions: + - 'ArrayIndexOutOfBoundsException' + - 'Exception' + - 'IllegalArgumentException' + - 'IllegalMonitorStateException' + - 'IllegalStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + ThrowingNewInstanceOfSameException: + active: true + TooGenericExceptionCaught: + active: true + excludes: ['**/test/**', '**/androidTest/**'] + exceptionNames: + - 'ArrayIndexOutOfBoundsException' + - 'Error' + - 'Exception' + - 'IllegalMonitorStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + allowedExceptionNameRegex: '_|(ignore|expected).*' + TooGenericExceptionThrown: + active: true + exceptionNames: + - 'Error' + - 'Exception' + - 'RuntimeException' + - 'Throwable' + +formatting: + active: true + android: true + autoCorrect: true + AnnotationOnSeparateLine: + active: false + autoCorrect: true + AnnotationSpacing: + active: false + autoCorrect: true + ArgumentListWrapping: + active: false + autoCorrect: true + indentSize: 4 + maxLineLength: 140 + ChainWrapping: + active: true + autoCorrect: true + CommentSpacing: + active: true + autoCorrect: true + EnumEntryNameCase: + active: false + autoCorrect: true + Filename: + active: true + FinalNewline: + active: true + autoCorrect: true + insertFinalNewLine: true + ImportOrdering: + active: true + autoCorrect: true + layout: '*,java.**,javax.**,kotlin.**,^' + Indentation: + active: true + autoCorrect: true + indentSize: 4 + MaximumLineLength: + active: true + maxLineLength: 140 + ignoreBackTickedIdentifier: false + ModifierOrdering: + active: true + autoCorrect: true + MultiLineIfElse: + active: true + autoCorrect: true + NoBlankLineBeforeRbrace: + active: true + autoCorrect: true + NoConsecutiveBlankLines: + active: true + autoCorrect: true + NoEmptyClassBody: + active: true + autoCorrect: true + NoEmptyFirstLineInMethodBlock: + active: true + autoCorrect: true + NoLineBreakAfterElse: + active: true + autoCorrect: true + NoLineBreakBeforeAssignment: + active: true + autoCorrect: true + NoMultipleSpaces: + active: true + autoCorrect: true + NoSemicolons: + active: true + autoCorrect: true + NoTrailingSpaces: + active: true + autoCorrect: true + NoUnitReturn: + active: true + autoCorrect: true + NoUnusedImports: + active: true + autoCorrect: true + NoWildcardImports: + active: true + PackageName: + active: true + autoCorrect: true + ParameterListWrapping: + active: true + autoCorrect: true + indentSize: 4 + maxLineLength: 120 + SpacingAroundAngleBrackets: + active: false + autoCorrect: true + SpacingAroundColon: + active: true + autoCorrect: true + SpacingAroundComma: + active: true + autoCorrect: true + SpacingAroundCurly: + active: true + autoCorrect: true + SpacingAroundDot: + active: true + autoCorrect: true + SpacingAroundDoubleColon: + active: true + autoCorrect: true + SpacingAroundKeyword: + active: true + autoCorrect: true + SpacingAroundOperators: + active: true + autoCorrect: true + SpacingAroundParens: + active: true + autoCorrect: true + SpacingAroundRangeOperator: + active: true + autoCorrect: true + SpacingAroundUnaryOperator: + active: true + autoCorrect: true + SpacingBetweenDeclarationsWithAnnotations: + active: true + autoCorrect: true + SpacingBetweenDeclarationsWithComments: + active: true + autoCorrect: true + StringTemplate: + active: true + autoCorrect: true + TrailingCommaOnDeclarationSite: + active: true + autoCorrect: true + +naming: + active: true + BooleanPropertyNaming: + active: false + allowedPattern: '^(is|has|are)' + ClassNaming: + active: true + classPattern: '[A-Z][a-zA-Z0-9]*' + ConstructorParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + privateParameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + EnumNaming: + active: true + enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' + ForbiddenClassName: + active: false + forbiddenName: [] + FunctionMaxLength: + active: false + maximumFunctionNameLength: 30 + FunctionMinLength: + active: false + minimumFunctionNameLength: 3 + FunctionNaming: + active: true + excludes: ['**/test/**', '**/androidTest/**'] + functionPattern: '([a-z][a-zA-Z0-9]*)|(`.*`)' + excludeClassPattern: '$^' + ignoreAnnotated: + - 'Composable' + FunctionParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + InvalidPackageDeclaration: + active: true + excludes: ['**/*.kts'] + rootPackage: '' + MatchingDeclarationName: + active: false + mustBeFirst: true + MemberNameEqualsClassName: + active: true + ignoreOverridden: true + NoNameShadowing: + active: false + NonBooleanPropertyPrefixedWithIs: + active: false + excludes: ['**/test/**', '**/androidTest/**'] + ObjectPropertyNaming: + active: true + excludes: ['**/test/**', '**/androidTest/**'] + 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 + packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' + TopLevelPropertyNaming: + active: true + excludes: ['**/test/**', '**/androidTest/**'] + constantPattern: '[A-Z][_A-Z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' + VariableMaxLength: + active: false + excludes: ['**/test/**', '**/androidTest/**'] + maximumVariableNameLength: 64 + VariableMinLength: + active: true + minimumVariableNameLength: 3 + VariableNaming: + active: true + variablePattern: '[a-z][A-Za-z0-9]*' + privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + +performance: + active: true + ArrayPrimitive: + active: true + ForEachOnRange: + active: true + SpreadOperator: + active: true + UnnecessaryTemporaryInstantiation: + active: true + +potential-bugs: + active: true + AvoidReferentialEquality: + active: false + forbiddenTypePatterns: + - 'kotlin.String' + CastToNullableType: + active: false + Deprecation: + active: false + DontDowncastCollectionTypes: + active: false + DoubleMutabilityForCollection: + active: false + EqualsAlwaysReturnsTrueOrFalse: + active: true + EqualsWithHashCodeExist: + active: true + ExitOutsideMain: + active: false + ExplicitGarbageCollectionCall: + active: true + HasPlatformType: + active: false + IgnoredReturnValue: + active: false + restrictToConfig: true + returnValueAnnotations: + - '*.CheckResult' + - '*.CheckReturnValue' + ignoreReturnValueAnnotations: + - '*.CanIgnoreReturnValue' + ImplicitDefaultLocale: + active: true + ImplicitUnitReturnType: + active: false + allowExplicitReturnType: true + InvalidRange: + active: true + IteratorHasNextCallsNextMethod: + active: true + IteratorNotThrowingNoSuchElementException: + active: true + LateinitUsage: + active: false + excludes: ['**/test/**', '**/androidTest/**'] + ignoreAnnotated: [] + ignoreOnClassesPattern: '' + MapGetWithNotNullAssertionOperator: + active: false + NullableToStringCall: + active: false + UnconditionalJumpStatementInLoop: + active: false + UnnecessaryNotNullOperator: + active: true + UnnecessarySafeCall: + active: true + UnreachableCatchBlock: + active: false + UnreachableCode: + active: true + UnsafeCallOnNullableType: + active: true + UnsafeCast: + active: true + UnusedUnaryOperator: + active: false + UselessPostfixExpression: + active: false + WrongEqualsTypeParameter: + active: true + +style: + active: true + ClassOrdering: + active: false + CollapsibleIfStatements: + active: false + DataClassContainsFunctions: + active: false + conversionFunctionPrefix: ['to'] + DataClassShouldBeImmutable: + active: false + DestructuringDeclarationWithTooManyEntries: + active: false + maxDestructuringEntries: 3 + EqualsNullCall: + active: true + EqualsOnSignatureLine: + active: false + ExplicitCollectionElementAccessMethod: + active: false + ExplicitItLambdaParameter: + active: false + ExpressionBodySyntax: + active: false + includeLineWrapping: false + ForbiddenComment: + active: true + comments: ['FIXME:','STOPSHIP:'] + allowedPatterns: '' + ForbiddenImport: + active: false + imports: [] + forbiddenPatterns: [''] + ForbiddenMethodCall: + active: false + methods: + - 'kotlin.io.print' + - 'kotlin.io.println' + ForbiddenVoid: + active: false + ignoreOverridden: false + ignoreUsageInGenerics: false + FunctionOnlyReturningConstant: + active: true + ignoreOverridableFunction: true + ignoreActualFunction: true + excludedFunctions: [] + ignoreAnnotated: ['dagger.Provides'] + LoopWithTooManyJumpStatements: + active: true + maxJumpCount: 1 + MagicNumber: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/theme/**'] + ignoreNumbers: + - '-1' + - '0' + - '1' + - '2' + ignoreHashCodeFunction: true + ignorePropertyDeclaration: false + ignoreLocalVariableDeclaration: false + ignoreConstantDeclaration: true + ignoreCompanionObjectPropertyDeclaration: true + ignoreAnnotation: false + ignoreNamedArgument: true + ignoreEnums: false + ignoreRanges: false + ignoreExtensionFunctions: true + MandatoryBracesLoops: + active: false + MaxLineLength: + active: true + maxLineLength: 140 + excludePackageStatements: true + excludeImportStatements: true + excludeCommentStatements: false + MayBeConst: + active: true + ModifierOrder: + active: true + MultilineLambdaItParameter: + active: false + NestedClassesVisibility: + active: true + NewLineAtEndOfFile: + active: true + NoTabs: + active: false + NullableBooleanCheck: + active: true + ObjectLiteralToLambda: + active: false + OptionalAbstractKeyword: + active: true + OptionalUnit: + active: false + PreferToOverPairSyntax: + active: false + ProtectedMemberInFinalClass: + active: true + RedundantExplicitType: + active: false + RedundantHigherOrderMapUsage: + active: false + RedundantVisibilityModifierRule: + active: false + ReturnCount: + active: true + max: 3 + excludedFunctions: ['equals'] + excludeLabeled: false + excludeReturnFromLambda: true + excludeGuardClauses: false + SafeCast: + active: true + SerialVersionUIDInSerializableClass: + active: true + SpacingBetweenPackageAndImports: + active: false + ThrowsCount: + active: true + max: 2 + excludeGuardClauses: false + TrailingWhitespace: + active: false + UnderscoresInNumericLiterals: + active: false + acceptableLength: 5 + UnnecessaryAbstractClass: + active: true + ignoreAnnotated: ['dagger.Module'] + UnnecessaryAnnotationUseSiteTarget: + active: false + UnnecessaryApply: + active: true + UnnecessaryFilter: + active: false + UnnecessaryInheritance: + active: true + UnnecessaryLet: + active: false + UnnecessaryParentheses: + active: false + UntilInsteadOfRangeTo: + active: false + UnusedImports: + active: true + UnusedPrivateClass: + active: true + UnusedPrivateMember: + active: true + allowedNames: '(_|ignored|expected|serialVersionUID)' + ignoreAnnotated: ['Preview'] + UseArrayLiteralsInAnnotations: + active: false + UseCheckNotNull: + active: false + UseCheckOrError: + active: false + UseDataClass: + active: true + ignoreAnnotated: [] + allowVars: true + UseEmptyCounterpart: + active: false + UseIfEmptyOrIfBlank: + active: true + UseIfInsteadOfWhen: + active: true + UseIsNullOrEmpty: + active: true + UseOrEmpty: + active: true + UseRequire: + active: false + UseRequireNotNull: + active: false + UselessCallOnNotNull: + active: true + UtilityClassWithPublicConstructor: + active: true + VarCouldBeVal: + active: true + WildcardImport: + active: true + excludeImports: + - 'java.util.*' + - 'kotlinx.android.synthetic.*' diff --git a/internal/git-hooks/pre-commit.sh b/internal/git-hooks/pre-commit.sh new file mode 100644 index 000000000..6eb2c2afb --- /dev/null +++ b/internal/git-hooks/pre-commit.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +echo "Running detekt..." +./gradlew detekt + +detektStatus=$? +if [[ "$detektStatus" = 0 ]] ; then + echo "Detekt run successfully" + exit 0 +else + echo 1>&2 "Detekt found violations" + exit 1 +fi \ No newline at end of file diff --git a/internal/guides/Detekt.md b/internal/guides/Detekt.md new file mode 100644 index 000000000..1a3a7f23c --- /dev/null +++ b/internal/guides/Detekt.md @@ -0,0 +1,89 @@ +# Detekt Guide + +The Spezi project utilizes [Detekt](https://detekt.dev/) as a static code analyzer for Kotlin. This guide contains relevant information regarding Detekt setup and its usage. + +## Introduction + +The project relies on the following Detekt dependencies: +1. Detekt plugin: `io.gitlab.arturbosch.detekt` +2. Detekt formatting library: `io.gitlab.arturbosch.detekt:detekt-formatting:${version}` + +Detekt is configured in the root project's `build.gradle.kts` file via the `Project.setupDetekt()` method, and it's applied to all subprojects (modules) of the project. It utilizes the [`detekt-config.yml`](../detekt-config.yml) configuration file, which contains all Detekt rules that the project complies with. + +Detekt plugin will create several Gradle tasks for the root project and for each module. You can run these tasks either via the terminal by using Gradle Wrapper at the root of the project: + +```bash +# Run Detekt analysis on the root project +./gradlew detekt + +# Run Detekt analysis on a specific module +./gradlew :moduleName:detekt +``` + +It's important to note that the Detekt task is configured to automatically correct any found violations (if the issue is autocorrectable); otherwise, the fix should be performed manually. + +Furthermore, Detekt is configured as a job in a [Github action](https://github.com/alaegin/Detekt-Action?tab=readme-ov-file) to run on every [pull request](../../.github/workflows/build-and-test.yml) pointing to the main project branch. The job is configured to comment violations in the `Files changed` section of the pull request. + +## Android Studio and local setup + +In addition to the project setup, we advise making use of [Android Studio Detekt plugin](https://plugins.jetbrains.com/plugin/10761-detekt) to have in-editor support pointing out potential violations and in-editor autocorrection. In order to install the plugin, follow these steps: + +1. Open `Android Studio` > `Settings` > `Plugins` > `Marketplace` +2. Search for `detekt` and install it +3. After installing, open `Android Studio` > `Settings` > `Tools` > `detekt` and enable the following configurations: + 1. `Enable background analysis` + 2. `Treat detekt findings as errors` + 3. `Enable formatting (ktlint) rules` + 4. Under `Files / Configuration files`, add the project's `detekt-config.yml` located at `SpeziKt/internal/detekt-config.yml` +4. Save the changes + +

+ +

+ +In order to comply automatically with some detekt rules, we advise to also perform the following configurations in Android studio + +1. Open `Android Studio` > `Settings` > `Editor` > `General` > `On Save` and check `Ensure every saved file ends with a line break` +2. Open `Android Studio` > `Settings` > `Editor` > `Kotlin` > `Scheme` and on in the settings icon import [spezi_code_style.xml](../spezi_code_style.xml) file at `SpeziKt/internal/spezi_code_style.xml`. This will allow formatting with respect to detekt formatting rules when applying `Code` > `Reformat Code / File` commands in Android studio (or the corresponding shortcuts) + +

+ +

+ +## Git hook + +To ensure that every code change satisfies Detekt rules, the project includes a `pre-commit.sh` script located at [internal/git-hooks/pre-commit.sh](../../internal/git-hooks/pre-commit.sh): + +```bash +#!/bin/bash + +echo "Running detekt..." +./gradlew detekt + +detektStatus=$? +if [[ "$detektStatus" = 0 ]] ; then + echo "Detekt run successfully" + exit 0 +else + echo 1>&2 "Detekt found violations" + exit 1 +fi +``` + +The script can be installed as a `pre-commit` git hook, which runs Detekt (with autocorrection enabled) before a commit is executed. This ensures that applied changes conform to Detekt rules. To install the git hook, the project contains a Gradle task under the group `spezi`, which activates the hook: + +

+ +

+ +or by running the task via gradle wrapper from the root of the project: + +```bash +./gradlew installGitHooks +``` + +If you don't want to use the pre-commit hook, you can either delete it from the `.git/hooks` folder or disable it for a single commit using the `--no-verify` option: + +```bash +git commit -m "Your commit message" --no-verify +``` diff --git a/internal/guides/resources/code_style.png b/internal/guides/resources/code_style.png new file mode 100644 index 000000000..13fb37f7b Binary files /dev/null and b/internal/guides/resources/code_style.png differ diff --git a/internal/guides/resources/detekt_config.png b/internal/guides/resources/detekt_config.png new file mode 100644 index 000000000..a48860452 Binary files /dev/null and b/internal/guides/resources/detekt_config.png differ diff --git a/internal/guides/resources/gradle_installgithooks.png b/internal/guides/resources/gradle_installgithooks.png new file mode 100644 index 000000000..f158383a5 Binary files /dev/null and b/internal/guides/resources/gradle_installgithooks.png differ diff --git a/internal/spezi_code_style.xml b/internal/spezi_code_style.xml new file mode 100644 index 000000000..65c32b9c7 --- /dev/null +++ b/internal/spezi_code_style.xml @@ -0,0 +1,82 @@ + + diff --git a/modules/contact/build.gradle.kts b/modules/contact/build.gradle.kts index af8c7cbba..ecc4954de 100644 --- a/modules/contact/build.gradle.kts +++ b/modules/contact/build.gradle.kts @@ -10,4 +10,4 @@ android { dependencies { testImplementation(project(":core:testing")) androidTestImplementation(libs.bundles.compose.androidTest) -} \ No newline at end of file +} diff --git a/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/ContactFactory.kt b/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/ContactFactory.kt index 1aae6c37e..e97629523 100644 --- a/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/ContactFactory.kt +++ b/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/ContactFactory.kt @@ -14,8 +14,17 @@ object ContactFactory { description: String = "", organization: String = "", address: String = "", - options: List = emptyList() + options: List = emptyList(), ): Contact { - return Contact(id, icon, name, title, description, organization, address, options) + return Contact( + id = id, + icon = icon, + name = name, + title = title, + description = description, + organization = organization, + address = address, + options = options, + ) } -} \ No newline at end of file +} diff --git a/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/ContactScreenTest.kt b/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/ContactScreenTest.kt index 9923e5bef..398df1d7c 100644 --- a/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/ContactScreenTest.kt +++ b/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/ContactScreenTest.kt @@ -34,7 +34,6 @@ class ContactScreenTest { composeTestRule.onNodeWithText(contact.name).assertExists() } - @Test fun contactView_displaysContactOptions() { val contact = ContactFactory.create( @@ -90,15 +89,14 @@ class ContactScreenTest { @Test fun contactView_displaysContactDescription() { - val contact = - ContactFactory.create(description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") + val description = "Lorem ipsum dolor sit amet" + val contact = ContactFactory.create(description = description) every { mockContactRepository.getContact() } returns contact composeTestRule.setContent { ContactScreen(ContactViewModel(mockContactRepository)) } - composeTestRule.onNodeWithText(mockContactRepository.getContact().description) - .assertExists() + composeTestRule.onNodeWithText(description).assertExists() } -} \ No newline at end of file +} diff --git a/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/TestActivity.kt b/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/TestActivity.kt index 314d0bdda..199503515 100644 --- a/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/TestActivity.kt +++ b/modules/contact/src/androidTest/kotlin/edu/stanford/spezi/modules/contact/TestActivity.kt @@ -2,4 +2,4 @@ package edu.stanford.spezi.modules.contact import androidx.activity.ComponentActivity -class TestActivity : ComponentActivity() \ No newline at end of file +class TestActivity : ComponentActivity() diff --git a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/ContactScreen.kt b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/ContactScreen.kt index 4a730b6c2..6648541e3 100644 --- a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/ContactScreen.kt +++ b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/ContactScreen.kt @@ -1,6 +1,5 @@ package edu.stanford.spezi.modules.contact - import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi @@ -134,7 +133,9 @@ fun ContactScreen(viewModel: ContactViewModel) { @Preview @Composable -fun ContactScreenPreview(@PreviewParameter(ContactViewModelPreviewParameterProvider::class) viewModel: ContactViewModel) { +fun ContactScreenPreview( + @PreviewParameter(ContactViewModelPreviewParameterProvider::class) viewModel: ContactViewModel, +) { SpeziTheme { ContactScreen(viewModel) } @@ -144,4 +145,4 @@ class ContactViewModelPreviewParameterProvider : PreviewParameterProvider = sequenceOf( ContactViewModel(DefaultContactRepository()), ) -} \ No newline at end of file +} diff --git a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/ContactViewModel.kt b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/ContactViewModel.kt index 0f0984f8f..a713b1090 100644 --- a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/ContactViewModel.kt +++ b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/ContactViewModel.kt @@ -56,4 +56,4 @@ class ContactViewModel(private val repository: ContactRepository) : ViewModel() } } } -} \ No newline at end of file +} diff --git a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/OnAction.kt b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/OnAction.kt index f653ee51c..c89e7655e 100644 --- a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/OnAction.kt +++ b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/OnAction.kt @@ -5,4 +5,4 @@ import edu.stanford.spezi.modules.contact.model.ContactOption sealed interface OnAction { data class CardClicked(val option: ContactOption) : OnAction data class NavigateTo(val address: String) : OnAction -} \ No newline at end of file +} diff --git a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/component/ContactOptionCard.kt b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/component/ContactOptionCard.kt index 16f6f13aa..9546dbcff 100644 --- a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/component/ContactOptionCard.kt +++ b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/component/ContactOptionCard.kt @@ -73,4 +73,4 @@ fun ContactOptionCardPreview() { publisher = { action -> println(action) } ) } -} \ No newline at end of file +} diff --git a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/component/NavigationCard.kt b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/component/NavigationCard.kt index 8ccb11662..bbfcca4ad 100644 --- a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/component/NavigationCard.kt +++ b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/component/NavigationCard.kt @@ -71,4 +71,4 @@ fun NavigationCardPreview() { NavigationCard("1234 Main Street, 12345 City", publisher = { action -> println(action) }) } -} \ No newline at end of file +} diff --git a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/model/Contact.kt b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/model/Contact.kt index efbbbe3a5..385d6e115 100644 --- a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/model/Contact.kt +++ b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/model/Contact.kt @@ -27,7 +27,7 @@ data class Contact( val description: String, val organization: String, val address: String, - val options: List + val options: List, ) /** @@ -46,7 +46,7 @@ data class ContactOption( val name: String, val value: String, val icon: ImageVector?, - val optionType: ContactOptionType + val optionType: ContactOptionType, ) /** @@ -56,4 +56,4 @@ data class ContactOption( */ enum class ContactOptionType { CALL, EMAIL, WEBSITE -} \ No newline at end of file +} diff --git a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/repository/ContactRepository.kt b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/repository/ContactRepository.kt index f6fc72ee9..e4d747370 100644 --- a/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/repository/ContactRepository.kt +++ b/modules/contact/src/main/kotlin/edu/stanford/spezi/modules/contact/repository/ContactRepository.kt @@ -26,7 +26,7 @@ class DefaultContactRepository : ContactRepository { icon = null, name = "Leland Stanford", title = "CEO", - description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", organization = "Stanford University", address = "450 Jane Stanford Way Stanford, CA", options = listOf( @@ -54,4 +54,4 @@ class DefaultContactRepository : ContactRepository { ) ) } -} \ No newline at end of file +} diff --git a/modules/contact/src/test/kotlin/edu/stanford/spezi/modules/contact/ContactRepositoryTest.kt b/modules/contact/src/test/kotlin/edu/stanford/spezi/modules/contact/DefaultContactRepositoryTest.kt similarity index 84% rename from modules/contact/src/test/kotlin/edu/stanford/spezi/modules/contact/ContactRepositoryTest.kt rename to modules/contact/src/test/kotlin/edu/stanford/spezi/modules/contact/DefaultContactRepositoryTest.kt index 8d0c7c465..062965e0f 100644 --- a/modules/contact/src/test/kotlin/edu/stanford/spezi/modules/contact/ContactRepositoryTest.kt +++ b/modules/contact/src/test/kotlin/edu/stanford/spezi/modules/contact/DefaultContactRepositoryTest.kt @@ -21,9 +21,7 @@ class DefaultContactRepositoryTest { with(contact) { assertThat(name).isEqualTo("Leland Stanford") assertThat(title).isEqualTo("CEO") - assertThat(description).isEqualTo( - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." - ) + assertThat(description).isEqualTo("Lorem ipsum dolor sit amet, consectetur adipiscing elit.") assertThat(organization).isEqualTo("Stanford University") assertThat(address).isEqualTo("450 Jane Stanford Way Stanford, CA") assertThat(options.size).isEqualTo(3) @@ -32,4 +30,4 @@ class DefaultContactRepositoryTest { assertThat(options[0].optionType).isEqualTo(ContactOptionType.CALL) } } -} \ No newline at end of file +} diff --git a/modules/onboarding/build.gradle.kts b/modules/onboarding/build.gradle.kts index 5a805d56b..0ffcb9cac 100644 --- a/modules/onboarding/build.gradle.kts +++ b/modules/onboarding/build.gradle.kts @@ -5,4 +5,4 @@ plugins { android { namespace = "edu.stanford.spezi.modules.onboarding" -} \ No newline at end of file +} diff --git a/modules/onboarding/src/main/kotlin/edu/stanford/spezi/modules/onboarding/OnboardingScreen.kt b/modules/onboarding/src/main/kotlin/edu/stanford/spezi/modules/onboarding/OnboardingScreen.kt index 1ebfde7e8..7e2dc272b 100644 --- a/modules/onboarding/src/main/kotlin/edu/stanford/spezi/modules/onboarding/OnboardingScreen.kt +++ b/modules/onboarding/src/main/kotlin/edu/stanford/spezi/modules/onboarding/OnboardingScreen.kt @@ -10,11 +10,10 @@ fun OnboardingScreen() { Text(text = "Onboarding Screen") } - @Preview @Composable fun OnboardingScreenPreview() { SpeziTheme { OnboardingScreen() } -} \ No newline at end of file +}