From e33725ceae9c274992527ce3660a12e27fc184df Mon Sep 17 00:00:00 2001 From: denwritescode Date: Thu, 16 Jul 2026 10:04:48 +0300 Subject: [PATCH 1/4] isolate multiplatform-settings behind a SettingsStore seam Co-Authored-By: Claude Opus 4.8 --- clients/tablet/composeApp/build.gradle.kts | 6 ++++-- .../kotlin/band/effective/office/tablet/App.kt | 15 +++++++-------- .../band/effective/office/tablet/Initializers.kt | 8 +++++++- clients/tablet/core/domain/build.gradle.kts | 1 - .../office/tablet/core/domain/model/Settings.kt | 5 ++--- .../tablet/core/domain/model/SettingsStore.kt | 7 +++++++ 6 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/SettingsStore.kt diff --git a/clients/tablet/composeApp/build.gradle.kts b/clients/tablet/composeApp/build.gradle.kts index b2f1c74ca..8eaa52536 100644 --- a/clients/tablet/composeApp/build.gradle.kts +++ b/clients/tablet/composeApp/build.gradle.kts @@ -48,8 +48,6 @@ kotlin { implementation(libs.napier) - implementation(libs.settings) - implementation(project(":clients:tablet:core:ui")) implementation(project(":clients:tablet:feature:main")) implementation(project(":clients:tablet:feature:settings")) @@ -66,6 +64,10 @@ kotlin { implementation(libs.koin.android) implementation("org.slf4j:slf4j-android:1.7.36") implementation(libs.firebase.messaging.ktx) + implementation(libs.settings) + } + iosMain.dependencies { + implementation(libs.settings) } } } diff --git a/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt b/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt index eb00f2b5f..c62270cf8 100644 --- a/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt +++ b/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt @@ -3,6 +3,7 @@ package band.effective.office.tablet import android.app.Application import band.effective.office.tablet.core.domain.manager.DateResetManager import band.effective.office.tablet.core.domain.model.SettingsManager +import band.effective.office.tablet.core.domain.model.SettingsStore import band.effective.office.tablet.core.ui.inactivity.InactivityLifecycleCallbacks import band.effective.office.tablet.di.KoinInitializer import com.google.firebase.messaging.FirebaseMessaging @@ -17,14 +18,12 @@ class App : Application() { super.onCreate() LoggerInitializer().init() KoinInitializer().init() - SettingsManager.init( - SharedPreferencesSettings( - this.getSharedPreferences( - "settings", - MODE_PRIVATE - ) - ) - ) + val settings = SharedPreferencesSettings(getSharedPreferences("settings", MODE_PRIVATE)) + SettingsManager.init(object : SettingsStore { + override fun getString(key: String, defaultValue: String) = settings.getString(key, defaultValue) + override fun putString(key: String, value: String) = settings.putString(key, value) + override fun remove(key: String) = settings.remove(key) + }) subscribeOnFirebaseTopics() initializeInactivitySystem() } diff --git a/clients/tablet/composeApp/src/iosMain/kotlin/band/effective/office/tablet/Initializers.kt b/clients/tablet/composeApp/src/iosMain/kotlin/band/effective/office/tablet/Initializers.kt index 538fa6357..d5e3b624e 100644 --- a/clients/tablet/composeApp/src/iosMain/kotlin/band/effective/office/tablet/Initializers.kt +++ b/clients/tablet/composeApp/src/iosMain/kotlin/band/effective/office/tablet/Initializers.kt @@ -1,6 +1,7 @@ package band.effective.office.tablet import band.effective.office.tablet.core.domain.model.SettingsManager +import band.effective.office.tablet.core.domain.model.SettingsStore import band.effective.office.tablet.di.KoinInitializer import com.russhwolf.settings.KeychainSettings @@ -9,6 +10,11 @@ class Initializers { fun init() { LoggerInitializer().init() KoinInitializer().init() - SettingsManager.init(KeychainSettings("effectiveOffice")) + val settings = KeychainSettings("effectiveOffice") + SettingsManager.init(object : SettingsStore { + override fun getString(key: String, defaultValue: String) = settings.getString(key, defaultValue) + override fun putString(key: String, value: String) = settings.putString(key, value) + override fun remove(key: String) = settings.remove(key) + }) } } \ No newline at end of file diff --git a/clients/tablet/core/domain/build.gradle.kts b/clients/tablet/core/domain/build.gradle.kts index fe275ca15..b7c232c4c 100644 --- a/clients/tablet/core/domain/build.gradle.kts +++ b/clients/tablet/core/domain/build.gradle.kts @@ -8,7 +8,6 @@ kotlin { api(project(":clients:shared:core")) api(libs.kotlinx.datetime) implementation(libs.kotlin.coroutines.core) - implementation(libs.settings) implementation(libs.bundles.koin) } androidMain.dependencies { diff --git a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/Settings.kt b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/Settings.kt index 7eaa5d55a..a600b69fb 100644 --- a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/Settings.kt +++ b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/Settings.kt @@ -1,7 +1,6 @@ package band.effective.office.tablet.core.domain.model -import com.russhwolf.settings.* -class SettingsManager(private val settings: Settings) { +class SettingsManager(private val settings: SettingsStore) { companion object { private const val KEY_NAME_ROOM = "nameRoom" @@ -9,7 +8,7 @@ class SettingsManager(private val settings: Settings) { // Singleton-like instance private var currentInstance: SettingsManager? = null - fun init(settings: Settings) { + fun init(settings: SettingsStore) { if(currentInstance == null) { currentInstance = SettingsManager(settings) } diff --git a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/SettingsStore.kt b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/SettingsStore.kt new file mode 100644 index 000000000..4f8e34310 --- /dev/null +++ b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/SettingsStore.kt @@ -0,0 +1,7 @@ +package band.effective.office.tablet.core.domain.model + +interface SettingsStore { + fun getString(key: String, defaultValue: String): String + fun putString(key: String, value: String) + fun remove(key: String) +} From 3510299bb202008f855f1ba51d852ac65305da99 Mon Sep 17 00:00:00 2001 From: denwritescode Date: Thu, 16 Jul 2026 10:06:16 +0300 Subject: [PATCH 2/4] move FCM topic module out of commonMain to androidMain Co-Authored-By: Claude Opus 4.8 --- .../androidMain/kotlin/band/effective/office/tablet/App.kt | 3 ++- .../band/effective/office/tablet/di/FirebaseTopicsModule.kt | 0 .../band/effective/office/tablet/di/KoinInitializer.kt | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) rename clients/tablet/composeApp/src/{commonMain => androidMain}/kotlin/band/effective/office/tablet/di/FirebaseTopicsModule.kt (100%) diff --git a/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt b/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt index c62270cf8..7a5194077 100644 --- a/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt +++ b/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt @@ -6,6 +6,7 @@ import band.effective.office.tablet.core.domain.model.SettingsManager import band.effective.office.tablet.core.domain.model.SettingsStore import band.effective.office.tablet.core.ui.inactivity.InactivityLifecycleCallbacks import band.effective.office.tablet.di.KoinInitializer +import band.effective.office.tablet.di.firebaseTopicsModule import com.google.firebase.messaging.FirebaseMessaging import com.russhwolf.settings.SharedPreferencesSettings import org.koin.android.ext.android.get @@ -17,7 +18,7 @@ class App : Application() { override fun onCreate() { super.onCreate() LoggerInitializer().init() - KoinInitializer().init() + KoinInitializer().init(listOf(firebaseTopicsModule)) val settings = SharedPreferencesSettings(getSharedPreferences("settings", MODE_PRIVATE)) SettingsManager.init(object : SettingsStore { override fun getString(key: String, defaultValue: String) = settings.getString(key, defaultValue) diff --git a/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/FirebaseTopicsModule.kt b/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/di/FirebaseTopicsModule.kt similarity index 100% rename from clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/FirebaseTopicsModule.kt rename to clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/di/FirebaseTopicsModule.kt diff --git a/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/KoinInitializer.kt b/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/KoinInitializer.kt index 1078708f6..5fc88bc67 100644 --- a/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/KoinInitializer.kt +++ b/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/KoinInitializer.kt @@ -8,13 +8,13 @@ import band.effective.office.tablet.feature.main.di.mainScreenModule import band.effective.office.tablet.feature.settings.di.settingsModule import band.effective.office.tablet.feature.slot.di.slotDiModule import org.koin.core.context.startKoin +import org.koin.core.module.Module class KoinInitializer { - fun init() { + fun init(platformModules: List = emptyList()) { startKoin { modules( appModule, - firebaseTopicsModule, dataModule, domainModule, mainScreenModule, @@ -22,6 +22,7 @@ class KoinInitializer { bookingEditorModule, fastBookingModule, slotDiModule, + *platformModules.toTypedArray(), ) } } From 0bc0f6bcbd78c15082a7ca34e1ab7dd9e5f8098b Mon Sep 17 00:00:00 2001 From: denwritescode Date: Thu, 16 Jul 2026 10:19:54 +0300 Subject: [PATCH 3/4] wrap calf date/time pickers behind an expect/actual seam Move calf out of the shared kmp.ui classpath into bookingEditor's android/ios source sets; drop the composeApp iOS-framework calf export. Co-Authored-By: Claude Opus 4.8 --- ....effective.office.client.kmp.ui.gradle.kts | 1 - clients/tablet/composeApp/build.gradle.kts | 3 - .../feature/bookingEditor/build.gradle.kts | 11 +++ .../components/DatePickerView.android.kt | 72 +++++++++++++++++++ .../components/TimePickerView.android.kt | 61 ++++++++++++++++ .../components/DatePickerView.kt | 63 +--------------- .../components/TimePickerView.kt | 54 +------------- .../components/DatePickerView.ios.kt | 72 +++++++++++++++++++ .../components/TimePickerView.ios.kt | 61 ++++++++++++++++ 9 files changed, 282 insertions(+), 116 deletions(-) create mode 100644 clients/tablet/feature/bookingEditor/src/androidMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.android.kt create mode 100644 clients/tablet/feature/bookingEditor/src/androidMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.android.kt create mode 100644 clients/tablet/feature/bookingEditor/src/iosMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.ios.kt create mode 100644 clients/tablet/feature/bookingEditor/src/iosMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.ios.kt diff --git a/build-logic/src/main/kotlin/band/effective/office/backend/band.effective.office.client.kmp.ui.gradle.kts b/build-logic/src/main/kotlin/band/effective/office/backend/band.effective.office.client.kmp.ui.gradle.kts index 638ab6541..bb68b6d27 100644 --- a/build-logic/src/main/kotlin/band/effective/office/backend/band.effective.office.client.kmp.ui.gradle.kts +++ b/build-logic/src/main/kotlin/band/effective/office/backend/band.effective.office.client.kmp.ui.gradle.kts @@ -17,7 +17,6 @@ kotlin { implementation(compose.components.uiToolingPreview) implementation(libs.findLibrary("coil").get()) implementation(libs.findLibrary("coil.network.ktor").get()) - api(libs.findLibrary("calf-ui").get()) } androidMain.dependencies { diff --git a/clients/tablet/composeApp/build.gradle.kts b/clients/tablet/composeApp/build.gradle.kts index 8eaa52536..eb19c1950 100644 --- a/clients/tablet/composeApp/build.gradle.kts +++ b/clients/tablet/composeApp/build.gradle.kts @@ -22,8 +22,6 @@ kotlin { it.binaries.framework { baseName = "ComposeApp" isStatic = true - - export(libs.calf.ui) } } @@ -35,7 +33,6 @@ kotlin { implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) - api(libs.calf.ui) api(libs.kotlinx.datetime) implementation(libs.jetbrains.navigation.compose) diff --git a/clients/tablet/feature/bookingEditor/build.gradle.kts b/clients/tablet/feature/bookingEditor/build.gradle.kts index 51e029ee5..125da6ec6 100644 --- a/clients/tablet/feature/bookingEditor/build.gradle.kts +++ b/clients/tablet/feature/bookingEditor/build.gradle.kts @@ -2,6 +2,17 @@ plugins { id("band.effective.office.client.kmp.feature") } +kotlin { + sourceSets { + androidMain.dependencies { + implementation(libs.calf.ui) + } + iosMain.dependencies { + implementation(libs.calf.ui) + } + } +} + compose.resources { publicResClass = false packageOfResClass = "band.effective.office.tablet.feature.bookingEditor" diff --git a/clients/tablet/feature/bookingEditor/src/androidMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.android.kt b/clients/tablet/feature/bookingEditor/src/androidMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.android.kt new file mode 100644 index 000000000..8349311f4 --- /dev/null +++ b/clients/tablet/feature/bookingEditor/src/androidMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.android.kt @@ -0,0 +1,72 @@ +package band.effective.office.tablet.feature.bookingEditor.presentation.datetimepicker.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.material3.DatePickerDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Modifier +import band.effective.office.shared.core.utils.asInstant +import band.effective.office.shared.core.utils.asLocalDateTime +import band.effective.office.tablet.core.ui.theme.LocalCustomColorsPalette +import com.mohamedrejeb.calf.ui.datepicker.AdaptiveDatePicker +import com.mohamedrejeb.calf.ui.datepicker.rememberAdaptiveDatePickerState +import kotlinx.datetime.Instant +import kotlinx.datetime.LocalDate +import kotlinx.datetime.LocalDateTime + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +actual fun DatePickerView( + modifier: Modifier, + currentDate: LocalDateTime, + onChangeDate: (LocalDate) -> Unit, +) { + // Create and remember the date picker state + val state = rememberAdaptiveDatePickerState( + initialSelectedDateMillis = currentDate.asInstant.toEpochMilliseconds(), + ) + + // React to date changes + LaunchedEffect(state.selectedDateMillis) { + val selectedDate = state.selectedDateMillis?.let { millis -> + Instant.fromEpochMilliseconds(millis).asLocalDateTime.date + } + + selectedDate?.let { + val year = it.year + val month = it.month + val day = it.dayOfMonth + onChangeDate(LocalDate(year, month, day)) + } + } + + val palette = LocalCustomColorsPalette.current + val accent = MaterialTheme.colorScheme.primary + val onAccent = MaterialTheme.colorScheme.onPrimary + + Column { + AdaptiveDatePicker( + state = state, + modifier = modifier, + colors = DatePickerDefaults.colors( + containerColor = palette.elevationBackground, + titleContentColor = palette.primaryTextAndIcon, + headlineContentColor = palette.primaryTextAndIcon, + weekdayContentColor = palette.secondaryTextAndIcon, + subheadContentColor = palette.primaryTextAndIcon, + navigationContentColor = accent, + yearContentColor = palette.primaryTextAndIcon, + currentYearContentColor = accent, + selectedYearContentColor = onAccent, + selectedYearContainerColor = accent, + dayContentColor = palette.primaryTextAndIcon, + selectedDayContentColor = onAccent, + selectedDayContainerColor = accent, + todayContentColor = accent, + todayDateBorderColor = accent, + ), + ) + } +} diff --git a/clients/tablet/feature/bookingEditor/src/androidMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.android.kt b/clients/tablet/feature/bookingEditor/src/androidMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.android.kt new file mode 100644 index 000000000..474c4eb4e --- /dev/null +++ b/clients/tablet/feature/bookingEditor/src/androidMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.android.kt @@ -0,0 +1,61 @@ +package band.effective.office.tablet.feature.bookingEditor.presentation.datetimepicker.components + +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.TimePickerDefaults +import androidx.compose.material3.TimePickerLayoutType +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Modifier +import band.effective.office.tablet.core.ui.theme.LocalCustomColorsPalette +import band.effective.office.tablet.core.ui.utils.DateDisplayMapper +import com.mohamedrejeb.calf.ui.timepicker.AdaptiveTimePicker +import com.mohamedrejeb.calf.ui.timepicker.rememberAdaptiveTimePickerState +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.LocalTime + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +actual fun TimePickerView( + modifier: Modifier, + currentDate: LocalDateTime, + onSnap: (LocalTime) -> Unit, +) { + val is24Hour = DateDisplayMapper.is24HourFormat() + + val state = rememberAdaptiveTimePickerState( + initialHour = currentDate.hour, + initialMinute = currentDate.minute, + is24Hour = is24Hour + ) + LaunchedEffect(state.hour, state.minute) { + val hour = state.hour + val minute = state.minute + onSnap(LocalTime(hour, minute, 0)) + } + + val palette = LocalCustomColorsPalette.current + val accent = MaterialTheme.colorScheme.primary + val onAccent = MaterialTheme.colorScheme.onPrimary + + AdaptiveTimePicker( + state = state, + modifier = modifier, + layoutType = TimePickerLayoutType.Vertical, + colors = TimePickerDefaults.colors( + containerColor = palette.elevationBackground, + clockDialColor = MaterialTheme.colorScheme.surface, + selectorColor = accent, + clockDialSelectedContentColor = onAccent, + clockDialUnselectedContentColor = palette.primaryTextAndIcon, + periodSelectorSelectedContainerColor = accent, + periodSelectorUnselectedContainerColor = MaterialTheme.colorScheme.surface, + periodSelectorSelectedContentColor = onAccent, + periodSelectorUnselectedContentColor = palette.primaryTextAndIcon, + timeSelectorSelectedContainerColor = accent, + timeSelectorUnselectedContainerColor = MaterialTheme.colorScheme.surface, + timeSelectorSelectedContentColor = onAccent, + timeSelectorUnselectedContentColor = palette.primaryTextAndIcon, + ) + ) +} diff --git a/clients/tablet/feature/bookingEditor/src/commonMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.kt b/clients/tablet/feature/bookingEditor/src/commonMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.kt index 0f6e512d2..98989fa2d 100644 --- a/clients/tablet/feature/bookingEditor/src/commonMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.kt +++ b/clients/tablet/feature/bookingEditor/src/commonMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.kt @@ -1,72 +1,13 @@ package band.effective.office.tablet.feature.bookingEditor.presentation.datetimepicker.components -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.DatePickerDefaults -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier -import band.effective.office.shared.core.utils.asInstant -import band.effective.office.shared.core.utils.asLocalDateTime -import band.effective.office.tablet.core.ui.theme.LocalCustomColorsPalette -import com.mohamedrejeb.calf.ui.datepicker.AdaptiveDatePicker -import com.mohamedrejeb.calf.ui.datepicker.rememberAdaptiveDatePickerState -import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate import kotlinx.datetime.LocalDateTime -@OptIn(ExperimentalMaterial3Api::class) @Composable -fun DatePickerView( +expect fun DatePickerView( modifier: Modifier = Modifier, currentDate: LocalDateTime, onChangeDate: (LocalDate) -> Unit, -) { - // Create and remember the date picker state - val state = rememberAdaptiveDatePickerState( - initialSelectedDateMillis = currentDate.asInstant.toEpochMilliseconds(), - ) - - // React to date changes - LaunchedEffect(state.selectedDateMillis) { - val selectedDate = state.selectedDateMillis?.let { millis -> - Instant.fromEpochMilliseconds(millis).asLocalDateTime.date - } - - selectedDate?.let { - val year = it.year - val month = it.month - val day = it.dayOfMonth - onChangeDate(LocalDate(year, month, day)) - } - } - - val palette = LocalCustomColorsPalette.current - val accent = MaterialTheme.colorScheme.primary - val onAccent = MaterialTheme.colorScheme.onPrimary - - Column { - AdaptiveDatePicker( - state = state, - modifier = modifier, - colors = DatePickerDefaults.colors( - containerColor = palette.elevationBackground, - titleContentColor = palette.primaryTextAndIcon, - headlineContentColor = palette.primaryTextAndIcon, - weekdayContentColor = palette.secondaryTextAndIcon, - subheadContentColor = palette.primaryTextAndIcon, - navigationContentColor = accent, - yearContentColor = palette.primaryTextAndIcon, - currentYearContentColor = accent, - selectedYearContentColor = onAccent, - selectedYearContainerColor = accent, - dayContentColor = palette.primaryTextAndIcon, - selectedDayContentColor = onAccent, - selectedDayContainerColor = accent, - todayContentColor = accent, - todayDateBorderColor = accent, - ), - ) - } -} +) diff --git a/clients/tablet/feature/bookingEditor/src/commonMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.kt b/clients/tablet/feature/bookingEditor/src/commonMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.kt index 25f7bf861..571cb09b4 100644 --- a/clients/tablet/feature/bookingEditor/src/commonMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.kt +++ b/clients/tablet/feature/bookingEditor/src/commonMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.kt @@ -1,61 +1,13 @@ package band.effective.office.tablet.feature.bookingEditor.presentation.datetimepicker.components -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.TimePickerDefaults -import androidx.compose.material3.TimePickerLayoutType import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier -import band.effective.office.tablet.core.ui.theme.LocalCustomColorsPalette -import band.effective.office.tablet.core.ui.utils.DateDisplayMapper -import com.mohamedrejeb.calf.ui.timepicker.AdaptiveTimePicker -import com.mohamedrejeb.calf.ui.timepicker.rememberAdaptiveTimePickerState import kotlinx.datetime.LocalDateTime import kotlinx.datetime.LocalTime -@OptIn(ExperimentalMaterial3Api::class) @Composable -fun TimePickerView( +expect fun TimePickerView( modifier: Modifier = Modifier, currentDate: LocalDateTime, - onSnap: (LocalTime) -> Unit -) { - val is24Hour = DateDisplayMapper.is24HourFormat() - - val state = rememberAdaptiveTimePickerState( - initialHour = currentDate.hour, - initialMinute = currentDate.minute, - is24Hour = is24Hour - ) - LaunchedEffect(state.hour, state.minute) { - val hour = state.hour - val minute = state.minute - onSnap(LocalTime(hour, minute, 0)) - } - - val palette = LocalCustomColorsPalette.current - val accent = MaterialTheme.colorScheme.primary - val onAccent = MaterialTheme.colorScheme.onPrimary - - AdaptiveTimePicker( - state = state, - modifier = modifier, - layoutType = TimePickerLayoutType.Vertical, - colors = TimePickerDefaults.colors( - containerColor = palette.elevationBackground, - clockDialColor = MaterialTheme.colorScheme.surface, - selectorColor = accent, - clockDialSelectedContentColor = onAccent, - clockDialUnselectedContentColor = palette.primaryTextAndIcon, - periodSelectorSelectedContainerColor = accent, - periodSelectorUnselectedContainerColor = MaterialTheme.colorScheme.surface, - periodSelectorSelectedContentColor = onAccent, - periodSelectorUnselectedContentColor = palette.primaryTextAndIcon, - timeSelectorSelectedContainerColor = accent, - timeSelectorUnselectedContainerColor = MaterialTheme.colorScheme.surface, - timeSelectorSelectedContentColor = onAccent, - timeSelectorUnselectedContentColor = palette.primaryTextAndIcon, - ) - ) -} \ No newline at end of file + onSnap: (LocalTime) -> Unit, +) diff --git a/clients/tablet/feature/bookingEditor/src/iosMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.ios.kt b/clients/tablet/feature/bookingEditor/src/iosMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.ios.kt new file mode 100644 index 000000000..8349311f4 --- /dev/null +++ b/clients/tablet/feature/bookingEditor/src/iosMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/DatePickerView.ios.kt @@ -0,0 +1,72 @@ +package band.effective.office.tablet.feature.bookingEditor.presentation.datetimepicker.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.material3.DatePickerDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Modifier +import band.effective.office.shared.core.utils.asInstant +import band.effective.office.shared.core.utils.asLocalDateTime +import band.effective.office.tablet.core.ui.theme.LocalCustomColorsPalette +import com.mohamedrejeb.calf.ui.datepicker.AdaptiveDatePicker +import com.mohamedrejeb.calf.ui.datepicker.rememberAdaptiveDatePickerState +import kotlinx.datetime.Instant +import kotlinx.datetime.LocalDate +import kotlinx.datetime.LocalDateTime + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +actual fun DatePickerView( + modifier: Modifier, + currentDate: LocalDateTime, + onChangeDate: (LocalDate) -> Unit, +) { + // Create and remember the date picker state + val state = rememberAdaptiveDatePickerState( + initialSelectedDateMillis = currentDate.asInstant.toEpochMilliseconds(), + ) + + // React to date changes + LaunchedEffect(state.selectedDateMillis) { + val selectedDate = state.selectedDateMillis?.let { millis -> + Instant.fromEpochMilliseconds(millis).asLocalDateTime.date + } + + selectedDate?.let { + val year = it.year + val month = it.month + val day = it.dayOfMonth + onChangeDate(LocalDate(year, month, day)) + } + } + + val palette = LocalCustomColorsPalette.current + val accent = MaterialTheme.colorScheme.primary + val onAccent = MaterialTheme.colorScheme.onPrimary + + Column { + AdaptiveDatePicker( + state = state, + modifier = modifier, + colors = DatePickerDefaults.colors( + containerColor = palette.elevationBackground, + titleContentColor = palette.primaryTextAndIcon, + headlineContentColor = palette.primaryTextAndIcon, + weekdayContentColor = palette.secondaryTextAndIcon, + subheadContentColor = palette.primaryTextAndIcon, + navigationContentColor = accent, + yearContentColor = palette.primaryTextAndIcon, + currentYearContentColor = accent, + selectedYearContentColor = onAccent, + selectedYearContainerColor = accent, + dayContentColor = palette.primaryTextAndIcon, + selectedDayContentColor = onAccent, + selectedDayContainerColor = accent, + todayContentColor = accent, + todayDateBorderColor = accent, + ), + ) + } +} diff --git a/clients/tablet/feature/bookingEditor/src/iosMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.ios.kt b/clients/tablet/feature/bookingEditor/src/iosMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.ios.kt new file mode 100644 index 000000000..474c4eb4e --- /dev/null +++ b/clients/tablet/feature/bookingEditor/src/iosMain/kotlin/band/effective/office/tablet/feature/bookingEditor/presentation/datetimepicker/components/TimePickerView.ios.kt @@ -0,0 +1,61 @@ +package band.effective.office.tablet.feature.bookingEditor.presentation.datetimepicker.components + +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.TimePickerDefaults +import androidx.compose.material3.TimePickerLayoutType +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Modifier +import band.effective.office.tablet.core.ui.theme.LocalCustomColorsPalette +import band.effective.office.tablet.core.ui.utils.DateDisplayMapper +import com.mohamedrejeb.calf.ui.timepicker.AdaptiveTimePicker +import com.mohamedrejeb.calf.ui.timepicker.rememberAdaptiveTimePickerState +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.LocalTime + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +actual fun TimePickerView( + modifier: Modifier, + currentDate: LocalDateTime, + onSnap: (LocalTime) -> Unit, +) { + val is24Hour = DateDisplayMapper.is24HourFormat() + + val state = rememberAdaptiveTimePickerState( + initialHour = currentDate.hour, + initialMinute = currentDate.minute, + is24Hour = is24Hour + ) + LaunchedEffect(state.hour, state.minute) { + val hour = state.hour + val minute = state.minute + onSnap(LocalTime(hour, minute, 0)) + } + + val palette = LocalCustomColorsPalette.current + val accent = MaterialTheme.colorScheme.primary + val onAccent = MaterialTheme.colorScheme.onPrimary + + AdaptiveTimePicker( + state = state, + modifier = modifier, + layoutType = TimePickerLayoutType.Vertical, + colors = TimePickerDefaults.colors( + containerColor = palette.elevationBackground, + clockDialColor = MaterialTheme.colorScheme.surface, + selectorColor = accent, + clockDialSelectedContentColor = onAccent, + clockDialUnselectedContentColor = palette.primaryTextAndIcon, + periodSelectorSelectedContainerColor = accent, + periodSelectorUnselectedContainerColor = MaterialTheme.colorScheme.surface, + periodSelectorSelectedContentColor = onAccent, + periodSelectorUnselectedContentColor = palette.primaryTextAndIcon, + timeSelectorSelectedContainerColor = accent, + timeSelectorUnselectedContainerColor = MaterialTheme.colorScheme.surface, + timeSelectorSelectedContentColor = onAccent, + timeSelectorUnselectedContentColor = palette.primaryTextAndIcon, + ) + ) +} From 0ddf6e820e01883b63f8fa6203404b70925b4375 Mon Sep 17 00:00:00 2001 From: denwritescode Date: Thu, 16 Jul 2026 10:48:37 +0300 Subject: [PATCH 4/4] provide SettingsStore via koin per platform (expect/actual) Drop the SettingsManager static singleton; SettingsManager and its SettingsStore are koin singles now. Android supplies its context and FCM module through a KoinAppDeclaration (androidContext(applicationContext) + modules(firebaseTopicsModule)); the android actual resolves Context from koin, the ios actual builds KeychainSettings. Consumers inject SettingsManager instead of SettingsManager.current(). Co-Authored-By: Claude Opus 4.8 --- clients/tablet/composeApp/build.gradle.kts | 4 ---- .../band/effective/office/tablet/App.kt | 15 +++++-------- .../office/tablet/di/KoinInitializer.kt | 6 ++--- .../effective/office/tablet/Initializers.kt | 9 -------- clients/tablet/core/domain/build.gradle.kts | 4 ++++ .../core/domain/di/domainModule.android.kt | 19 ++++++++++++++++ .../tablet/core/domain/di/domainModule.kt | 13 +++++++++-- .../tablet/core/domain/model/Settings.kt | 22 ++++--------------- .../domain/useCase/CheckSettingsUseCase.kt | 4 ++-- .../core/domain/useCase/SetRoomUseCase.kt | 4 ++-- .../tablet/core/domain/di/domainModule.ios.kt | 18 +++++++++++++++ 11 files changed, 68 insertions(+), 50 deletions(-) create mode 100644 clients/tablet/core/domain/src/androidMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.android.kt create mode 100644 clients/tablet/core/domain/src/iosMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.ios.kt diff --git a/clients/tablet/composeApp/build.gradle.kts b/clients/tablet/composeApp/build.gradle.kts index eb19c1950..bf39692f9 100644 --- a/clients/tablet/composeApp/build.gradle.kts +++ b/clients/tablet/composeApp/build.gradle.kts @@ -61,10 +61,6 @@ kotlin { implementation(libs.koin.android) implementation("org.slf4j:slf4j-android:1.7.36") implementation(libs.firebase.messaging.ktx) - implementation(libs.settings) - } - iosMain.dependencies { - implementation(libs.settings) } } } diff --git a/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt b/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt index 7a5194077..49e2e6986 100644 --- a/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt +++ b/clients/tablet/composeApp/src/androidMain/kotlin/band/effective/office/tablet/App.kt @@ -2,14 +2,12 @@ package band.effective.office.tablet import android.app.Application import band.effective.office.tablet.core.domain.manager.DateResetManager -import band.effective.office.tablet.core.domain.model.SettingsManager -import band.effective.office.tablet.core.domain.model.SettingsStore import band.effective.office.tablet.core.ui.inactivity.InactivityLifecycleCallbacks import band.effective.office.tablet.di.KoinInitializer import band.effective.office.tablet.di.firebaseTopicsModule import com.google.firebase.messaging.FirebaseMessaging -import com.russhwolf.settings.SharedPreferencesSettings import org.koin.android.ext.android.get +import org.koin.android.ext.koin.androidContext import org.koin.core.qualifier.named import kotlin.time.Duration.Companion.minutes @@ -18,13 +16,10 @@ class App : Application() { override fun onCreate() { super.onCreate() LoggerInitializer().init() - KoinInitializer().init(listOf(firebaseTopicsModule)) - val settings = SharedPreferencesSettings(getSharedPreferences("settings", MODE_PRIVATE)) - SettingsManager.init(object : SettingsStore { - override fun getString(key: String, defaultValue: String) = settings.getString(key, defaultValue) - override fun putString(key: String, value: String) = settings.putString(key, value) - override fun remove(key: String) = settings.remove(key) - }) + KoinInitializer().init { + androidContext(applicationContext) + modules(firebaseTopicsModule) + } subscribeOnFirebaseTopics() initializeInactivitySystem() } diff --git a/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/KoinInitializer.kt b/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/KoinInitializer.kt index 5fc88bc67..0fbad9387 100644 --- a/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/KoinInitializer.kt +++ b/clients/tablet/composeApp/src/commonMain/kotlin/band/effective/office/tablet/di/KoinInitializer.kt @@ -8,10 +8,10 @@ import band.effective.office.tablet.feature.main.di.mainScreenModule import band.effective.office.tablet.feature.settings.di.settingsModule import band.effective.office.tablet.feature.slot.di.slotDiModule import org.koin.core.context.startKoin -import org.koin.core.module.Module +import org.koin.dsl.KoinAppDeclaration class KoinInitializer { - fun init(platformModules: List = emptyList()) { + fun init(koinConfig: KoinAppDeclaration = {}) { startKoin { modules( appModule, @@ -22,8 +22,8 @@ class KoinInitializer { bookingEditorModule, fastBookingModule, slotDiModule, - *platformModules.toTypedArray(), ) + koinConfig() } } } diff --git a/clients/tablet/composeApp/src/iosMain/kotlin/band/effective/office/tablet/Initializers.kt b/clients/tablet/composeApp/src/iosMain/kotlin/band/effective/office/tablet/Initializers.kt index d5e3b624e..1c63acf3d 100644 --- a/clients/tablet/composeApp/src/iosMain/kotlin/band/effective/office/tablet/Initializers.kt +++ b/clients/tablet/composeApp/src/iosMain/kotlin/band/effective/office/tablet/Initializers.kt @@ -1,20 +1,11 @@ package band.effective.office.tablet -import band.effective.office.tablet.core.domain.model.SettingsManager -import band.effective.office.tablet.core.domain.model.SettingsStore import band.effective.office.tablet.di.KoinInitializer -import com.russhwolf.settings.KeychainSettings class Initializers { fun init() { LoggerInitializer().init() KoinInitializer().init() - val settings = KeychainSettings("effectiveOffice") - SettingsManager.init(object : SettingsStore { - override fun getString(key: String, defaultValue: String) = settings.getString(key, defaultValue) - override fun putString(key: String, value: String) = settings.putString(key, value) - override fun remove(key: String) = settings.remove(key) - }) } } \ No newline at end of file diff --git a/clients/tablet/core/domain/build.gradle.kts b/clients/tablet/core/domain/build.gradle.kts index b7c232c4c..6f2765c39 100644 --- a/clients/tablet/core/domain/build.gradle.kts +++ b/clients/tablet/core/domain/build.gradle.kts @@ -13,6 +13,10 @@ kotlin { androidMain.dependencies { implementation(libs.coroutines.android) implementation(libs.koin.android) + implementation(libs.settings) + } + iosMain.dependencies { + implementation(libs.settings) } } } diff --git a/clients/tablet/core/domain/src/androidMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.android.kt b/clients/tablet/core/domain/src/androidMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.android.kt new file mode 100644 index 000000000..f5152c2ec --- /dev/null +++ b/clients/tablet/core/domain/src/androidMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.android.kt @@ -0,0 +1,19 @@ +package band.effective.office.tablet.core.domain.di + +import android.content.Context +import band.effective.office.tablet.core.domain.model.SettingsStore +import com.russhwolf.settings.SharedPreferencesSettings +import org.koin.dsl.module + +actual fun settingsStoreModule() = module { + single { + val settings = SharedPreferencesSettings( + get().getSharedPreferences("settings", Context.MODE_PRIVATE) + ) + object : SettingsStore { + override fun getString(key: String, defaultValue: String) = settings.getString(key, defaultValue) + override fun putString(key: String, value: String) = settings.putString(key, value) + override fun remove(key: String) = settings.remove(key) + } + } +} diff --git a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.kt b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.kt index bcee076bf..5ea5b9460 100644 --- a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.kt +++ b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.kt @@ -1,5 +1,6 @@ package band.effective.office.tablet.core.domain.di +import band.effective.office.tablet.core.domain.model.SettingsManager import band.effective.office.tablet.core.domain.useCase.CheckBookingUseCase import band.effective.office.tablet.core.domain.useCase.CheckSettingsUseCase import band.effective.office.tablet.core.domain.useCase.CreateBookingUseCase @@ -19,9 +20,17 @@ import band.effective.office.tablet.core.domain.useCase.SlotUseCase import band.effective.office.tablet.core.domain.useCase.TimerUseCase import band.effective.office.tablet.core.domain.useCase.UpdateBookingUseCase import band.effective.office.tablet.core.domain.useCase.UpdateUseCase +import org.koin.core.module.Module import org.koin.dsl.module +expect fun settingsStoreModule(): Module + val domainModule = module { + + includes(settingsStoreModule()) + + single { SettingsManager(settings = get()) } + // Booking use cases single { CreateBookingUseCase( @@ -68,9 +77,9 @@ val domainModule = module { // Other use cases single { OrganizersInfoUseCase(repository = get()) } single { CheckBookingUseCase(roomInfoUseCase = get()) } - single { CheckSettingsUseCase() } + single { CheckSettingsUseCase(settingsManager = get()) } single { SelectRoomUseCase() } - single { SetRoomUseCase() } + single { SetRoomUseCase(settingsManager = get()) } single { SlotUseCase() } single { TimerUseCase() } single { UpdateUseCase(roomInfoUseCase = get(), timerUseCase = get()) } diff --git a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/Settings.kt b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/Settings.kt index a600b69fb..c4d859519 100644 --- a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/Settings.kt +++ b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/model/Settings.kt @@ -2,24 +2,6 @@ package band.effective.office.tablet.core.domain.model class SettingsManager(private val settings: SettingsStore) { - companion object { - private const val KEY_NAME_ROOM = "nameRoom" - - // Singleton-like instance - private var currentInstance: SettingsManager? = null - - fun init(settings: SettingsStore) { - if(currentInstance == null) { - currentInstance = SettingsManager(settings) - } - } - - fun current(): SettingsManager { - return currentInstance - ?: error("SettingsManager not initialized. Call SettingsManager.init(settings) first.") - } - } - var currentRoomName: String get() = settings.getString(KEY_NAME_ROOM, "") private set(value) { @@ -35,5 +17,9 @@ class SettingsManager(private val settings: SettingsStore) { fun removeRoomName() { settings.remove(KEY_NAME_ROOM) } + + private companion object { + const val KEY_NAME_ROOM = "nameRoom" + } } diff --git a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/useCase/CheckSettingsUseCase.kt b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/useCase/CheckSettingsUseCase.kt index 544fee56a..01272a7c7 100644 --- a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/useCase/CheckSettingsUseCase.kt +++ b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/useCase/CheckSettingsUseCase.kt @@ -3,8 +3,8 @@ package band.effective.office.tablet.core.domain.useCase import band.effective.office.tablet.core.domain.model.SettingsManager /**use case for get settings values*/ -class CheckSettingsUseCase { +class CheckSettingsUseCase(private val settingsManager: SettingsManager) { /**Get current room from settings*/ operator fun invoke() = - SettingsManager.current().checkCurrentRoom() + settingsManager.checkCurrentRoom() } \ No newline at end of file diff --git a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/useCase/SetRoomUseCase.kt b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/useCase/SetRoomUseCase.kt index b3f05a490..ab4df66cc 100644 --- a/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/useCase/SetRoomUseCase.kt +++ b/clients/tablet/core/domain/src/commonMain/kotlin/band/effective/office/tablet/core/domain/useCase/SetRoomUseCase.kt @@ -3,8 +3,8 @@ package band.effective.office.tablet.core.domain.useCase import band.effective.office.tablet.core.domain.model.SettingsManager /**Use case for set settings*/ -class SetRoomUseCase { +class SetRoomUseCase(private val settingsManager: SettingsManager) { /**save current room name*/ operator fun invoke(nameRoom: String) = - SettingsManager.current().updateSettings(nameRoom) + settingsManager.updateSettings(nameRoom) } \ No newline at end of file diff --git a/clients/tablet/core/domain/src/iosMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.ios.kt b/clients/tablet/core/domain/src/iosMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.ios.kt new file mode 100644 index 000000000..c434f5044 --- /dev/null +++ b/clients/tablet/core/domain/src/iosMain/kotlin/band/effective/office/tablet/core/domain/di/domainModule.ios.kt @@ -0,0 +1,18 @@ +package band.effective.office.tablet.core.domain.di + +import band.effective.office.tablet.core.domain.model.SettingsStore +import com.russhwolf.settings.ExperimentalSettingsImplementation +import com.russhwolf.settings.KeychainSettings +import org.koin.dsl.module + +@OptIn(ExperimentalSettingsImplementation::class) +actual fun settingsStoreModule() = module { + single { + val settings = KeychainSettings("effectiveOffice") + object : SettingsStore { + override fun getString(key: String, defaultValue: String) = settings.getString(key, defaultValue) + override fun putString(key: String, value: String) = settings.putString(key, value) + override fun remove(key: String) = settings.remove(key) + } + } +}