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 b2f1c74ca..bf39692f9 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) @@ -48,8 +45,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")) 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..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,12 +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.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 @@ -16,15 +16,10 @@ class App : Application() { override fun onCreate() { super.onCreate() LoggerInitializer().init() - KoinInitializer().init() - SettingsManager.init( - SharedPreferencesSettings( - this.getSharedPreferences( - "settings", - MODE_PRIVATE - ) - ) - ) + KoinInitializer().init { + androidContext(applicationContext) + modules(firebaseTopicsModule) + } subscribeOnFirebaseTopics() initializeInactivitySystem() } 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..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,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.dsl.KoinAppDeclaration class KoinInitializer { - fun init() { + fun init(koinConfig: KoinAppDeclaration = {}) { startKoin { modules( appModule, - firebaseTopicsModule, dataModule, domainModule, mainScreenModule, @@ -23,6 +23,7 @@ class KoinInitializer { fastBookingModule, slotDiModule, ) + 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 538fa6357..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,14 +1,11 @@ package band.effective.office.tablet -import band.effective.office.tablet.core.domain.model.SettingsManager import band.effective.office.tablet.di.KoinInitializer -import com.russhwolf.settings.KeychainSettings class Initializers { fun init() { LoggerInitializer().init() KoinInitializer().init() - SettingsManager.init(KeychainSettings("effectiveOffice")) } } \ 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..6f2765c39 100644 --- a/clients/tablet/core/domain/build.gradle.kts +++ b/clients/tablet/core/domain/build.gradle.kts @@ -8,12 +8,15 @@ kotlin { api(project(":clients:shared:core")) api(libs.kotlinx.datetime) implementation(libs.kotlin.coroutines.core) - implementation(libs.settings) implementation(libs.bundles.koin) } 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 7eaa5d55a..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 @@ -1,25 +1,6 @@ package band.effective.office.tablet.core.domain.model -import com.russhwolf.settings.* -class SettingsManager(private val settings: Settings) { - - companion object { - private const val KEY_NAME_ROOM = "nameRoom" - - // Singleton-like instance - private var currentInstance: SettingsManager? = null - - fun init(settings: Settings) { - if(currentInstance == null) { - currentInstance = SettingsManager(settings) - } - } - - fun current(): SettingsManager { - return currentInstance - ?: error("SettingsManager not initialized. Call SettingsManager.init(settings) first.") - } - } +class SettingsManager(private val settings: SettingsStore) { var currentRoomName: String get() = settings.getString(KEY_NAME_ROOM, "") @@ -36,5 +17,9 @@ class SettingsManager(private val settings: Settings) { 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/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) +} 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) + } + } +} 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, + ) + ) +}