From d7c3250ff2b360c61398425b7b2c28bf021b175c Mon Sep 17 00:00:00 2001 From: Yahor Urbanovich Date: Thu, 10 Oct 2024 10:53:22 +0300 Subject: [PATCH] Setup checking tests on ci --- .github/workflows/verify.yml | 34 ++++++++++++++++++- README.md | 8 +++-- gradle/libs.versions.toml | 6 ++-- .../maps/compose/marker/compose/IconMarker.kt | 1 + .../screen/ui/foundation/ModalBottomSheet.kt | 19 ++--------- .../settings/changelog/build.gradle.kts | 5 +-- .../domain/util/DateFormatter.android.kt | 14 -------- .../repository/ChangelogRepositoryImpl.kt | 9 ++--- .../changelog/domain/util/DateFormatter.kt | 8 ----- .../commonTest/kotlin/DateFormatterTest.kt | 13 ------- .../domain/util/DateFormatter.ios.kt | 20 ----------- .../grodnoroads/extensions/DateTimeTest.kt | 12 +++---- .../grodnoroads/location/LatLng.android.kt | 2 +- .../grodnoroads/location/LatLng.ios.kt | 2 +- .../shared/formatter/CameraFormatter.kt | 2 +- .../shared/formatter/ChangelogFormatter.kt | 28 +++++++++++++++ .../formatter/ChangelogFormatterTest.kt | 28 +++++++++++++++ 17 files changed, 115 insertions(+), 96 deletions(-) delete mode 100644 kmp/features/settings/changelog/src/androidMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.android.kt delete mode 100644 kmp/features/settings/changelog/src/commonMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.kt delete mode 100644 kmp/features/settings/changelog/src/commonTest/kotlin/DateFormatterTest.kt delete mode 100644 kmp/features/settings/changelog/src/iosMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.ios.kt create mode 100644 kmp/shared/formatter/src/commonMain/kotlin/com/egoriku/grodnoroads/shared/formatter/ChangelogFormatter.kt create mode 100644 kmp/shared/formatter/src/commonTest/kotlin/com/egoriku/grodnoroads/shared/formatter/ChangelogFormatterTest.kt diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 67800abe6..ba12067a8 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -7,7 +7,7 @@ on: branches: [ "develop" ] jobs: - build: + android-test: runs-on: ubuntu-latest steps: @@ -21,8 +21,40 @@ jobs: java-version: 17 cache: gradle + - name: Copy google-services.json + run: echo ${{ secrets.GOOGLE_JSON }} | base64 --decode > app/android/google-services.json + - name: Make secrets.properties run: echo ${{ secrets.SECRETS_PROPERTIES }} | base64 --decode > secrets.properties - name: Spotless check run: ./gradlew spotlessCheck + + - name: Run Android tests + run: ./gradlew testDebugUnitTest + + - name: Build Android app + run: ./gradlew app:android:assembleDebug + + - name: Build UI Demo app + run: ./gradlew app:ui-demo:assembleDebug + +# ios-test: +# runs-on: macos-latest +# +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# +# - name: set up JDK 17 +# uses: actions/setup-java@v4 +# with: +# distribution: temurin +# java-version: 17 +# cache: gradle +# +# - name: Make secrets.properties +# run: echo ${{ secrets.SECRETS_PROPERTIES }} | base64 --decode > secrets.properties +# +# - name: Run iOS tests +# run: ./gradlew iosSimulatorArm64Test diff --git a/README.md b/README.md index 0f8450a7e..1b8d98c1f 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,11 @@ In case bug and suggestions, please create issue. ### Useful gradle commands -Check dependency updates: `./gradlew dependencyUpdates` +Update code style: `./gradlew spotlessApply` -Run compose metrics: `./gradlew app:android:assembleRelease -PenableComposeCompilerReports=true` +Check code style: `./gradlew spotlessCheck` + +Run compose metrics: `./gradlew app:android:assembleRelease -PenableComposeCompilerReports=true` Generate kmp buildconfig: `./gradlew :kmp:shared:components:generateBuildKonfig` @@ -46,4 +48,4 @@ Build app release: `./gradlew app:android:assembleRelease` Pods: remove pod: `pod deintegrate` -init pod: `pod install` \ No newline at end of file +init pod: `pod install` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d16441006..25720e55a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ minSdk = "23" # Android 6.0 targetSdk = "34" agp = "8.7.0" -coil = "3.0.0-rc01" +coil = "3.0.0-alpha10" decompose = "3.1.0" essenty = "2.1.0" kotlinx-serialization = "1.7.3" @@ -24,7 +24,7 @@ androidx-datastore = "androidx.datastore:datastore-preferences:1.1.1" androidx-datastore-core = "androidx.datastore:datastore-preferences-core:1.1.1" androidx-media = "androidx.media:media:1.7.0" -balloon-compose = "com.github.skydoves:balloon-compose:1.6.8" +balloon-compose = "com.github.skydoves:balloon-compose:1.6.7" coil = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } coil-network-ktor = "io.coil-kt.coil3:coil-network-ktor:3.0.0-alpha08" @@ -100,4 +100,4 @@ spotless = "com.diffplug.spotless:7.0.0.BETA2" # Project conventional plugins grodnoroads-application = { id = "grodnoroads.application", version = "unspecified" } grodnoroads-kmp-compose = { id = "grodnoroads.kmp.compose", version = "unspecified" } -grodnoroads-kmp-library = { id = "grodnoroads.kmp.library", version = "unspecified" } \ No newline at end of file +grodnoroads-kmp-library = { id = "grodnoroads.kmp.library", version = "unspecified" } diff --git a/kmp/compose/maps-compose/src/commonMain/kotlin/com/egoriku/grodnoroads/maps/compose/marker/compose/IconMarker.kt b/kmp/compose/maps-compose/src/commonMain/kotlin/com/egoriku/grodnoroads/maps/compose/marker/compose/IconMarker.kt index 390cb25d1..fa4e72567 100644 --- a/kmp/compose/maps-compose/src/commonMain/kotlin/com/egoriku/grodnoroads/maps/compose/marker/compose/IconMarker.kt +++ b/kmp/compose/maps-compose/src/commonMain/kotlin/com/egoriku/grodnoroads/maps/compose/marker/compose/IconMarker.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue +import com.egoriku.grodnoroads.foundation.core.rememberMutableState import com.egoriku.grodnoroads.location.LatLng import com.egoriku.grodnoroads.maps.compose.core.Marker import com.egoriku.grodnoroads.maps.compose.core.remove diff --git a/kmp/features/guidance/src/commonMain/kotlin/com/egoriku/grodnoroads/guidance/screen/ui/foundation/ModalBottomSheet.kt b/kmp/features/guidance/src/commonMain/kotlin/com/egoriku/grodnoroads/guidance/screen/ui/foundation/ModalBottomSheet.kt index df25c4fc7..d52f35265 100644 --- a/kmp/features/guidance/src/commonMain/kotlin/com/egoriku/grodnoroads/guidance/screen/ui/foundation/ModalBottomSheet.kt +++ b/kmp/features/guidance/src/commonMain/kotlin/com/egoriku/grodnoroads/guidance/screen/ui/foundation/ModalBottomSheet.kt @@ -8,17 +8,12 @@ import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetState -import androidx.compose.material3.contentColorFor import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.unit.Dp -import com.egoriku.grodnoroads.foundation.theme.tonalElevation +import com.egoriku.grodnoroads.foundation.common.ui.bottomsheet.ModalBottomSheet @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -28,12 +23,7 @@ fun ModalBottomSheet( modifier: Modifier = Modifier, sheetState: SheetState = rememberModalBottomSheetState(), shape: Shape = BottomSheetDefaults.ExpandedShape, - containerColor: Color = BottomSheetDefaults.ContainerColor, - contentColor: Color = contentColorFor(containerColor), - tonalElevation: Dp = MaterialTheme.tonalElevation, - scrimColor: Color = BottomSheetDefaults.ScrimColor, dragHandle: @Composable (() -> Unit)? = { BottomSheetDefaults.DragHandle() }, - windowInsets: WindowInsets = WindowInsets(0, 0, 0, 0), content: @Composable ColumnScope.(T) -> Unit ) { if (data != null) { @@ -44,12 +34,7 @@ fun ModalBottomSheet( onDismissRequest = onDismissRequest, sheetState = sheetState, shape = shape, - containerColor = containerColor, - contentColor = contentColor, - tonalElevation = tonalElevation, - scrimColor = scrimColor, - dragHandle = dragHandle, - windowInsets = windowInsets + dragHandle = dragHandle ) { Column(modifier = Modifier.padding(bottom = bottomPadding)) { content(data) diff --git a/kmp/features/settings/changelog/build.gradle.kts b/kmp/features/settings/changelog/build.gradle.kts index d25f9dfec..c052d10d1 100644 --- a/kmp/features/settings/changelog/build.gradle.kts +++ b/kmp/features/settings/changelog/build.gradle.kts @@ -1,6 +1,5 @@ import com.egoriku.grodnoroads.extension.applyTargets import com.egoriku.grodnoroads.extension.commonDependencies -import com.egoriku.grodnoroads.extension.commonTestDependencies plugins { alias(libs.plugins.grodnoroads.kmp.library) @@ -21,6 +20,7 @@ kotlin { implementation(projects.kmp.compose.foundation.uikit) implementation(projects.kmp.compose.resources) implementation(projects.kmp.shared.crashlytics) + implementation(projects.kmp.shared.formatter) implementation(projects.kmp.libraries.coroutines) implementation(projects.kmp.libraries.extensions) @@ -32,8 +32,5 @@ kotlin { implementation(libs.mvikotlin.extensions) implementation(libs.mvikotlin.main) } - commonTestDependencies { - implementation(libs.kotlin.test) - } } } diff --git a/kmp/features/settings/changelog/src/androidMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.android.kt b/kmp/features/settings/changelog/src/androidMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.android.kt deleted file mode 100644 index f265f13e4..000000000 --- a/kmp/features/settings/changelog/src/androidMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.android.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.egoriku.grodnoroads.settings.changelog.domain.util - -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale - -// TODO: Use formatting from kotlinx-datetime -actual class DateFormatter { - private val dayMonthYearFormatter = SimpleDateFormat(DATE_FORMAT_PATTERN, Locale.getDefault()) - - actual fun formatTime(timeLong: Long): String { - return dayMonthYearFormatter.format(Date(timeLong * 1000)) - } -} diff --git a/kmp/features/settings/changelog/src/commonMain/kotlin/com/egoriku/grodnoroads/settings/changelog/data/repository/ChangelogRepositoryImpl.kt b/kmp/features/settings/changelog/src/commonMain/kotlin/com/egoriku/grodnoroads/settings/changelog/data/repository/ChangelogRepositoryImpl.kt index e83cdd57a..52de7f807 100644 --- a/kmp/features/settings/changelog/src/commonMain/kotlin/com/egoriku/grodnoroads/settings/changelog/data/repository/ChangelogRepositoryImpl.kt +++ b/kmp/features/settings/changelog/src/commonMain/kotlin/com/egoriku/grodnoroads/settings/changelog/data/repository/ChangelogRepositoryImpl.kt @@ -4,9 +4,10 @@ import com.egoriku.grodnoroads.extensions.common.ResultOf import com.egoriku.grodnoroads.settings.changelog.data.dto.ChangelogDTO import com.egoriku.grodnoroads.settings.changelog.domain.model.ReleaseNotes import com.egoriku.grodnoroads.settings.changelog.domain.repository.ChangelogRepository -import com.egoriku.grodnoroads.settings.changelog.domain.util.DateFormatter +import com.egoriku.grodnoroads.shared.formatter.ChangelogFormatter import dev.gitlive.firebase.firestore.Direction import dev.gitlive.firebase.firestore.FirebaseFirestore +import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO import kotlinx.coroutines.withContext @@ -15,8 +16,6 @@ internal class ChangelogRepositoryImpl( private val firestore: FirebaseFirestore ) : ChangelogRepository { - private val formatter = DateFormatter() - override suspend fun load() = withContext(Dispatchers.IO) { runCatching { val changelog = firestore @@ -33,7 +32,9 @@ internal class ChangelogRepositoryImpl( versionCode = it.code, versionName = it.name, notes = it.notes.replace("\\n", "\n"), - releaseDate = formatter.formatTime(it.releaseDate.seconds) + releaseDate = ChangelogFormatter.format( + timestamp = it.releaseDate.seconds.seconds.inWholeMilliseconds + ) ) } ) diff --git a/kmp/features/settings/changelog/src/commonMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.kt b/kmp/features/settings/changelog/src/commonMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.kt deleted file mode 100644 index 1156db243..000000000 --- a/kmp/features/settings/changelog/src/commonMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.egoriku.grodnoroads.settings.changelog.domain.util - -internal const val DATE_FORMAT_PATTERN = "dd MMMM, yyyy" - -expect class DateFormatter() { - - fun formatTime(timeLong: Long): String -} diff --git a/kmp/features/settings/changelog/src/commonTest/kotlin/DateFormatterTest.kt b/kmp/features/settings/changelog/src/commonTest/kotlin/DateFormatterTest.kt deleted file mode 100644 index ad26f8726..000000000 --- a/kmp/features/settings/changelog/src/commonTest/kotlin/DateFormatterTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -import com.egoriku.grodnoroads.settings.changelog.domain.util.DateFormatter -import kotlin.test.Test -import kotlin.test.assertEquals - -class DateFormatterTest { - private val formatter = DateFormatter() - - @Test - fun testFormatting() { - val date = formatter.formatTime(1678395600) - assertEquals("10 March, 2023", date) - } -} diff --git a/kmp/features/settings/changelog/src/iosMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.ios.kt b/kmp/features/settings/changelog/src/iosMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.ios.kt deleted file mode 100644 index 5bf02bd36..000000000 --- a/kmp/features/settings/changelog/src/iosMain/kotlin/com/egoriku/grodnoroads/settings/changelog/domain/util/DateFormatter.ios.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.egoriku.grodnoroads.settings.changelog.domain.util - -import platform.Foundation.NSDate -import platform.Foundation.NSDateFormatter -import platform.Foundation.NSLocale -import platform.Foundation.currentLocale -import platform.Foundation.dateWithTimeIntervalSince1970 -import platform.Foundation.localeIdentifier -import platform.Foundation.localeWithLocaleIdentifier - -actual class DateFormatter { - actual fun formatTime(timeLong: Long): String { - val date = NSDate.dateWithTimeIntervalSince1970(timeLong.toDouble()) - val dateFormatter = NSDateFormatter().apply { - dateFormat = DATE_FORMAT_PATTERN - locale = NSLocale.localeWithLocaleIdentifier(NSLocale.currentLocale.localeIdentifier) - } - return dateFormatter.stringFromDate(date) - } -} diff --git a/kmp/libraries/extensions/src/commonTest/kotlin/com/egoriku/grodnoroads/extensions/DateTimeTest.kt b/kmp/libraries/extensions/src/commonTest/kotlin/com/egoriku/grodnoroads/extensions/DateTimeTest.kt index 5d4da308a..41e47994c 100644 --- a/kmp/libraries/extensions/src/commonTest/kotlin/com/egoriku/grodnoroads/extensions/DateTimeTest.kt +++ b/kmp/libraries/extensions/src/commonTest/kotlin/com/egoriku/grodnoroads/extensions/DateTimeTest.kt @@ -19,12 +19,12 @@ class DateTimeTest { @Test fun formatTest() { assertEquals( - "8:06", - DateTime.formatToTime((8.hours + 6.minutes).inWholeMilliseconds) + expected = "8:06", + actual = DateTime.formatToTime((8.hours + 6.minutes).inWholeMilliseconds) ) assertEquals( - "17:09", - DateTime.formatToTime((17.hours + 9.minutes).inWholeMilliseconds) + expected = "17:09", + actual = DateTime.formatToTime((17.hours + 9.minutes).inWholeMilliseconds) ) val date = LocalDateTime( @@ -36,8 +36,8 @@ class DateTimeTest { second = 12 ).toInstant(TimeZone.UTC).toEpochMilliseconds() assertEquals( - "17:09", - DateTime.formatToTime(date) + expected = "17:09", + actual = DateTime.formatToTime(date) ) } } diff --git a/kmp/libraries/location/src/androidMain/kotlin/com/egoriku/grodnoroads/location/LatLng.android.kt b/kmp/libraries/location/src/androidMain/kotlin/com/egoriku/grodnoroads/location/LatLng.android.kt index 1675d56fc..5269251e3 100644 --- a/kmp/libraries/location/src/androidMain/kotlin/com/egoriku/grodnoroads/location/LatLng.android.kt +++ b/kmp/libraries/location/src/androidMain/kotlin/com/egoriku/grodnoroads/location/LatLng.android.kt @@ -4,7 +4,7 @@ actual typealias PlatformLatLng = com.google.android.gms.maps.model.LatLng fun PlatformLatLng.toLatLng() = LatLng(this) -actual class LatLng actual constructor(val platform: PlatformLatLng) { +actual data class LatLng actual constructor(val platform: PlatformLatLng) { actual val latitude: Double get() = platform.latitude diff --git a/kmp/libraries/location/src/iosMain/kotlin/com/egoriku/grodnoroads/location/LatLng.ios.kt b/kmp/libraries/location/src/iosMain/kotlin/com/egoriku/grodnoroads/location/LatLng.ios.kt index 6949b5748..75edb4b78 100644 --- a/kmp/libraries/location/src/iosMain/kotlin/com/egoriku/grodnoroads/location/LatLng.ios.kt +++ b/kmp/libraries/location/src/iosMain/kotlin/com/egoriku/grodnoroads/location/LatLng.ios.kt @@ -14,7 +14,7 @@ fun CValue.toLatLng() = LatLng(IOSLatLng(this)) class IOSLatLng(val cValue: CValue) @OptIn(ExperimentalForeignApi::class) -actual class LatLng actual constructor(private val platform: PlatformLatLng) { +actual data class LatLng actual constructor(private val platform: PlatformLatLng) { actual val latitude: Double get() = platform.cValue.useContents { latitude } diff --git a/kmp/shared/formatter/src/commonMain/kotlin/com/egoriku/grodnoroads/shared/formatter/CameraFormatter.kt b/kmp/shared/formatter/src/commonMain/kotlin/com/egoriku/grodnoroads/shared/formatter/CameraFormatter.kt index baf7ead43..90e5f7829 100644 --- a/kmp/shared/formatter/src/commonMain/kotlin/com/egoriku/grodnoroads/shared/formatter/CameraFormatter.kt +++ b/kmp/shared/formatter/src/commonMain/kotlin/com/egoriku/grodnoroads/shared/formatter/CameraFormatter.kt @@ -9,7 +9,7 @@ import kotlinx.datetime.toLocalDateTime object CameraFormatter { - private var defaultTimeZone = TimeZone.of("Europe/Minsk") + private val defaultTimeZone = TimeZone.of("Europe/Minsk") private val dateTimeFormat = LocalDateTime.Format { dayOfMonth() char('.') diff --git a/kmp/shared/formatter/src/commonMain/kotlin/com/egoriku/grodnoroads/shared/formatter/ChangelogFormatter.kt b/kmp/shared/formatter/src/commonMain/kotlin/com/egoriku/grodnoroads/shared/formatter/ChangelogFormatter.kt new file mode 100644 index 000000000..75ea3a7b5 --- /dev/null +++ b/kmp/shared/formatter/src/commonMain/kotlin/com/egoriku/grodnoroads/shared/formatter/ChangelogFormatter.kt @@ -0,0 +1,28 @@ +package com.egoriku.grodnoroads.shared.formatter + +import kotlinx.datetime.Instant +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.format +import kotlinx.datetime.format.MonthNames +import kotlinx.datetime.format.Padding +import kotlinx.datetime.format.char +import kotlinx.datetime.toLocalDateTime + +object ChangelogFormatter { + + private val defaultTimeZone = TimeZone.of("Europe/Minsk") + private val dayMonthYearFormatter = LocalDateTime.Format { + dayOfMonth(padding = Padding.NONE) + char(' ') + monthName(MonthNames.ENGLISH_FULL) + char(',') + char(' ') + year() + } + + fun format(timestamp: Long): String = + Instant.fromEpochMilliseconds(timestamp) + .toLocalDateTime(defaultTimeZone) + .format(dayMonthYearFormatter) +} diff --git a/kmp/shared/formatter/src/commonTest/kotlin/com/egoriku/grodnoroads/shared/formatter/ChangelogFormatterTest.kt b/kmp/shared/formatter/src/commonTest/kotlin/com/egoriku/grodnoroads/shared/formatter/ChangelogFormatterTest.kt new file mode 100644 index 000000000..662fd1acf --- /dev/null +++ b/kmp/shared/formatter/src/commonTest/kotlin/com/egoriku/grodnoroads/shared/formatter/ChangelogFormatterTest.kt @@ -0,0 +1,28 @@ +package com.egoriku.grodnoroads.shared.formatter + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlinx.datetime.LocalDate +import kotlinx.datetime.TimeZone +import kotlinx.datetime.atStartOfDayIn + +class ChangelogFormatterTest { + + @Test + fun formatterTest() { + assertEquals( + expected = "10 March, 2023", + actual = ChangelogFormatter.format(1678395600000) + ) + assertEquals( + expected = "5 January, 2023", + actual = ChangelogFormatter.format( + timestamp = LocalDate( + year = 2023, + monthNumber = 1, + dayOfMonth = 5 + ).atStartOfDayIn(TimeZone.UTC).toEpochMilliseconds() + ) + ) + } +}