diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 1d7687d1c5..f205321ea2 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -4,6 +4,41 @@
+
+
+
diff --git a/accessibility-toolbox/build.gradle.kts b/accessibility-toolbox/build.gradle.kts
index 753586114e..b67ab47556 100644
--- a/accessibility-toolbox/build.gradle.kts
+++ b/accessibility-toolbox/build.gradle.kts
@@ -1,5 +1,7 @@
@file:Suppress("UnstableApiUsage")
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
plugins {
id(libs.plugins.androidLibrary.get().pluginId)
id(libs.plugins.kotlin.android.get().pluginId)
@@ -50,12 +52,13 @@ android {
getByName("androidTest").java.srcDirs("src/androidTest/kotlin")
}
- kotlinOptions {
- freeCompilerArgs = listOf(
- *kotlinOptions.freeCompilerArgs.toTypedArray(),
- "-Xjvm-default=all"
- )
- jvmTarget = "17"
+ kotlin {
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_17
+ freeCompilerArgs.addAll(
+ "-Xjvm-default=all"
+ )
+ }
}
lint {
diff --git a/build.gradle.kts b/build.gradle.kts
index 8288229ce9..3619a3276d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -29,8 +29,6 @@ buildscript {
}
}
-val sdkVersion = libs.versions.snabbleSdk.get()
-
allprojects {
repositories {
google()
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index cb3e9b067c..b92f55fd87 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -1,5 +1,7 @@
@file:Suppress("UnstableApiUsage")
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
plugins {
id(libs.plugins.androidLibrary.get().pluginId)
id(libs.plugins.kotlin.android.get().pluginId)
@@ -48,12 +50,13 @@ android {
targetCompatibility = JavaVersion.VERSION_17
}
- kotlinOptions {
- freeCompilerArgs = listOf(
- *kotlinOptions.freeCompilerArgs.toTypedArray(),
- "-Xjvm-default=all"
- )
- jvmTarget = "17"
+ kotlin {
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_17
+ freeCompilerArgs.addAll(
+ "-Xjvm-default=all"
+ )
+ }
}
buildFeatures {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index fbd67a8a22..2e065beb5c 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -2,23 +2,23 @@
compileSdk = "35"
targetSdk = "35"
minSdk = "21"
-gradlePlugin = "8.9.2"
-kotlin = "2.0.20"
-navigation = "2.8.1"
+gradlePlugin = "8.11.0"
+kotlin = "2.2.0"
+navigation = "2.9.1"
snabbleSdk = "0.69.6"
-androidx-camera = "1.3.4"
-androidx-compose-ui = "1.7.2"
+androidx-camera = "1.4.2"
+androidx-compose-ui = "1.8.3"
com-squareup-okhttp3 = "4.12.0"
io-kotest = "5.9.1"
dokka = "1.9.20"
-androidx-compose-material = "1.7.2"
-android-lifecycle = "2.8.6"
-koin = "4.0.0"
+androidx-compose-material = "1.8.3"
+android-lifecycle = "2.9.1"
+koin = "4.1.0"
[libraries]
-airbnb-lottie = "com.airbnb.android:lottie:6.5.2"
-androidx-activityCompose = "androidx.activity:activity-compose:1.9.2"
-androidx-appcompat = "androidx.appcompat:appcompat:1.7.0"
+airbnb-lottie = "com.airbnb.android:lottie:6.6.7"
+androidx-activityCompose = "androidx.activity:activity-compose:1.10.1"
+androidx-appcompat = "androidx.appcompat:appcompat:1.7.1"
androidx-biometric = "androidx.biometric:biometric:1.2.0-alpha05"
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "androidx-camera" }
androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "androidx-camera" }
@@ -26,13 +26,13 @@ androidx-camera-extension = { module = "androidx.camera:camera-extensions", vers
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "androidx-camera" }
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "androidx-camera" }
androidx-cardview = "androidx.cardview:cardview:1.0.0"
-androidx-core-ktx = "androidx.core:core-ktx:1.13.1"
-androidx-constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4"
-androidx-constraintlayoutCompose = "androidx.constraintlayout:constraintlayout-compose:1.0.1"
+androidx-core-ktx = "androidx.core:core-ktx:1.16.0"
+androidx-constraintlayout = "androidx.constraintlayout:constraintlayout:2.2.1"
+androidx-constraintlayoutCompose = "androidx.constraintlayout:constraintlayout-compose:1.1.1"
# Compose previews won't work w/o this: https://issuetracker.google.com/issues/227767363
-androidx-customview = "androidx.customview:customview:1.1.0"
-androidx-customview-poolingcontainer = "androidx.customview:customview-poolingcontainer:1.0.0"
-androidx-gridlayout = "androidx.gridlayout:gridlayout:1.0.0"
+androidx-customview = "androidx.customview:customview:1.2.0"
+androidx-customview-poolingcontainer = "androidx.customview:customview-poolingcontainer:1.1.0"
+androidx-gridlayout = "androidx.gridlayout:gridlayout:1.1.0"
androidx-lifecycle-common = {module = "androidx.lifecycle:lifecycle-common", version.ref = "android-lifecycle"}
androidx-lifecycleExtension = "androidx.lifecycle:lifecycle-extensions:2.2.0"
androidx-lifecycleLiveData = {module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "android-lifecycle"}
@@ -45,17 +45,17 @@ androidx-navigation-fragmentKtx = { module = "androidx.navigation:navigation-fra
androidx-navigation-runtimeKtx = { module = "androidx.navigation:navigation-runtime-ktx", version.ref = "navigation" }
androidx-navigation-uiKtx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navigation" }
androidx-preferences = "androidx.preference:preference-ktx:1.2.1"
-androidx-recyclerview = "androidx.recyclerview:recyclerview:1.3.2"
+androidx-recyclerview = "androidx.recyclerview:recyclerview:1.4.0"
androidx-startupRuntime = "androidx.startup:startup-runtime:1.2.0"
androidx-swiperefreshlayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
androidx-viewpager2 = "androidx.viewpager2:viewpager2:1.1.0"
-androidx-webkit = "androidx.webkit:webkit:1.12.0"
+androidx-webkit = "androidx.webkit:webkit:1.14.0"
apache-commonsLang3 = "org.apache.commons:commons-lang3:3.17.0"
caverock-androidsvgAar = "com.caverock:androidsvg-aar:1.4"
-compose-iconsExtended = { module = "androidx.compose.material:material-icons-extended", version.ref = "androidx-compose-material" }
+compose-iconsExtended = { module = "androidx.compose.material:material-icons-extended", version = "1.7.8" }
compose-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "navigation" }
compose-material = { module = "androidx.compose.material:material", version.ref = "androidx-compose-material" }
-compose-material3 = "androidx.compose.material3:material3:1.3.0"
+compose-material3 = "androidx.compose.material3:material3:1.3.2"
compose-material3Themeadapter = "com.google.accompanist:accompanist-themeadapter-material3:0.36.0"
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "androidx-compose-ui" }
compose-uiTestManifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "androidx-compose-ui" }
@@ -64,18 +64,18 @@ compose-uiTooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "
compose-uiToolingPreview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "androidx-compose-ui" }
compose-uiUtil = { module = "androidx.compose.ui:ui-util", version.ref = "androidx-compose-ui" }
compose-uiViewBinding = { module = "androidx.compose.ui:ui-viewbinding", version.ref = "androidx-compose-ui" }
-commonsIo = "commons-io:commons-io:2.17.0"
+commonsIo = "commons-io:commons-io:2.19.0"
datatrans-androidSdk = "ch.datatrans:android-sdk:3.7.0"
-desugarJdkLibsNio = "com.android.tools:desugar_jdk_libs_nio:2.1.2"
+desugarJdkLibsNio = "com.android.tools:desugar_jdk_libs_nio:2.1.5"
glide-compose = "com.github.bumptech.glide:compose:1.0.0-beta01"
-googlePlayServices-maps = "com.google.android.gms:play-services-maps:19.0.0"
+googlePlayServices-maps = "com.google.android.gms:play-services-maps:19.2.0"
googlePlayServices-wallet = "com.google.android.gms:play-services-wallet:19.4.0"
google-mlkit-barcodeScanning = "com.google.mlkit:barcode-scanning:17.3.0"
google-zxing-core = "com.google.zxing:core:3.5.3"
-gson = "com.google.code.gson:gson:2.11.0"
+gson = "com.google.code.gson:gson:2.13.1"
iban4j = "org.iban4j:iban4j:3.2.10-RELEASE"
jakewhartonProcessPhoenix = "com.jakewharton:process-phoenix:3.0.0"
-picasso = "com.squareup.picasso:picasso:2.8"
+picasso = "com.squareup.picasso:picasso:2.71828"
rekisoftLazyWorker = "eu.rekisoft.android.util:LazyWorker:2.1.0"
relex-circleindicator = "me.relex:circleindicator:2.1.6"
snabble-phoneAuth-countryCodePicker = "io.snabble.phoneauth:countryCodePicker:3.3.0"
@@ -93,13 +93,13 @@ kotest-runnerJunit = { module = "io.kotest:kotest-runner-junit5", version.ref =
kotest-assertionsCore = { module = "io.kotest:kotest-assertions-core", version.ref = "io-kotest" }
koltin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
-kotlinx-serializationJson = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3"
-mockk = "io.mockk:mockk:1.13.12"
+kotlinx-serializationJson = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0"
+mockk = "io.mockk:mockk:1.14.4"
# @pin requires higher target
mockito-kotlin = "org.mockito.kotlin:mockito-kotlin:5.4.0"
-roboletric = "org.robolectric:robolectric:4.13"
+roboletric = "org.robolectric:robolectric:4.15.1"
roboletric-androidAll = "org.robolectric:android-all:13-robolectric-9030017"
-sebaslogen-resaca = "io.github.sebaslogen:resaca:4.3.0"
+sebaslogen-resaca = "io.github.sebaslogen:resaca:4.4.8"
squareup-okhttp3-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "com-squareup-okhttp3" }
test-espressoCore = "androidx.test.espresso:espresso-core:3.6.1"
test-ext-junit = "androidx.test.ext:junit:1.2.1"
@@ -111,7 +111,7 @@ classpath-dokkaGradlePlugin = { module = "org.jetbrains.dokka:dokka-gradle-plugi
classpath-dokkaBase = { module = "org.jetbrains.dokka:dokka-base", version.ref = "dokka" }
classpath-jlouns-gradleCrossPlatformExecPlugin = "gradle.plugin.com.github.jlouns:gradle-cross-platform-exec-plugin:0.5.0"
classpath-qmazzo-sqlitePlugin = "gradle.plugin.gmazzo:sqlite-plugin:0.2"
-classpath-bjoernq-unmockPlugin = "com.github.bjoernq:unmockplugin:0.8.0"
+classpath-bjoernq-unmockPlugin = "com.github.bjoernq:unmockplugin:0.9.0"
[bundles]
camera = [
@@ -157,6 +157,6 @@ kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref =
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
snabbleSetup = "io.snabble.setup:1.0.1"
unmock = "de.mobilej.unmock:0.7.9"
-benManesVersions = "com.github.ben-manes.versions:0.51.0"
-versionCatalogUpdate = "nl.littlerobots.version-catalog-update:0.8.4"
+benManesVersions = "com.github.ben-manes.versions:0.52.0"
+versionCatalogUpdate = "nl.littlerobots.version-catalog-update:1.0.0"
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e2847c8200..37f853b1c8 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/kotlin-sample/build.gradle.kts b/kotlin-sample/build.gradle.kts
index 595789ae42..dc2c557350 100644
--- a/kotlin-sample/build.gradle.kts
+++ b/kotlin-sample/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
plugins {
id(libs.plugins.androidApplication.get().pluginId)
id(libs.plugins.kotlin.android.get().pluginId)
@@ -17,7 +19,10 @@ android {
versionCode = 1
versionName = "1.0"
- resourceConfigurations.addAll(listOf("de", "en"))
+ androidResources {
+ localeFilters.addAll(listOf("de", "en"))
+ }
+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -35,12 +40,13 @@ android {
targetCompatibility = JavaVersion.VERSION_17
}
- kotlinOptions {
- freeCompilerArgs = listOf(
- *kotlinOptions.freeCompilerArgs.toTypedArray(),
- "-Xjvm-default=all"
- )
- jvmTarget = "17"
+ kotlin {
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_17
+ freeCompilerArgs.addAll(
+ "-Xjvm-default=all"
+ )
+ }
}
buildFeatures {
diff --git a/mlkit-scanner-engine/build.gradle.kts b/mlkit-scanner-engine/build.gradle.kts
index 31b95fa357..ff46be9b40 100644
--- a/mlkit-scanner-engine/build.gradle.kts
+++ b/mlkit-scanner-engine/build.gradle.kts
@@ -1,5 +1,7 @@
@file:Suppress("UnstableApiUsage")
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
plugins {
id(libs.plugins.androidLibrary.get().pluginId)
id(libs.plugins.kotlin.android.get().pluginId)
@@ -43,14 +45,16 @@ android {
targetCompatibility = JavaVersion.VERSION_17
}
- kotlinOptions {
- freeCompilerArgs = listOf(
- *kotlinOptions.freeCompilerArgs.toTypedArray(),
- "-Xjvm-default=all"
- )
- jvmTarget = "17"
+ kotlin {
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_17
+ freeCompilerArgs.addAll(
+ "-Xjvm-default=all"
+ )
+ }
}
+
lint {
abortOnError = false
}
diff --git a/ui-toolkit/build.gradle.kts b/ui-toolkit/build.gradle.kts
index e833257be6..9240e423f5 100644
--- a/ui-toolkit/build.gradle.kts
+++ b/ui-toolkit/build.gradle.kts
@@ -1,5 +1,7 @@
@file:Suppress("UnstableApiUsage")
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
plugins {
id(libs.plugins.androidLibrary.get().pluginId)
id(libs.plugins.kotlin.android.get().pluginId)
@@ -52,12 +54,13 @@ android {
targetCompatibility = JavaVersion.VERSION_17
}
- kotlinOptions {
- freeCompilerArgs = listOf(
- *kotlinOptions.freeCompilerArgs.toTypedArray(),
- "-Xjvm-default=all"
- )
- jvmTarget = "17"
+ kotlin {
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_17
+ freeCompilerArgs.addAll(
+ "-Xjvm-default=all"
+ )
+ }
}
buildFeatures {
@@ -97,6 +100,7 @@ dependencies {
implementation(libs.sebaslogen.resaca)
implementation(libs.bundles.compose)
+ implementation(libs.androidx.swiperefreshlayout)
debugImplementation(libs.bundles.compose.debug)
implementation(libs.bundles.koin)
diff --git a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/ButtonItem.kt b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/ButtonItem.kt
index 441c85cee4..54d4b3a491 100644
--- a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/ButtonItem.kt
+++ b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/ButtonItem.kt
@@ -5,7 +5,7 @@ import androidx.annotation.ColorRes
data class ButtonItem(
override val id: String,
val text: String,
- @ColorRes val foregroundColor: Int?,
- @ColorRes val backgroundColor: Int?,
+ @param:ColorRes val foregroundColor: Int?,
+ @param:ColorRes val backgroundColor: Int?,
val padding: Padding,
) : Widget
diff --git a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/CustomerCardItem.kt b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/CustomerCardItem.kt
index 85848a5d79..85dc24cbed 100644
--- a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/CustomerCardItem.kt
+++ b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/CustomerCardItem.kt
@@ -5,6 +5,6 @@ import androidx.annotation.DrawableRes
data class CustomerCardItem(
override val id: String,
val text: String,
- @DrawableRes val image: Int?,
+ @param:DrawableRes val image: Int?,
val padding: Padding,
) : Widget
diff --git a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/ImageItem.kt b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/ImageItem.kt
index b038aeac92..8015572890 100644
--- a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/ImageItem.kt
+++ b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/ImageItem.kt
@@ -4,6 +4,6 @@ import androidx.annotation.DrawableRes
data class ImageItem(
override val id: String,
- @DrawableRes val image: Int?,
+ @param:DrawableRes val image: Int?,
val padding: Padding,
) : Widget
diff --git a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/TextItem.kt b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/TextItem.kt
index 8575802aa7..8cda72006e 100644
--- a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/TextItem.kt
+++ b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/domain/model/TextItem.kt
@@ -5,7 +5,7 @@ import androidx.annotation.ColorInt
data class TextItem(
override val id: String,
val text: String,
- @ColorInt val textColor: Int? = null,
+ @param:ColorInt val textColor: Int? = null,
val textStyle: String? = null,
val showDisclosure: Boolean,
val padding: Padding,
diff --git a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/ui/DynamicScreen.kt b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/ui/DynamicScreen.kt
index b2133e9a1b..4c4d5fc7b5 100644
--- a/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/ui/DynamicScreen.kt
+++ b/ui-toolkit/src/main/kotlin/io/snabble/sdk/dynamicview/ui/DynamicScreen.kt
@@ -8,6 +8,7 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.viewmodel.compose.viewModel
import io.snabble.sdk.dynamicview.domain.model.Configuration
import io.snabble.sdk.dynamicview.domain.model.DynamicConfig
import io.snabble.sdk.dynamicview.domain.model.ImageItem
@@ -55,7 +56,9 @@ internal fun DynamicScreen(
@Composable
private fun DynamicScreenPreviewWith(config: DynamicConfig) {
ThemeWrapper {
- DynamicScreen(dynamicViewModel = DynamicViewModel().apply { setConfig(config) }, modifier = Modifier)
+ val viewModel: DynamicViewModel = viewModel()
+ viewModel.apply { setConfig(config) }
+ DynamicScreen(dynamicViewModel = viewModel, modifier = Modifier)
}
}
diff --git a/ui-toolkit/src/main/kotlin/io/snabble/sdk/screens/onboarding/ui/OnboardingFragment.kt b/ui-toolkit/src/main/kotlin/io/snabble/sdk/screens/onboarding/ui/OnboardingFragment.kt
index 4f746684b3..7118116100 100644
--- a/ui-toolkit/src/main/kotlin/io/snabble/sdk/screens/onboarding/ui/OnboardingFragment.kt
+++ b/ui-toolkit/src/main/kotlin/io/snabble/sdk/screens/onboarding/ui/OnboardingFragment.kt
@@ -43,7 +43,7 @@ open class OnboardingFragment : Fragment() {
val headerImage = view.findViewById(R.id.image_header)
headerImage.resolveImageOrHide(model.configuration?.imageSource)
- viewPager = view.findViewById(R.id.view_pager).apply {
+ viewPager = view.findViewById(R.id.view_pager).apply {
adapter = StepAdapter(model)
offscreenPageLimit = 1
}
diff --git a/ui-toolkit/src/main/kotlin/io/snabble/sdk/widgets/snabble/purchase/repository/PurchasesRepository.kt b/ui-toolkit/src/main/kotlin/io/snabble/sdk/widgets/snabble/purchase/repository/PurchasesRepository.kt
index a0418e2717..a0df979a9f 100644
--- a/ui-toolkit/src/main/kotlin/io/snabble/sdk/widgets/snabble/purchase/repository/PurchasesRepository.kt
+++ b/ui-toolkit/src/main/kotlin/io/snabble/sdk/widgets/snabble/purchase/repository/PurchasesRepository.kt
@@ -45,7 +45,7 @@ internal class PurchasesRepositoryImpl(
val receipts = filter { it.pdfUrl != null }
return when {
receipts.isEmpty() -> emptyList()
- else -> receipts.slice(0 until size.coerceAtMost(count))
+ else -> receipts.slice(0 until size.coerceAtMost(count).coerceAtMost(receipts.size))
.map { it.toPurchase(timeFormatter) }
}
}
diff --git a/ui-toolkit/src/main/kotlin/io/snabble/sdk/widgets/snabble/toggle/ui/ToggleWidget.kt b/ui-toolkit/src/main/kotlin/io/snabble/sdk/widgets/snabble/toggle/ui/ToggleWidget.kt
index 80157e8673..2506fa0c9a 100644
--- a/ui-toolkit/src/main/kotlin/io/snabble/sdk/widgets/snabble/toggle/ui/ToggleWidget.kt
+++ b/ui-toolkit/src/main/kotlin/io/snabble/sdk/widgets/snabble/toggle/ui/ToggleWidget.kt
@@ -16,7 +16,9 @@ import org.koin.core.parameter.parametersOf
internal fun ToggleWidget(
modifier: Modifier = Modifier,
model: ToggleItem,
- viewModel: ToggleViewModel = viewModelScoped(model.key) { KoinProvider.get { parametersOf(model.key) } },
+ viewModel: ToggleViewModel = viewModelScoped(key = model.key) {
+ KoinProvider.get { parametersOf(model.key) }
+ },
onAction: OnDynamicAction,
) {
val isCheckedState = viewModel.toggleState.collectAsStateWithLifecycle()
diff --git a/ui/build.gradle.kts b/ui/build.gradle.kts
index 0d00861273..f9178fbc56 100644
--- a/ui/build.gradle.kts
+++ b/ui/build.gradle.kts
@@ -1,5 +1,7 @@
@file:Suppress("UnstableApiUsage")
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
plugins {
id(libs.plugins.androidLibrary.get().pluginId)
id(libs.plugins.kotlin.android.get().pluginId)
@@ -47,12 +49,13 @@ android {
targetCompatibility = JavaVersion.VERSION_17
}
- kotlinOptions {
- freeCompilerArgs = listOf(
- *kotlinOptions.freeCompilerArgs.toTypedArray(),
- "-Xjvm-default=all"
- )
- jvmTarget = "17"
+ kotlin {
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_17
+ freeCompilerArgs.addAll(
+ "-Xjvm-default=all"
+ )
+ }
}
lint {
diff --git a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt
index b488a033dc..af38219b0e 100644
--- a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt
+++ b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt
@@ -11,7 +11,7 @@ import androidx.fragment.app.Fragment
import io.snabble.sdk.InitializationState
import io.snabble.sdk.Snabble
-abstract class BaseFragment(@LayoutRes val layoutResId: Int = 0, val waitForProject: Boolean = true) : Fragment() {
+abstract class BaseFragment(@param:LayoutRes val layoutResId: Int = 0, val waitForProject: Boolean = true) : Fragment() {
private lateinit var sdkNotInitialized: TextView
private lateinit var fragmentContainer: ViewGroup
diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/shoppingcart/cartdiscount/model/CartDiscountItem.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/shoppingcart/cartdiscount/model/CartDiscountItem.kt
index 26e5656dd9..21cb7ed9cb 100644
--- a/ui/src/main/java/io/snabble/sdk/ui/cart/shoppingcart/cartdiscount/model/CartDiscountItem.kt
+++ b/ui/src/main/java/io/snabble/sdk/ui/cart/shoppingcart/cartdiscount/model/CartDiscountItem.kt
@@ -8,8 +8,8 @@ import io.snabble.sdk.ui.cart.shoppingcart.CartItem
internal data class CartDiscountItem(
override val item: ShoppingCart.Item,
- @StringRes val title: Int = R.string.Snabble_Shoppingcart_discounts,
+ @param:StringRes val title: Int = R.string.Snabble_Shoppingcart_discounts,
val discount: String,
val name: String,
- @DrawableRes val imageResId: Int = R.drawable.snabble_ic_percent
+ @param:DrawableRes val imageResId: Int = R.drawable.snabble_ic_percent
) : CartItem
diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt
index ef386f946f..cdf873365b 100644
--- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt
+++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt
@@ -1,22 +1,23 @@
package io.snabble.sdk.ui.checkout
-import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
+import android.content.res.Configuration
+import android.graphics.Color
+import android.os.Build
import android.os.Bundle
+import android.view.Gravity
import android.view.View
import android.view.ViewGroup
-import android.view.WindowManager
import android.widget.FrameLayout
import androidx.activity.addCallback
import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible
-import androidx.core.view.updateLayoutParams
-import androidx.core.view.updateMargins
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Observer
import androidx.navigation.NavController
@@ -42,6 +43,9 @@ class CheckoutActivity : FragmentActivity() {
const val ARG_PROJECT_ID = "projectId"
+ private const val HSV_COLOR_SIZE = 3
+ private const val DARKEN_FACTOR = 0.2f
+
@JvmStatic
fun startCheckoutFlow(context: Context, newTask: Boolean = false) {
val intent = Intent(context, CheckoutActivity::class.java).apply {
@@ -157,7 +161,7 @@ class CheckoutActivity : FragmentActivity() {
private fun setUpToolBarAndStatusBar() {
val showToolBar = resources.getBoolean(R.bool.showToolbarInCheckout)
- findViewById(R.id.checkout_toolbar_spacer)?.isVisible = showToolBar
+ findViewById(R.id.checkout_toolbar)?.isVisible = showToolBar
navController.addOnDestinationChangedListener { _, _, arguments ->
findViewById(R.id.checkout_toolbar)?.isVisible =
@@ -165,19 +169,13 @@ class CheckoutActivity : FragmentActivity() {
val toolBarColor =
this@CheckoutActivity.toolBarColorForProject(Snabble.checkedInProject.value)
+ if (showToolBar) toolBarColor?.let { applyStatusBarStyling(toolBarColor) }
val onToolBarColor =
this@CheckoutActivity.onToolBarColorForProject(Snabble.checkedInProject.value)
this.findViewById(R.id.checkout_toolbar).apply {
toolBarColor?.let(::setBackgroundColor)
onToolBarColor?.let(::setTitleTextColor)
}
- this.findViewById(R.id.checkout_toolbar_spacer).apply {
- toolBarColor?.let(::setBackgroundColor)
- }
- }
-
- if (showToolBar) {
- applyInsets()
}
}
@@ -256,35 +254,63 @@ class CheckoutActivity : FragmentActivity() {
}
}
- private fun applyInsets() {
- val root = findViewById(R.id.root) ?: return
-
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
- WindowCompat.setDecorFitsSystemWindows(window, false)
+ private fun applyStatusBarStyling(color: Int) {
+ val root = findViewById(R.id.root)
val windowInsetsController = WindowInsetsControllerCompat(window, root)
+ setStatusBarColor(darkenColor(color))
+ windowInsetsController.isAppearanceLightStatusBars = !isNightModeActive
+ }
- ViewCompat.setOnApplyWindowInsetsListener(root) { view, windowInsets ->
- window.statusBarColor = 0x22000000
- windowInsetsController.isAppearanceLightStatusBars = false
-
- val currentInsetTypeMask = listOf(
- WindowInsetsCompat.Type.navigationBars(),
- WindowInsetsCompat.Type.ime(),
- WindowInsetsCompat.Type.systemBars(),
- WindowInsetsCompat.Type.statusBars()
- ).fold(0) { accumulator, type -> accumulator or type }
-
- @SuppressLint("WrongConstant")
- val insets = windowInsets.getInsets(currentInsetTypeMask)
- view.updateLayoutParams {
- updateMargins(insets.left, 0, insets.right, insets.bottom)
- }
- findViewById(R.id.checkout_toolbar_spacer)?.apply {
- setPadding(0, insets.top, 0, 0)
+ private fun darkenColor(color: Int): Int {
+ val hsv = FloatArray(HSV_COLOR_SIZE)
+ Color.colorToHSV(color, hsv)
+ hsv[2] *= (1f - DARKEN_FACTOR) // Reduce brightness
+ return Color.HSVToColor(hsv)
+ }
+
+ private fun setStatusBarColor(color: Int) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { // API 35+
+ // For API 35+, use edge-to-edge but handle status bar coloring properly
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+
+ // Create a status bar overlay instead of coloring the entire root view
+ ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.root)) { view, insets ->
+ val statusBarInsets = insets.getInsets(WindowInsetsCompat.Type.statusBars())
+
+ // Create a colored overlay just for the status bar area
+ createStatusBarOverlay(color, statusBarInsets.top)
+
+ insets
}
+ } else {
+ // For API < 35, use the traditional method
+ @Suppress("DEPRECATION")
+ window.statusBarColor = color
+ }
+ }
- windowInsets.inset(insets.left, insets.top, insets.right, insets.bottom)
+ private var statusBarOverlay: View? = null
+
+ private fun createStatusBarOverlay(color: Int, height: Int) {
+ // Remove any existing overlay
+ statusBarOverlay?.let {
+ (it.parent as? ViewGroup)?.removeView(it)
}
+
+ // Create new overlay positioned absolutely at the top
+ statusBarOverlay = View(this).apply {
+ setBackgroundColor(color)
+ layoutParams = FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ height
+ ).apply {
+ gravity = Gravity.TOP // Position at the very top
+ }
+ }
+
+ // Add overlay to the window's decor view
+ val decorView = window.decorView as FrameLayout
+ decorView.addView(statusBarOverlay)
}
private fun onStateChanged() {
@@ -297,3 +323,14 @@ class CheckoutActivity : FragmentActivity() {
}.build())
}
}
+
+val Context.isNightModeActive: Boolean
+ get() {
+ return when (AppCompatDelegate.getDefaultNightMode()) {
+ AppCompatDelegate.MODE_NIGHT_YES -> true
+ AppCompatDelegate.MODE_NIGHT_NO -> false
+ else ->
+ resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
+ Configuration.UI_MODE_NIGHT_YES
+ }
+ }
diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentMethodMetaData.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentMethodMetaData.kt
index 16fbc38666..14ffe2bd95 100644
--- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentMethodMetaData.kt
+++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentMethodMetaData.kt
@@ -71,6 +71,6 @@ class PaymentMethodMetaDataHelper(
}
data class PaymentMethodMetaData(
- @DrawableRes val iconResId: Int,
+ @param:DrawableRes val iconResId: Int,
val label: String
)
diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt
index cbca15667f..f72df60a1a 100644
--- a/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt
+++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt
@@ -8,7 +8,6 @@ import io.snabble.sdk.Unit
import io.snabble.sdk.codes.ScannedCode
import io.snabble.sdk.codes.gs1.GS1Code
import io.snabble.sdk.ui.R
-import io.snabble.sdk.ui.scanner.ProductResolver.*
import io.snabble.sdk.ui.telemetry.Telemetry
import io.snabble.sdk.ui.utils.DelayedProgressDialog
import io.snabble.sdk.ui.utils.UIUtils
@@ -112,9 +111,9 @@ class ProductResolver private constructor(private val context: Context, private
for (i in scannedCodes.indices) {
val scannedCode = scannedCodes[i]
productDatabase.findByCodeOnline(scannedCode, object : OnProductAvailableListener {
- override fun onProductAvailable(product: Product, wasOnlineProduct: Boolean) {
+ override fun onProductAvailable(product: Product, wasOnline: Boolean) {
result.product = product
- result.wasOnlineProduct = wasOnlineProduct
+ result.wasOnlineProduct = wasOnline
result.code = scannedCode
result.matchCount++
countDownLatch.countDown()
diff --git a/ui/src/main/res/layout/snabble_activity_checkout.xml b/ui/src/main/res/layout/snabble_activity_checkout.xml
index 7b99a9bcc5..8dd4ea0553 100644
--- a/ui/src/main/res/layout/snabble_activity_checkout.xml
+++ b/ui/src/main/res/layout/snabble_activity_checkout.xml
@@ -7,13 +7,10 @@
android:fitsSystemWindows="true"
android:orientation="vertical">
-
-
+ android:fitsSystemWindows="true">
-
+