diff --git a/assets/person.svg b/assets/person.svg new file mode 100644 index 0000000000000000000000000000000000000000..89371094ee36dc5d13f31fe323d7b0df11f114b7 --- /dev/null +++ b/assets/person.svg @@ -0,0 +1,4 @@ + + + + diff --git a/buildSrc/buildSrc/src/main/kotlin/Plugins.kt b/buildSrc/buildSrc/src/main/kotlin/Plugins.kt index a01f2dce92b5708af8db1ce0c2b01285df552f74..e9d10b447d531fd1ca32d624bf7c0b892bb04382 100644 --- a/buildSrc/buildSrc/src/main/kotlin/Plugins.kt +++ b/buildSrc/buildSrc/src/main/kotlin/Plugins.kt @@ -11,6 +11,11 @@ object Plugins { const val plugin = "com.android.application" } + object AndroidLib{ + const val implementation = "com.android.tools.build:gradle:7.3.1" + const val plugin = "com.android.library" + } + object Shadow { const val implementation = "gradle.plugin.com.github.johnrengelman:shadow:7.1.2" const val plugin = "com.github.johnrengelman.shadow" diff --git a/rpi-server/src/main/kotlin/band.effective.office.elevator/plugins/Routing.kt b/rpi-server/src/main/kotlin/band.effective.office.elevator/plugins/Routing.kt index 4ed7a78c9c3ad2b09f32b856f5ca636ab3a2ef6f..29f07cb4b7c7eef6834440f5a6e3de71aa6a073f 100644 --- a/rpi-server/src/main/kotlin/band.effective.office.elevator/plugins/Routing.kt +++ b/rpi-server/src/main/kotlin/band.effective.office.elevator/plugins/Routing.kt @@ -1,6 +1,10 @@ package band.effective.office.elevator.plugins -import band.effective.office.common.utils.* +import band.effective.office.common.utils.DateUtils +import band.effective.office.common.utils.HashUtil +import band.effective.office.common.utils.PropertiesUtil +import band.effective.office.common.utils.toGMTDate +import band.effective.office.common.utils.toVerifiableDate import band.effective.office.elevator.utils.ElevatorController import io.ktor.http.* import io.ktor.server.application.* diff --git a/settings.gradle.kts b/settings.gradle.kts index a9a8dd76e91b5a8efcf49f47d4d080c52b0ed91c..1fe7c01832473f52579bc5244218b5949475ff52 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,3 +3,10 @@ rootProject.name = "effective-office" include("cloud-server", "rpi-server", "gpio") include("common") include("composeApp") +include(":tabletApp") +include(":tabletApp:features:selectRoom") +include(":tabletApp:features:roomInfo") +include(":tabletApp:features:network") +include(":tabletApp:features:domain") +include(":tabletApp:features:core") +include(":tabletApp:features:freeNegotiationsScreen") \ No newline at end of file diff --git a/tabletApp/build.gradle.kts b/tabletApp/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..3e933cb95a504b36a327b4ff9c9faa5666f23565 --- /dev/null +++ b/tabletApp/build.gradle.kts @@ -0,0 +1,74 @@ +plugins { + id(Plugins.Android.plugin) + id(Plugins.MultiplatformCompose.plugin) + id(Plugins.Kotlin.plugin) + id(Plugins.Parcelize.plugin) + id(Plugins.Libres.plugin) +} + +android { + namespace = "band.effective.office.tablet" + compileSdk = 33 + + defaultConfig { + applicationId = "band.effective.office.tablet" + versionCode = 1 + versionName = "0.0.1" + + minSdk = 26 + targetSdk = 33 + } + sourceSets["main"].apply { + manifest.srcFile("src/androidMain/AndroidManifest.xml") + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + +} + +kotlin { + android { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } + + sourceSets { + val commonMain by getting { + dependencies { + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + + // Decompose + implementation(Dependencies.Decompose.decompose) + implementation(Dependencies.Decompose.extensions) + + //Libres + implementation(Dependencies.Libres.libresCompose) + + // MVI Kotlin + api(Dependencies.MviKotlin.mviKotlin) + api(Dependencies.MviKotlin.mviKotlinMain) + api(Dependencies.MviKotlin.mviKotlinExtensionsCoroutines) + + implementation(project(":tabletApp:features:selectRoom")) + implementation(project(":tabletApp:features:roomInfo")) + implementation(project(":tabletApp:features:freeNegotiationsScreen")) + implementation(project(":tabletApp:features:core")) + + } + } + val androidMain by getting { + dependencies { + implementation(Dependencies.AndroidX.appCompat) + implementation(Dependencies.AndroidX.activityCompose) + implementation(Dependencies.Compose.uiTooling) + } + } + } +} diff --git a/tabletApp/features/core/build.gradle.kts b/tabletApp/features/core/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..ed50077434d57a95f22e2b50d658431485c25b9a --- /dev/null +++ b/tabletApp/features/core/build.gradle.kts @@ -0,0 +1,29 @@ +import Dependencies.Versions.compose + +plugins { + id(Plugins.MultiplatformCompose.plugin) + id(Plugins.AndroidLib.plugin) + id(Plugins.Kotlin.plugin) +} + +android { + compileSdk = 33 +} + +kotlin { + android { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } + + sourceSets { + val commonMain by getting { + dependencies { + implementation(compose.material) + } + } + } +} diff --git a/tabletApp/features/core/src/androidMain/AndroidManifest.xml b/tabletApp/features/core/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..591c12d455150738dea13872cbd9874a04da962e --- /dev/null +++ b/tabletApp/features/core/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/Booking.kt b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/Booking.kt new file mode 100644 index 0000000000000000000000000000000000000000..9134539410a731062701c2fc8086b0a3483cc911 --- /dev/null +++ b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/Booking.kt @@ -0,0 +1,6 @@ +package band.effective.office.tablet.domain.model + +data class Booking( + val nameRoom: String, + val eventInfo: EventInfo +) \ No newline at end of file diff --git a/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/EventInfo.kt b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/EventInfo.kt new file mode 100644 index 0000000000000000000000000000000000000000..888fea56caee9f706015294c6ccb199b9a70d891 --- /dev/null +++ b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/EventInfo.kt @@ -0,0 +1,18 @@ +package band.effective.office.tablet.domain.model + +import java.util.Calendar +import java.util.GregorianCalendar + +data class EventInfo( + val startTime: Calendar, + val finishTime: Calendar, + val organizer: String +){ + companion object{ + val emptyEvent = EventInfo( + startTime = GregorianCalendar(), + finishTime = GregorianCalendar(), + organizer = "" + ) + } +} diff --git a/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/RoomInfo.kt b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/RoomInfo.kt new file mode 100644 index 0000000000000000000000000000000000000000..a96836474f3e956008f60c101b39f31529904687 --- /dev/null +++ b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/domain/model/RoomInfo.kt @@ -0,0 +1,23 @@ +package band.effective.office.tablet.domain.model + +data class RoomInfo( + val name: String, + val capacity: Int, + val isHaveTv: Boolean, + val electricSocketCount: Int, + val eventList: List, + //NOTE(Maksim Mishenko): currentEvent is null if room is free + val currentEvent: EventInfo? +){ + companion object{ + val defaultValue = + RoomInfo( + name = "Default", + capacity = 0, + isHaveTv = false, + electricSocketCount = 0, + eventList = listOf(), + currentEvent = null + ) + } +} diff --git a/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Color.kt b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Color.kt new file mode 100644 index 0000000000000000000000000000000000000000..280662f95bd50071e2ac2f79af35e7aad66eefb6 --- /dev/null +++ b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Color.kt @@ -0,0 +1,40 @@ +package band.effective.office.tablet.ui.theme + +import androidx.compose.ui.graphics.Color + +internal val md_theme_dark_primary = Color(0xFFEE7234) +internal val md_theme_dark_secondary = Color(0xFFA262F7) +internal val md_theme_dark_background = Color(0xFF1E1C1A) +internal val md_theme_dark_surface = Color(0xFF252322) +internal val md_theme_dark_elevationBackground = Color(0xFF302D2C) +internal val md_theme_dark_mountainBackground = Color(0xFF3A3736) +internal val md_theme_dark_busyStatus = Color(0xFFF84C4C) +internal val md_theme_dark_freeStatus = Color(0xFF36C85F) +internal val md_theme_dark_onError = Color(0xFFEA4C2A) +internal val md_theme_dark_onSuccess = Color(0xFF25C050) +internal val md_theme_dark_secondaryButton = Color(0xFFFEFEFE) +internal val md_theme_dark_primaryTextAndIcon = Color(0xFFF9F9F9) +internal val md_theme_dark_secondaryTextAndIcon = Color(0xFF7F7F7F) +internal val md_theme_dark_tertiaryTextAndIcon = Color(0xFF777777) +internal val md_theme_dark_pressedPrimaryButton = Color(0xFFEC6521) +internal val md_theme_dark_disabledPrimaryButton = Color(0xFF342C28) +internal val md_theme_dark_iconAndText = Color(0xFFFA362F8) +internal val md_theme_dark_primaryCard = Color(0xFFF3A3736) + + +internal val md_theme_light_primary = Color(0xFFE55A0F) +internal val md_theme_light_secondary = Color(0xFF6E00FE) +internal val md_theme_light_background = Color(0xFFFEFEFE) +internal val md_theme_light_surface = Color(0xFFF9F9F9) +internal val md_theme_light_elevationBackground = Color(0xFFEFEFEF) +internal val md_theme_light_mountainBackground = Color(0xFFEFEFEF) +internal val md_theme_light_busyStatus = Color(0xFFF84343) +internal val md_theme_light_freeStatus = Color(0xFF36C85F) +internal val md_theme_light_onError = Color(0xFFEA4C2A) +internal val md_theme_light_onSuccess = Color(0xFF25C050) +internal val md_theme_light_secondaryButton = Color(0xFFE55A0F) +internal val md_theme_light_primaryTextAndIcon = Color(0xFF1F1814) +internal val md_theme_light_secondaryTextAndIcon = Color(0xFF747474) +internal val md_theme_light_tertiaryTextAndIcon = Color(0xFF979797) +internal val md_theme_light_pressedPrimaryButton = Color(0xFFED6F2F) +internal val md_theme_light_disabledPrimaryButton = Color(0xFFD1C9C5) diff --git a/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Theme.kt b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Theme.kt new file mode 100644 index 0000000000000000000000000000000000000000..426e1a207d68a774a4ce9a11fd36e4167384ea52 --- /dev/null +++ b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Theme.kt @@ -0,0 +1,72 @@ +package band.effective.office.tablet.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val darkColors = darkColors( + primary = band.effective.office.tablet.ui.theme.md_theme_dark_primary, + secondary = band.effective.office.tablet.ui.theme.md_theme_dark_secondary, + background = band.effective.office.tablet.ui.theme.md_theme_dark_background, + surface = band.effective.office.tablet.ui.theme.md_theme_dark_surface, + onError = band.effective.office.tablet.ui.theme.md_theme_dark_onError, +) + +object CustomDarkColors { + val elevationBackground = md_theme_dark_elevationBackground + val mountainBackground = md_theme_dark_mountainBackground + val busyStatus = md_theme_dark_busyStatus + val freeStatus = md_theme_dark_freeStatus + val background = md_theme_dark_background + val surface = md_theme_dark_surface + val primary = md_theme_dark_primary + val primaryCard = md_theme_dark_primaryCard + val iconAndText = md_theme_dark_iconAndText + val onSuccess = md_theme_dark_onSuccess + val secondaryButton = md_theme_dark_secondaryButton + val primaryTextAndIcon = md_theme_dark_primaryTextAndIcon + val secondaryTextAndIcon = md_theme_dark_secondaryTextAndIcon + val tertiaryTextAndIcon = md_theme_dark_tertiaryTextAndIcon + val pressedPrimaryButton = md_theme_dark_pressedPrimaryButton + val disabledPrimaryButton = md_theme_dark_disabledPrimaryButton +} + +private val lightColors = lightColors( + primary = band.effective.office.tablet.ui.theme.md_theme_light_primary, + secondary = band.effective.office.tablet.ui.theme.md_theme_light_secondary, + background = band.effective.office.tablet.ui.theme.md_theme_light_background, + surface = band.effective.office.tablet.ui.theme.md_theme_light_surface, + onError = band.effective.office.tablet.ui.theme.md_theme_light_onError, +) + +object CustomLightColors { + val elevationBackground = md_theme_light_elevationBackground + val mountainBackground = md_theme_light_mountainBackground + val busyStatus = md_theme_light_busyStatus + val freeStatus = md_theme_light_freeStatus + val onSuccess = md_theme_light_onSuccess + val secondaryButton = md_theme_light_secondaryButton + val primaryTextAndIcon = md_theme_light_primaryTextAndIcon + val secondaryTextAndIcon = md_theme_light_secondaryTextAndIcon + val tertiaryTextAndIcon = md_theme_light_tertiaryTextAndIcon + val pressedPrimaryButton = md_theme_light_pressedPrimaryButton + val disabledPrimaryButton = md_theme_light_disabledPrimaryButton +} + +@Composable +internal fun AppTheme( + useDarkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colors = darkColors + + MaterialTheme( + colors = colors, + content = { + Surface (content = content) + } + ) +} \ No newline at end of file diff --git a/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Typography.kt b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Typography.kt new file mode 100644 index 0000000000000000000000000000000000000000..1762bd057397d329b73b2837dd44648becb60450 --- /dev/null +++ b/tabletApp/features/core/src/commonMain/kotlin/band/effective/office/tablet/ui/theme/Typography.kt @@ -0,0 +1,56 @@ +package band.effective.office.tablet.ui.theme + +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +val header1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 56.sp, + lineHeight = 56.sp * 1.5f, + letterSpacing = 56.sp * 0.02f +) +val header2 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 48.sp, + lineHeight = 48.sp * 1.5f, + letterSpacing = 48.sp * 0.02f +) +val header3 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 36.sp, + lineHeight = 36.sp * 1.5f, + letterSpacing = 36.sp * 0.02f +) +val header4 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 28.sp, + lineHeight = 28.sp * 1.5f, + letterSpacing = 28.sp * 0.02f +) +val header5 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 24.sp, + lineHeight = 24.sp * 1.5f, + letterSpacing = 24.sp * 0.02f +) +val header6 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 20.sp, + lineHeight = 20.sp * 1.5f, + letterSpacing = 20.sp * 0.02f +) +val header7 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 18.sp, + lineHeight = 18.sp * 1.5f, + letterSpacing = 18.sp * 0.02f +) diff --git a/tabletApp/features/domain/build.gradle.kts b/tabletApp/features/domain/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..ddb3f9af744da58d2d9cc2692b8c39455d1991be --- /dev/null +++ b/tabletApp/features/domain/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + id(Plugins.AndroidLib.plugin) + id(Plugins.Kotlin.plugin) +} + + +android { + compileSdk = 33 + sourceSets["main"].apply { + manifest.srcFile("src/androidMain/AndroidManifest.xml") + res.srcDirs("src/androidMain/resources") + res.srcDir("build/generated/libres/android/resources") + } +} + +kotlin { + android { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } + + sourceSets { + val commonMain by getting { + dependencies { + // Koin + api(Dependencies.Koin.core) + + implementation(project(":tabletApp:features:core")) + implementation(project(":tabletApp:features:network")) + } + } + val androidMain by getting { + dependencies{ + // Koin + api(Dependencies.Koin.android) + } + } + } +} diff --git a/tabletApp/features/domain/src/androidMain/AndroidManifest.xml b/tabletApp/features/domain/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..c3665bc42238c9f317cfdc03fa2be953f0036ffc --- /dev/null +++ b/tabletApp/features/domain/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/di/DomainModule.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/di/DomainModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..98c968963f4c1858be8b90fb81c2c0bf640adf60 --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/di/DomainModule.kt @@ -0,0 +1,33 @@ +package band.effective.office.tablet.di + +import band.effective.office.tablet.domain.CurrentEventController +import band.effective.office.tablet.domain.CurrentEventControllerServerImpl +import band.effective.office.tablet.domain.MockController +import band.effective.office.tablet.domain.useCase.BookingUseCase +import band.effective.office.tablet.domain.useCase.OrganizersInfoUseCase +import band.effective.office.tablet.domain.useCase.RoomInfoUseCase +import band.effective.office.tablet.network.api.WorkApi +import band.effective.office.tablet.network.repository.BookingRepository +import band.effective.office.tablet.network.repository.CancelRepository +import band.effective.office.tablet.network.repository.OrganizerRepository +import band.effective.office.tablet.network.repository.RoomRepository +import band.effective.office.tablet.network.repository.ServerUpdateRepository +import band.effective.office.tablet.network.repository.impl.BookingRepositoryImpl +import band.effective.office.tablet.network.repository.impl.CancelRepositoryImpl +import band.effective.office.tablet.network.repository.impl.OrganizerRepositoryImpl +import band.effective.office.tablet.network.repository.impl.RoomRepositoryImpl +import band.effective.office.tablet.network.repository.impl.ServerUpdateRepositoryImpl +import org.koin.dsl.module + +val domainModule = module { + single { RoomRepositoryImpl(get()) } + single { OrganizerRepositoryImpl(get()) } + single { CancelRepositoryImpl(get()) } + single { BookingRepositoryImpl(get()) } + single { ServerUpdateRepositoryImpl(get()) } + + single { RoomInfoUseCase(get()) } + single { OrganizersInfoUseCase(get()) } + single { BookingUseCase(get()) } + single { CurrentEventControllerServerImpl(get(), get(), get()) } +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventController.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventController.kt new file mode 100644 index 0000000000000000000000000000000000000000..c27a6f5917b4d743b47c360a99daf2223dee8815 --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventController.kt @@ -0,0 +1,48 @@ +package band.effective.office.tablet.domain + +import band.effective.office.tablet.domain.model.EventInfo +import band.effective.office.tablet.domain.useCase.RoomInfoUseCase +import band.effective.office.tablet.network.repository.CancelRepository +import band.effective.office.tablet.network.repository.ServerUpdateRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch + +abstract class CurrentEventController( + private val roomUseCase: RoomInfoUseCase, + private val serverUpdateRepository: ServerUpdateRepository, + private val cancelRepository: CancelRepository +) { + private lateinit var job: Job + protected lateinit var scope: CoroutineScope + protected var currentEvent: EventInfo? = null + protected val handlersList: MutableList<() -> Unit> = mutableListOf() + + fun start(scope: CoroutineScope) { + this.scope = scope + job = update() + scope.launch { serverUpdateRepository.subscribeOnUpdates(scope, { onServerUpdate() }, {}) } + } + + private fun cancelCurrentEvent() { + scope.launch { + if (cancelRepository.cancelEvent()) { + onServerUpdate() + } + } + } + + private fun onServerUpdate() { + scope.launch { + job.cancel() + currentEvent = roomUseCase().currentEvent + job = update() + } + } + + fun subscribe(onEvent: () -> Unit) { + handlersList.add(onEvent) + } + + protected abstract fun update(): Job +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventControllerImpl.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventControllerImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..904eea2988271052c5396870b308c47bbf0c2b07 --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventControllerImpl.kt @@ -0,0 +1,28 @@ +package band.effective.office.tablet.domain + +import band.effective.office.tablet.domain.useCase.RoomInfoUseCase +import band.effective.office.tablet.network.repository.CancelRepository +import band.effective.office.tablet.network.repository.ServerUpdateRepository +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.util.GregorianCalendar + +class CurrentEventControllerImpl( + private val roomUseCase: RoomInfoUseCase, + private val serverUpdateRepository: ServerUpdateRepository, + private val cancelRepository: CancelRepository +) : CurrentEventController(roomUseCase, serverUpdateRepository, cancelRepository) { + override fun update() = scope.launch { + while (true) { + val roomInfo = roomUseCase() + val nextEventTime = + roomInfo.currentEvent?.finishTime ?: roomInfo.eventList.firstOrNull()?.startTime + if (nextEventTime != null) { + val timeToUpdate = nextEventTime.time.time - GregorianCalendar().time.time + delay(timeToUpdate) + currentEvent = roomUseCase().currentEvent + handlersList.forEach { it() } + } + } + } +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventControllerServerImpl.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventControllerServerImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..9beb7e6776f05f02174161341fa881300b53fb26 --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/CurrentEventControllerServerImpl.kt @@ -0,0 +1,14 @@ +package band.effective.office.tablet.domain + +import band.effective.office.tablet.domain.useCase.RoomInfoUseCase +import band.effective.office.tablet.network.repository.CancelRepository +import band.effective.office.tablet.network.repository.ServerUpdateRepository +import kotlinx.coroutines.launch + +class CurrentEventControllerServerImpl( + roomUseCase: RoomInfoUseCase, + serverUpdateRepository: ServerUpdateRepository, + cancelRepository: CancelRepository +) : CurrentEventController(roomUseCase, serverUpdateRepository, cancelRepository) { + override fun update() = scope.launch {} +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/MockController.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/MockController.kt new file mode 100644 index 0000000000000000000000000000000000000000..9668f2ad29ee55df23b9495b860b39f5070a1585 --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/MockController.kt @@ -0,0 +1,20 @@ +package band.effective.office.tablet.domain + +import band.effective.office.tablet.network.api.WorkApi +import kotlinx.coroutines.flow.update + +class MockController( + val workApi: WorkApi +){ + fun changeBusy(newValue: Boolean){ + workApi.changeBusy(newValue) + } + + fun changeEventCount(isMany: Boolean){ + workApi.changeEventCount(isMany) + } + + fun changeHaveTv(newValue: Boolean){ + workApi.mutableRoomInfo.update { it.copy(isHaveTv = newValue) } + } +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/BookingUseCase.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/BookingUseCase.kt new file mode 100644 index 0000000000000000000000000000000000000000..43b3b887b0aaef8909db1effd3381db682ea41c0 --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/BookingUseCase.kt @@ -0,0 +1,7 @@ +package band.effective.office.tablet.domain.useCase + +import band.effective.office.tablet.network.repository.BookingRepository + +class BookingUseCase(private val repository: BookingRepository) { + suspend fun invoke() = repository.bookingRoom() +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/CheckBookingUseCase.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/CheckBookingUseCase.kt new file mode 100644 index 0000000000000000000000000000000000000000..f4e31e8bbc2d2522712b09b8f9b5b22721d5560e --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/CheckBookingUseCase.kt @@ -0,0 +1,38 @@ +package band.effective.office.tablet.domain.useCase + +import band.effective.office.tablet.domain.model.EventInfo +import java.util.Calendar + +class CheckBookingUseCase(private val roomInfoUseCase: RoomInfoUseCase) { + suspend operator fun invoke(event: EventInfo): Boolean { + val eventsList: List = eventList() + return !predicate(event, eventsList) + } + + suspend fun busyEvent(event: EventInfo): EventInfo? { + val eventsList: List = eventList() + return eventsList.firstOrNull() { it.startTime.belong(event) || event.startTime.belong(it) }?.copy() + } + + + private fun predicate(event: EventInfo, eventsList: List) = + startEventBelongList(event.startTime, eventsList) || startNewEventBelongList( + event, + eventsList + ) + + private suspend fun eventList(): List { + val roomInfo = roomInfoUseCase() + return if (roomInfo.currentEvent != null) roomInfo.eventList + roomInfo.currentEvent!! + else roomInfo.eventList + } + + private fun startNewEventBelongList(event: EventInfo, eventsList: List) = + eventsList.any { it.startTime.belong(event) } + + private fun startEventBelongList(calendar: Calendar, eventsList: List) = + eventsList.any { calendar.belong(it) } + + private fun Calendar.belong(event: EventInfo) = + this >= event.startTime && this <= event.finishTime +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/OrganizersInfoUseCase.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/OrganizersInfoUseCase.kt new file mode 100644 index 0000000000000000000000000000000000000000..c8ad08be5f178fb803a9cb0f578b8b6866a1e8ab --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/OrganizersInfoUseCase.kt @@ -0,0 +1,7 @@ +package band.effective.office.tablet.domain.useCase + +import band.effective.office.tablet.network.repository.OrganizerRepository + +class OrganizersInfoUseCase(private val repository: OrganizerRepository) { + suspend operator fun invoke() = repository.getOrganizersList() +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/RoomInfoUseCase.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/RoomInfoUseCase.kt new file mode 100644 index 0000000000000000000000000000000000000000..9f42316896606f8096734cc8a471f910f19953cb --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/RoomInfoUseCase.kt @@ -0,0 +1,7 @@ +package band.effective.office.tablet.domain.useCase + +import band.effective.office.tablet.network.repository.RoomRepository + +class RoomInfoUseCase(private val repository: RoomRepository) { + suspend operator fun invoke() = repository.getRoomInfo() +} \ No newline at end of file diff --git a/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/UpdateUseCase.kt b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/UpdateUseCase.kt new file mode 100644 index 0000000000000000000000000000000000000000..81057dbef3c8488250ca075e68221df9abb68cd9 --- /dev/null +++ b/tabletApp/features/domain/src/commonMain/kotlin/band/effective/office/tablet/domain/useCase/UpdateUseCase.kt @@ -0,0 +1,55 @@ +package band.effective.office.tablet.domain.useCase + +import android.util.Log +import band.effective.office.tablet.domain.CurrentEventController +import band.effective.office.tablet.domain.model.RoomInfo +import band.effective.office.tablet.network.repository.ServerUpdateRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +class UpdateUseCase( + private val roomInfoUseCase: RoomInfoUseCase, + private val organizersInfoUseCase: OrganizersInfoUseCase, + private val currentEventController: CurrentEventController, + private val serverUpdateRepository: ServerUpdateRepository +) { + suspend fun getRoomInfo() = roomInfoUseCase() + suspend fun getOrganizersList() = organizersInfoUseCase() + suspend operator fun invoke( + scope: CoroutineScope, + roomUpdateHandler: (RoomInfo) -> Unit, + organizerUpdateHandler: (List) -> Unit + ) { + serverUpdateRepository.subscribeOnUpdates(scope, { + roomUpdateHandler(roomUpdate(scope)) + }, { + organizerUpdateHandler(organizerUpdate(scope)) + }) + currentEventController.subscribe { + roomUpdateHandler(roomUpdate(scope)) + } + } + + private fun roomUpdate(scope: CoroutineScope): RoomInfo { + var newRoomInfo: RoomInfo? = null + scope.launch(Dispatchers.IO) { + newRoomInfo = roomInfoUseCase() + } + while (newRoomInfo == null) { + } + return newRoomInfo!! + } + + private fun organizerUpdate( + scope: CoroutineScope + ): List { + var newOrgListInfo: List? = null + scope.launch(Dispatchers.IO) { + newOrgListInfo = organizersInfoUseCase() + } + while (newOrgListInfo == null) { + } + return newOrgListInfo!! + } +} \ No newline at end of file diff --git a/tabletApp/features/freeNegotiationsScreen/build.gradle.kts b/tabletApp/features/freeNegotiationsScreen/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..ac41b56cd34ff368f45c2bb3de6a960d53452b72 --- /dev/null +++ b/tabletApp/features/freeNegotiationsScreen/build.gradle.kts @@ -0,0 +1,65 @@ +plugins { + id(Plugins.AndroidLib.plugin) + id(Plugins.MultiplatformCompose.plugin) + id(Plugins.Kotlin.plugin) + id(Plugins.Parcelize.plugin) + id(Plugins.Libres.plugin) +} + +android { + compileSdk = 33 + sourceSets["main"].apply { + res.srcDirs("src/androidMain/resources") + res.srcDir("build/generated/libres/android/resources") + } +} + +kotlin { + android { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } + + + sourceSets { + val commonMain by getting { + dependencies { + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + + // Decompose + implementation(Dependencies.Decompose.decompose) + implementation(Dependencies.Decompose.extensions) + + //Koin + api(Dependencies.Koin.core) + + //Libres + implementation(Dependencies.Libres.libresCompose) + + implementation(project(":tabletApp:features:core")) + } + } + + val androidMain by getting { + dependencies { + //Koin + api(Dependencies.Koin.android) + } + } + } + + libres { + // https://github.com/Skeptick/libres#setup + generatedClassName = "MainRes" // "Res" by default + generateNamedArguments = true // false by default + baseLocaleLanguageCode = "ru" // "en" by default + camelCaseNamesForAppleFramework = true // false by default + + } + +} diff --git a/tabletApp/features/freeNegotiationsScreen/src/androidMain/AndroidManifest.xml b/tabletApp/features/freeNegotiationsScreen/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..c5c2a6c3dd5902c0d425185b368e152d4d31a2ce --- /dev/null +++ b/tabletApp/features/freeNegotiationsScreen/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/FreeNegotiationsComponent.kt b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/FreeNegotiationsComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..b4d1d55a1fa6b6933b41b7649da789bf58296125 --- /dev/null +++ b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/FreeNegotiationsComponent.kt @@ -0,0 +1,59 @@ +package band.effective.office.tablet.ui.freeNegotiationsScreen + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Person +import band.effective.office.tablet.ui.freeNegotiationsScreen.models.RoomCharacteristicsItem +import band.effective.office.tablet.ui.freeNegotiationsScreen.models.RoomItem +import com.arkivanov.decompose.ComponentContext + + +class FreeNegotiationsComponent( + componentContext: ComponentContext +) : ComponentContext by componentContext { + val rooms: List = listOf( + RoomItem( + name = "Moon", + stuff = listOf( + RoomCharacteristicsItem( + icon = Icons.Default.Person, + text = "5 человек" + ), + RoomCharacteristicsItem( + icon = Icons.Default.Person, + text = "5 человек" + ), + RoomCharacteristicsItem( + icon = Icons.Default.Person, + text = "5 человек" + ), + RoomCharacteristicsItem( + icon = Icons.Default.Person, + text = "5 человек" + ), + RoomCharacteristicsItem( + icon = Icons.Default.Person, + text = "5 человек" + ) + ) + ), + RoomItem( + name = "Moon", + stuff = listOf( + RoomCharacteristicsItem( + icon = Icons.Default.Person, + text = "5 человек" + ) + ) + ), + RoomItem( + name = "Moon", + stuff = listOf( + RoomCharacteristicsItem( + icon = Icons.Default.Person, + text = "5 человек" + ) + ) + ), + ) + +} \ No newline at end of file diff --git a/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/FreeNegotiationsScreen.kt b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/FreeNegotiationsScreen.kt new file mode 100644 index 0000000000000000000000000000000000000000..c264ffb5d7dab7590a783f8afde5996ef1c12d6c --- /dev/null +++ b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/FreeNegotiationsScreen.kt @@ -0,0 +1,106 @@ +package band.effective.office.tablet.ui.freeNegotiationsScreen + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import band.effective.office.tablet.features.freeNegotiationsScreen.MainRes +import band.effective.office.tablet.ui.freeNegotiationsScreen.components.RoomCard +import band.effective.office.tablet.ui.theme.CustomDarkColors + + +@Composable +fun FreeNegotiationsScreen(component: FreeNegotiationsComponent) { + FreeNegotiationsContent( + date = "5 июля", + timeStart = "17:49", + timeEnd = "19:00", + onClick = {}, + component = component, + ) +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +internal fun FreeNegotiationsContent( + date: String, + timeStart: String, + timeEnd: String, + onClick: () -> Unit, + component: FreeNegotiationsComponent +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(CustomDarkColors.background) + .verticalScroll( + rememberScrollState() + ) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(130.dp) + .background(CustomDarkColors.surface), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.Start + ) { + Spacer(modifier = Modifier.height(22.dp)) + IconButton(onClick = { onClick() }) { + Row(modifier = Modifier.padding(bottom = 22.dp)) { + Icon( + imageVector = ImageVector.vectorResource(MainRes.image.arrow_to_left), + contentDescription = null, + tint = CustomDarkColors.iconAndText + ) + } + } + Spacer(modifier = Modifier.width(4.dp)) + Text( + modifier = Modifier.padding(bottom = 22.dp), + text = "${MainRes.string.occupy} $date ${MainRes.string.with} " + + " $timeStart ${MainRes.string.before} $timeEnd", + style = MaterialTheme.typography.h6.copy( + color = CustomDarkColors.iconAndText, + fontWeight = FontWeight.Medium + ) + ) + } + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { + FlowRow( + modifier = Modifier.padding(26.dp), + horizontalArrangement = Arrangement.Center + ) { + for (room in component.rooms) { + RoomCard( + roomItem = room, + onClick = {}, + modifier = Modifier.fillMaxWidth(0.32F) + ) + Spacer(modifier = Modifier.width(24.dp)) + } + } + } + } +} \ No newline at end of file diff --git a/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/components/RoomCard.kt b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/components/RoomCard.kt new file mode 100644 index 0000000000000000000000000000000000000000..c3ec2d651c2acea1049b06948807f8b1aa8f8807 --- /dev/null +++ b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/components/RoomCard.kt @@ -0,0 +1,92 @@ +package band.effective.office.tablet.ui.freeNegotiationsScreen.components + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Card +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import band.effective.office.tablet.features.freeNegotiationsScreen.MainRes +import band.effective.office.tablet.ui.freeNegotiationsScreen.models.RoomItem +import band.effective.office.tablet.ui.theme.CustomDarkColors + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun RoomCard( + roomItem: RoomItem, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Column(modifier = modifier) { + Card( + modifier = Modifier + .fillMaxWidth().height(288.dp), + shape = RoundedCornerShape(16.dp), + backgroundColor = CustomDarkColors.primaryCard + ) { + Column(modifier = Modifier.padding(16.dp).fillMaxWidth()) { + Text( + text = roomItem.name, + style = MaterialTheme.typography.h2.copy( + Color.White, + fontWeight = FontWeight.Medium + ) + ) + Spacer(modifier = Modifier.height(28.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + FlowRow( + horizontalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(horizontal = 32.dp, vertical = 28.dp), + maxItemsInEachRow = 2 + ) { + for (stuff in roomItem.stuff) { + RoomCharacteristics( + icon = stuff.icon, + text = stuff.text + ) + } + } + } + Spacer(modifier = Modifier.height(50.dp)) + } + } + Spacer(modifier = Modifier.height(16.dp)) + Button( + onClick = { onClick() }, + modifier = Modifier + .border(2.dp, shape = RoundedCornerShape(40.dp), color = CustomDarkColors.primary) + .fillMaxWidth().height(64.dp), + shape = RoundedCornerShape(40.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = CustomDarkColors.background + ) + ) { + Text( + text = "${MainRes.string.occupy} ${roomItem.name}", + style = MaterialTheme.typography.subtitle1.copy( + color = CustomDarkColors.primary, + fontWeight = FontWeight.Medium + ) + ) + } + Spacer(modifier = Modifier.height(16.dp)) + } +} \ No newline at end of file diff --git "a/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/components/Room\320\241haracteristics.kt" "b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/components/Room\320\241haracteristics.kt" new file mode 100644 index 0000000000000000000000000000000000000000..ed002c4aef9bf35474fb79e91c086f292c6d7d55 --- /dev/null +++ "b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/components/Room\320\241haracteristics.kt" @@ -0,0 +1,36 @@ +package band.effective.office.tablet.ui.freeNegotiationsScreen.components + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import band.effective.office.tablet.ui.theme.CustomDarkColors + +@Composable +fun RoomCharacteristics(icon: ImageVector, text: String) { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + imageVector = icon, + contentDescription = null, + tint = CustomDarkColors.primaryTextAndIcon, + modifier = Modifier.size(30.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = text, + style = MaterialTheme.typography.subtitle1.copy( + color = CustomDarkColors.primaryTextAndIcon, + fontWeight = FontWeight.Medium + ) + ) + } +} \ No newline at end of file diff --git a/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/models/RoomItem.kt b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/models/RoomItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..e4e650c12a395a3a9d7ef0327bc7d875b16a4a82 --- /dev/null +++ b/tabletApp/features/freeNegotiationsScreen/src/commonMain/kotlin/band/effective/office/tablet/ui/freeNegotiationsScreen/models/RoomItem.kt @@ -0,0 +1,13 @@ +package band.effective.office.tablet.ui.freeNegotiationsScreen.models + +import androidx.compose.ui.graphics.vector.ImageVector + +class RoomItem( + val name: String, + val stuff: List +) + +class RoomCharacteristicsItem( + val icon: ImageVector, + val text: String +) \ No newline at end of file diff --git a/tabletApp/features/freeNegotiationsScreen/src/commonMain/libres/images/arrow_to_left.svg b/tabletApp/features/freeNegotiationsScreen/src/commonMain/libres/images/arrow_to_left.svg new file mode 100644 index 0000000000000000000000000000000000000000..f7f61fc21dae3ad4289169f677c676cbc80c6ecb --- /dev/null +++ b/tabletApp/features/freeNegotiationsScreen/src/commonMain/libres/images/arrow_to_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/tabletApp/features/freeNegotiationsScreen/src/commonMain/libres/strings/strings_ru.xml b/tabletApp/features/freeNegotiationsScreen/src/commonMain/libres/strings/strings_ru.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f51658779f5ae2c8bcc209e2ef77a5719be6124 --- /dev/null +++ b/tabletApp/features/freeNegotiationsScreen/src/commonMain/libres/strings/strings_ru.xml @@ -0,0 +1,6 @@ + + + Занять + с + до + \ No newline at end of file diff --git a/tabletApp/features/network/build.gradle.kts b/tabletApp/features/network/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..3910626af4515df968f71f87d624b177fd39b27b --- /dev/null +++ b/tabletApp/features/network/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + id(Plugins.AndroidLib.plugin) + id(Plugins.Kotlin.plugin) +} + + +android { + compileSdk = 33 + sourceSets["main"].apply { + manifest.srcFile("src/androidMain/AndroidManifest.xml") + res.srcDirs("src/androidMain/resources") + res.srcDir("build/generated/libres/android/resources") + } +} + +kotlin { + android { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } + + sourceSets { + val commonMain by getting { + dependencies { + // Koin + api(Dependencies.Koin.core) + + implementation(project(":tabletApp:features:core")) + } + } + val androidMain by getting { + dependencies { + // Koin + api(Dependencies.Koin.android) + } + } + } +} diff --git a/tabletApp/features/network/src/androidMain/AndroidManifest.xml b/tabletApp/features/network/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..28fe6ddf7cda3e73e6bdef9ad7d21be064e3e766 --- /dev/null +++ b/tabletApp/features/network/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/di/NetworkModule.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/di/NetworkModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..558ae485815999e5d56e8ff6aafd4ecc22a90913 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/di/NetworkModule.kt @@ -0,0 +1,9 @@ +import band.effective.office.tablet.network.api.Api +import band.effective.office.tablet.network.api.WorkApi +import org.koin.dsl.module + +val networkModule = module { + val workApi = WorkApi() + single { workApi } + single { workApi } +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/api/Api.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/api/Api.kt new file mode 100644 index 0000000000000000000000000000000000000000..b8cbd69f5d79e6981f10d7e54f92a1555b42b341 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/api/Api.kt @@ -0,0 +1,14 @@ +package band.effective.office.tablet.network.api + +import band.effective.office.tablet.domain.model.RoomInfo +import band.effective.office.tablet.network.model.WebServerEvent +import kotlinx.coroutines.CoroutineScope + +interface Api { + //TODO(Maksim Mishenko): change return value + suspend fun getRoomInfo(): RoomInfo + suspend fun getOrganizers(): List + suspend fun cancelEvent(): Boolean + suspend fun bookingRoom(): Boolean + fun subscribeOnWebHock(scope: CoroutineScope,handler: (event: WebServerEvent) -> Unit) +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/api/WorkApi.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/api/WorkApi.kt new file mode 100644 index 0000000000000000000000000000000000000000..94878ec98561771c541a1b981a725f907df35a9d --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/api/WorkApi.kt @@ -0,0 +1,130 @@ +package band.effective.office.tablet.network.api + +import band.effective.office.tablet.domain.model.EventInfo +import band.effective.office.tablet.domain.model.RoomInfo +import band.effective.office.tablet.network.model.WebServerEvent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import java.util.Calendar +import java.util.GregorianCalendar + +class WorkApi : Api { + val mutableRoomInfo = MutableStateFlow(RoomInfo.defaultValue) + val mutableOrgList = + MutableStateFlow(listOf("Ольга Белозерова", "Матвей Авгуль", "Лилия Акентьева")) + + override suspend fun getRoomInfo(): RoomInfo { + return mutableRoomInfo.value + } + + override suspend fun getOrganizers(): List { + return mutableOrgList.value + } + + override suspend fun cancelEvent(): Boolean { + return false + } + + override suspend fun bookingRoom(): Boolean { + return false + } + + override fun subscribeOnWebHock( + scope: CoroutineScope, + handler: (event: WebServerEvent) -> Unit + ) { + scope.launch { + mutableRoomInfo.collect { handler(WebServerEvent.RoomInfoUpdate) } + } + scope.launch { + mutableOrgList.collect { + handler(WebServerEvent.OrganizerInfoUpdate) + } + } + } + + private val startCurrentEvent: Calendar + private val finishCurrentEvent: Calendar + + /**It's field contain time for mocks, when it is used it needs to be increment, so that different mocks have different times*/ + private val currentTime: Calendar + + init { + val calendar = GregorianCalendar() + calendar.add(Calendar.MINUTE, -10) + startCurrentEvent = calendar.clone() as Calendar + calendar.add(Calendar.MINUTE, 30) + finishCurrentEvent = calendar.clone() as Calendar + currentTime = calendar.clone() as Calendar + + mutableRoomInfo.update { + RoomInfo( + name = "Sirius", + capacity = 4, + isHaveTv = false, + electricSocketCount = 2, + eventList = eventsList(), + currentEvent = currentEvent() + ) + } + } + + private fun getTime(): Calendar { + currentTime.add(Calendar.MINUTE, 30) + return currentTime.clone() as Calendar + } + + private fun currentEvent() = EventInfo( + startTime = startCurrentEvent, + finishTime = finishCurrentEvent, + organizer = "Ольга Белозерова" + ) + + private fun olyaEvent() = EventInfo( + startTime = getTime(), + finishTime = getTime(), + organizer = "Ольга Белозерова" + ) + + private fun matveyEvent() = EventInfo( + startTime = getTime(), + finishTime = getTime(), + organizer = "Матвей Авгуль" + ) + + private fun lilaEvent() = EventInfo( + startTime = getTime(), + finishTime = getTime(), + organizer = "Лилия Акентьева" + ) + + private fun eventsList() = listOf(olyaEvent(), matveyEvent(), lilaEvent()) + + private fun bigEventList() = + eventsList() + eventsList() + eventsList() + eventsList() + eventsList() + + fun changeBusy(newValue: Boolean) { + if (newValue) { + mutableRoomInfo.update { it.copy(currentEvent = null) } + } else { + mutableRoomInfo.update { it.copy(currentEvent = currentEvent()) } + } + } + + fun changeEventCount(isMany: Boolean) { + updateCurrentTime() + if (isMany) { + mutableRoomInfo.update { it.copy(eventList = bigEventList()) } + } else { + mutableRoomInfo.update { it.copy(eventList = eventsList()) } + } + } + + private fun updateCurrentTime() { + val calendar = GregorianCalendar() + calendar.add(Calendar.MINUTE, 20) + currentTime.time = calendar.time + } +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/model/WebServerEvent.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/model/WebServerEvent.kt new file mode 100644 index 0000000000000000000000000000000000000000..d2b17158b19cea68abf33c274e55332d5fe679d4 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/model/WebServerEvent.kt @@ -0,0 +1,6 @@ +package band.effective.office.tablet.network.model + +sealed interface WebServerEvent { + object RoomInfoUpdate : WebServerEvent + object OrganizerInfoUpdate : WebServerEvent +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/BookingReposutory.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/BookingReposutory.kt new file mode 100644 index 0000000000000000000000000000000000000000..627544e351ba726f066d3d93d71137a8c7d9c6ec --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/BookingReposutory.kt @@ -0,0 +1,5 @@ +package band.effective.office.tablet.network.repository + +interface BookingRepository { + suspend fun bookingRoom(): Boolean +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/CancelRepository.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/CancelRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..4de789b4e5ade094cafb892504ab0504d9c3f65b --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/CancelRepository.kt @@ -0,0 +1,5 @@ +package band.effective.office.tablet.network.repository + +interface CancelRepository { + suspend fun cancelEvent(): Boolean +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/OrganizerRepository.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/OrganizerRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..44d41dcaa8f3d240351ec4a24e1b73e105661420 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/OrganizerRepository.kt @@ -0,0 +1,5 @@ +package band.effective.office.tablet.network.repository + +interface OrganizerRepository { + suspend fun getOrganizersList(): List +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/RoomRepository.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/RoomRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..caecf7425b65f0b8175facf67b2aef36661a6386 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/RoomRepository.kt @@ -0,0 +1,7 @@ +package band.effective.office.tablet.network.repository + +import band.effective.office.tablet.domain.model.RoomInfo + +interface RoomRepository { + suspend fun getRoomInfo(): RoomInfo +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/ServerUpdateRepository.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/ServerUpdateRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..c73f3c7dae1aa98bcd4a695bfb2dae1e534ea628 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/ServerUpdateRepository.kt @@ -0,0 +1,11 @@ +package band.effective.office.tablet.network.repository + +import kotlinx.coroutines.CoroutineScope + +interface ServerUpdateRepository { + suspend fun subscribeOnUpdates( + scope: CoroutineScope, + roomInfoUpdateHandler: () -> Unit, + organizersListUpdateHandler: () -> Unit + ) +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/BookingRepositoryImpl.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/BookingRepositoryImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..63572fa4e293de089848920ab774df82e4467845 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/BookingRepositoryImpl.kt @@ -0,0 +1,8 @@ +package band.effective.office.tablet.network.repository.impl + +import band.effective.office.tablet.network.api.Api +import band.effective.office.tablet.network.repository.BookingRepository + +class BookingRepositoryImpl(private val api: Api) : BookingRepository { + override suspend fun bookingRoom(): Boolean = api.bookingRoom() +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/CancelRepositoryImpl.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/CancelRepositoryImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..6247df8d062e5c7af6ea01b54bf531665c03a443 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/CancelRepositoryImpl.kt @@ -0,0 +1,8 @@ +package band.effective.office.tablet.network.repository.impl + +import band.effective.office.tablet.network.api.Api +import band.effective.office.tablet.network.repository.CancelRepository + +class CancelRepositoryImpl(private val api: Api) : CancelRepository { + override suspend fun cancelEvent(): Boolean = api.cancelEvent() +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/OrganizerRepositoryImpl.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/OrganizerRepositoryImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..b3590e6f4d3638314205e3e98e81f0d96dbb582b --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/OrganizerRepositoryImpl.kt @@ -0,0 +1,8 @@ +package band.effective.office.tablet.network.repository.impl + +import band.effective.office.tablet.network.api.Api +import band.effective.office.tablet.network.repository.OrganizerRepository + +class OrganizerRepositoryImpl(private val api: Api) : OrganizerRepository { + override suspend fun getOrganizersList(): List = api.getOrganizers() +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/RoomRepositoryImpl.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/RoomRepositoryImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..23525a5d8dbbe271d7aef88db20888ede826491b --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/RoomRepositoryImpl.kt @@ -0,0 +1,9 @@ +package band.effective.office.tablet.network.repository.impl + +import band.effective.office.tablet.domain.model.RoomInfo +import band.effective.office.tablet.network.api.Api +import band.effective.office.tablet.network.repository.RoomRepository + +class RoomRepositoryImpl(private val api: Api): RoomRepository { + override suspend fun getRoomInfo() = api.getRoomInfo() +} \ No newline at end of file diff --git a/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/ServerUpdateRepositoryImpl.kt b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/ServerUpdateRepositoryImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..72b410cd01f4edde57a9a1d6624d247f1915da88 --- /dev/null +++ b/tabletApp/features/network/src/commonMain/kotlin/band/effective/office/tablet/network/repository/impl/ServerUpdateRepositoryImpl.kt @@ -0,0 +1,21 @@ +package band.effective.office.tablet.network.repository.impl + +import band.effective.office.tablet.network.api.Api +import band.effective.office.tablet.network.model.WebServerEvent +import band.effective.office.tablet.network.repository.ServerUpdateRepository +import kotlinx.coroutines.CoroutineScope + +class ServerUpdateRepositoryImpl(private val api: Api) : ServerUpdateRepository { + override suspend fun subscribeOnUpdates( + scope: CoroutineScope, + roomInfoUpdateHandler: () -> Unit, + organizersListUpdateHandler: () -> Unit + ) { + api.subscribeOnWebHock(scope) { event -> + when (event) { + is WebServerEvent.OrganizerInfoUpdate -> organizersListUpdateHandler() + is WebServerEvent.RoomInfoUpdate -> roomInfoUpdateHandler() + } + } + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/build.gradle.kts b/tabletApp/features/roomInfo/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..46ebb661237436e11fd46bb00efbd2f0967d6fc8 --- /dev/null +++ b/tabletApp/features/roomInfo/build.gradle.kts @@ -0,0 +1,74 @@ +plugins { + id(Plugins.AndroidLib.plugin) + id(Plugins.MultiplatformCompose.plugin) + id(Plugins.Kotlin.plugin) + id(Plugins.Parcelize.plugin) + id(Plugins.Libres.plugin) +} + + +android { + compileSdk = 33 + sourceSets["main"].apply { + manifest.srcFile("src/androidMain/AndroidManifest.xml") + res.srcDirs("src/androidMain/resources") + res.srcDir("build/generated/libres/android/resources") + } +} + +kotlin { + android { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } + + sourceSets { + val commonMain by getting { + dependencies { + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + + // Decompose + implementation(Dependencies.Decompose.decompose) + implementation(Dependencies.Decompose.extensions) + + // Koin + api(Dependencies.Koin.core) + + //Libres + implementation(Dependencies.Libres.libresCompose) + + // MVI Kotlin + api(Dependencies.MviKotlin.mviKotlin) + api(Dependencies.MviKotlin.mviKotlinMain) + api(Dependencies.MviKotlin.mviKotlinExtensionsCoroutines) + + implementation(project(":tabletApp:features:core")) + implementation(project(":tabletApp:features:network")) + implementation(project(":tabletApp:features:domain")) + implementation(project(":tabletApp:features:selectRoom")) + } + } + val androidMain by getting { + dependencies { + // Koin + api(Dependencies.Koin.android) + + implementation(project(":tabletApp:features:selectRoom")) + } + } + } +} + +libres { + // https://github.com/Skeptick/libres#setup + generatedClassName = "MainRes" // "Res" by default + generateNamedArguments = true // false by default + baseLocaleLanguageCode = "ru" // "en" by default + camelCaseNamesForAppleFramework = true // false by default + +} diff --git a/tabletApp/features/roomInfo/src/androidMain/AndroidManifest.xml b/tabletApp/features/roomInfo/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..c428412fcfbbac7d2b911485e1d8b88ff4637d6c --- /dev/null +++ b/tabletApp/features/roomInfo/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tabletApp/features/roomInfo/src/androidMain/kotlin/band/effective/office/tablet/di/InitRoomInfoKoin.kt b/tabletApp/features/roomInfo/src/androidMain/kotlin/band/effective/office/tablet/di/InitRoomInfoKoin.kt new file mode 100644 index 0000000000000000000000000000000000000000..07f2ebf4a3d23df1e1f2c2cd54c654f59d0b5dd4 --- /dev/null +++ b/tabletApp/features/roomInfo/src/androidMain/kotlin/band/effective/office/tablet/di/InitRoomInfoKoin.kt @@ -0,0 +1,7 @@ +package band.effective.office.tablet.di + +import org.koin.core.context.startKoin + +fun initRoomInfoKoin() = startKoin { + modules(commonModule, selectRoomModule) +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/di/CommonModule.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/di/CommonModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..4935727d6cd0c8f4ce5d5a6a6107b9d6423572a1 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/di/CommonModule.kt @@ -0,0 +1,9 @@ +package band.effective.office.tablet.di + +import networkModule +import org.koin.core.context.loadKoinModules +import org.koin.dsl.module + +val commonModule = module { + loadKoinModules(listOf(networkModule, domainModule, uiModule)) +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/di/UiModule.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/di/UiModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..4dc1977467cf51c07c936df19d9b234dff3421ec --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/di/UiModule.kt @@ -0,0 +1,13 @@ +package band.effective.office.tablet.di + +import band.effective.office.tablet.domain.MockController +import band.effective.office.tablet.domain.useCase.BookingUseCase +import band.effective.office.tablet.domain.useCase.CheckBookingUseCase +import band.effective.office.tablet.domain.useCase.UpdateUseCase +import org.koin.dsl.module + +val uiModule = module { + single { UpdateUseCase(get(), get(), get(), get()) } + single { CheckBookingUseCase(get()) } + single { MockController(get()) } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/MainComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/MainComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/MainScreenEvent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/MainScreenEvent.kt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/MainScreenState.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/MainScreenState.kt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/RealMainComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/RealMainComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/BookingRoomComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/BookingRoomComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..8f8bdb4809babf8bb8ce59dfc3b04f52cf593ddc --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/BookingRoomComponent.kt @@ -0,0 +1,64 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents + +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.store.BookingStore +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.store.BookingStoreFactory +import band.effective.office.tablet.utils.componentCoroutineScope +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.childContext +import com.arkivanov.mvikotlin.core.instancekeeper.getStore +import com.arkivanov.mvikotlin.core.store.StoreFactory +import com.arkivanov.mvikotlin.extensions.coroutines.stateFlow +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.util.Calendar +import java.util.GregorianCalendar + +class BookingRoomComponent( + private val componentContext: ComponentContext, + storeFactory: StoreFactory, + private val onCurrentBookingRoom: () -> Unit, + private val onBookingOtherRoom: () -> Unit +) : + ComponentContext by componentContext { + + private val bookingStore = instanceKeeper.getStore { + BookingStoreFactory(storeFactory).create() + } + + @OptIn(ExperimentalCoroutinesApi::class) + val state = bookingStore.stateFlow + + val dateTimeComponent: RealDateTimeComponent = + RealDateTimeComponent( + childContext("dateTime"), + changeDay = { bookingStore.accept(BookingStore.Intent.OnChangeDate(it)) } + ) + val eventLengthComponent: RealEventLengthComponent = + RealEventLengthComponent(childContext("length"), + changeLength = { bookingStore.accept(BookingStore.Intent.OnChangeLength(it)) }) + val eventOrganizerComponent: RealEventOrganizerComponent = + RealEventOrganizerComponent( + childContext("organizer"), + onSelectOrganizer = { bookingStore.accept(BookingStore.Intent.OnChangeOrganizer(it)) }) + + fun bookingCurrentRoom() { + onCurrentBookingRoom() + } + + fun bookingOtherRoom(){ + onBookingOtherRoom() + } + + + //TODO(Maksim Mishenko): think about while(true) + private fun updateSelectTime() { + componentCoroutineScope().launch { + while (true) { + val now = GregorianCalendar() + //mutableState.update { it.copy(selectDate = now) } + delay((60 - now.get(Calendar.SECOND)) * 1000L) + } + } + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/BookingRoomView.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/BookingRoomView.kt new file mode 100644 index 0000000000000000000000000000000000000000..7c2f0900772dae3ebad945166c5294092cd14316 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/BookingRoomView.kt @@ -0,0 +1,83 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.roomInfo.MainRes +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.uiComponents.BusyAlertView +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.uiComponents.DateTimeView +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.uiComponents.EventLengthView +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.uiComponents.EventOrganizerView + +@Composable +fun BookingRoomView(modifier: Modifier = Modifier, bookingRoomComponent: BookingRoomComponent) { + val state by bookingRoomComponent.state.collectAsState() + Surface(modifier = modifier.fillMaxSize(), color = Color(0xFF252322)) { + Column(modifier = Modifier.fillMaxSize()) { + Spacer(modifier = Modifier.height(63.dp)) + Text( + text = MainRes.string.booking_view_title, + color = Color(0xFFFAFAFA), + fontSize = 36.sp + ) + Spacer(modifier = Modifier.height(25.dp)) + DateTimeView( + modifier = Modifier.fillMaxWidth().height(100.dp), + component = bookingRoomComponent.dateTimeComponent, + selectDate = state.selectDate + ) + Spacer(modifier = Modifier.height(25.dp)) + EventLengthView( + modifier = Modifier.fillMaxWidth().height(100.dp), + component = bookingRoomComponent.eventLengthComponent, + currentLength = state.length, + isBusy = state.isBusy + ) + Spacer(modifier = Modifier.height(25.dp)) + EventOrganizerView( + modifier = Modifier.fillMaxWidth().height(100.dp), + component = bookingRoomComponent.eventOrganizerComponent, + organizers = state.organizers + ) + Spacer(modifier = Modifier.height(50.dp)) + if (state.isBusy) { + BusyAlertView( + modifier = Modifier.fillMaxWidth(), + event = state.busyEvent, + onClick = { bookingRoomComponent.bookingOtherRoom() }) + } + } + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) { + Button( + modifier = Modifier.fillMaxWidth().height(60.dp).clip(RoundedCornerShape(100.dp)), + onClick = { bookingRoomComponent.bookingCurrentRoom() }, + colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFFFFFFFF), + backgroundColor = Color(0xFFEF7234), + disabledBackgroundColor = Color(0xFF342C28), + disabledContentColor = Color(0xFF808080) + ), + enabled = !state.isBusy + ) { + Text(text = MainRes.string.booking_button_text.format(roomName = state.roomName)) + } + } + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealDateTimeComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealDateTimeComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..a62bcda6694c762c0e0ef25254de57f4c6f395d0 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealDateTimeComponent.kt @@ -0,0 +1,11 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents + +import com.arkivanov.decompose.ComponentContext + +class RealDateTimeComponent( + componentContext: ComponentContext, + private val changeDay: (Int) -> Unit +) : ComponentContext by componentContext { + fun incrementDay() = changeDay(1) + fun decrementDay() = changeDay(-1) +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealEventLengthComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealEventLengthComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..5c75b21adbc0f281cd419d80f03054e83aa34183 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealEventLengthComponent.kt @@ -0,0 +1,11 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents + +import com.arkivanov.decompose.ComponentContext + +class RealEventLengthComponent( + componentContext: ComponentContext, + private val changeLength: (Int) -> Unit +) : ComponentContext by componentContext { + fun increment() = changeLength(15) + fun decrement() = changeLength(-30) +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealEventOrganizerComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealEventOrganizerComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..9a8f0c231016a7e627ea49105fdef705603bc86c --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/RealEventOrganizerComponent.kt @@ -0,0 +1,28 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents + +import com.arkivanov.decompose.ComponentContext +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update + +class RealEventOrganizerComponent( + componentContext: ComponentContext, + private val onSelectOrganizer: (String) -> Unit +) : + ComponentContext by componentContext { + private var mutableExpanded = MutableStateFlow(false) + val expanded = mutableExpanded.asStateFlow() + + private var mutableSelectedItem = MutableStateFlow("") + val selectedItem = mutableSelectedItem.asStateFlow() + + fun onExpandedChange() { + mutableExpanded.update { !it } + } + + fun onSelectItem(item: String) { + mutableSelectedItem.update { item } + mutableExpanded.update { false } + onSelectOrganizer(item) + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/store/BookingStore.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/store/BookingStore.kt new file mode 100644 index 0000000000000000000000000000000000000000..c4e96e28ff58f18e89877d4cc29e9efc8bfc34eb --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/store/BookingStore.kt @@ -0,0 +1,38 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.store + +import band.effective.office.tablet.domain.model.EventInfo +import com.arkivanov.mvikotlin.core.store.Store +import java.util.Calendar +import java.util.GregorianCalendar + +interface BookingStore : Store { + sealed interface Intent { + object OnBookingCurrentRoom : Intent + object OnBookingOtherRoom : Intent + data class OnChangeDate(val changeInDay: Int) : Intent + data class OnChangeLength(val change: Int) : Intent + data class OnChangeOrganizer(val newOrganizer: String) : Intent + } + + data class State( + val length: Int, + val organizer: String, + val organizers: List, + val selectDate: Calendar, + val isBusy: Boolean, + val busyEvent: EventInfo, + val roomName: String + ) { + companion object { + val default = State( + length = 0, + organizer = "", + organizers = listOf(), + selectDate = GregorianCalendar(), + isBusy = false, + busyEvent = EventInfo.emptyEvent, + roomName = "Sirius" + ) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/store/BookingStoreFactory.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/store/BookingStoreFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..66e57ac0f73ab5dc2877554fb7e4fa251f760cce --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/store/BookingStoreFactory.kt @@ -0,0 +1,187 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.store + +import band.effective.office.tablet.domain.model.EventInfo +import band.effective.office.tablet.domain.model.RoomInfo +import band.effective.office.tablet.domain.useCase.CheckBookingUseCase +import band.effective.office.tablet.domain.useCase.UpdateUseCase +import com.arkivanov.mvikotlin.core.store.Reducer +import com.arkivanov.mvikotlin.core.store.Store +import com.arkivanov.mvikotlin.core.store.StoreFactory +import com.arkivanov.mvikotlin.core.utils.ExperimentalMviKotlinApi +import com.arkivanov.mvikotlin.extensions.coroutines.CoroutineExecutor +import com.arkivanov.mvikotlin.extensions.coroutines.coroutineBootstrapper +import kotlinx.coroutines.launch +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import java.util.Calendar + +class BookingStoreFactory(private val storeFactory: StoreFactory) : KoinComponent { + + val checkBookingUseCase: CheckBookingUseCase by inject() + val updateUseCase: UpdateUseCase by inject() + + @OptIn(ExperimentalMviKotlinApi::class) + fun create(): BookingStore = + object : BookingStore, + Store by storeFactory.create( + name = "MainStore", + initialState = BookingStore.State.default, + bootstrapper = coroutineBootstrapper { + launch() { + val eventInfo = EventInfo.emptyEvent + dispatch( + Action.Init( + updateUseCase.getOrganizersList(), + !checkBookingUseCase(eventInfo), + checkBookingUseCase.busyEvent(eventInfo) ?: EventInfo.emptyEvent + ) + ) + dispatch(Action.UpdateOrganizers(updateUseCase.getOrganizersList())) + updateUseCase(this, + { + launch { + dispatch( + Action.UpdateEvents(it) + ) + } + + }, + { dispatch(Action.UpdateOrganizers(it)) }) + } + }, + executorFactory = ::ExecutorImpl, + reducer = ReducerImpl + ) {} + + private sealed interface Action { + data class UpdateOrganizers(val organizers: List) : Action + data class Init( + val organizers: List, + val isBusy: Boolean, + val busyEvent: EventInfo + ) : Action + + data class UpdateEvents(val newData: RoomInfo) : Action + } + + private sealed interface Message { + data class ChangeEvent( + val selectDate: Calendar, + val length: Int, + val isBusy: Boolean, + val busyEvent: EventInfo + ) : Message + + data class ChangeOrganizer(val newOrganizer: String) : Message + object BookingCurrentRoom : Message + object BookingOtherRoom : Message + data class UpdateOrganizers(val organizers: List) : Message + data class UpdateBusy( + val isBusy: Boolean, + val busyEvent: EventInfo + ) : Message + } + + private inner class ExecutorImpl() : + CoroutineExecutor() { + override fun executeIntent( + intent: BookingStore.Intent, + getState: () -> BookingStore.State + ) { + when (intent) { + is BookingStore.Intent.OnBookingCurrentRoom -> dispatch(Message.BookingCurrentRoom) + is BookingStore.Intent.OnBookingOtherRoom -> dispatch(Message.BookingOtherRoom) + is BookingStore.Intent.OnChangeDate -> changeDate(getState(), intent.changeInDay) + is BookingStore.Intent.OnChangeLength -> changeLength(getState(), intent.change) + is BookingStore.Intent.OnChangeOrganizer -> dispatch(Message.ChangeOrganizer(intent.newOrganizer)) + } + } + + override fun executeAction(action: Action, getState: () -> BookingStore.State) { + when (action) { + is Action.UpdateOrganizers -> dispatch(Message.UpdateOrganizers(action.organizers)) + is Action.Init -> { + val defaultEvent = EventInfo.emptyEvent + dispatch( + Message.ChangeEvent( + selectDate = defaultEvent.startTime, + length = 0, + isBusy = action.isBusy, + busyEvent = action.busyEvent + ) + ) + } + + is Action.UpdateEvents -> checkBusy(getState()) + } + } + + fun changeDate(state: BookingStore.State, changeDay: Int) = scope.launch() { + val event = state.copy(selectDate = state.selectDate.dayUpdate(changeDay)).toEvent() + dispatch( + Message.ChangeEvent( + event.startTime, + state.length, + !checkBookingUseCase(event), + checkBookingUseCase.busyEvent(event) ?: EventInfo.emptyEvent + ) + ) + } + + fun changeLength(state: BookingStore.State, change: Int) = scope.launch() { + val event = state.copy(length = state.length + change).toEvent() + dispatch( + Message.ChangeEvent( + event.startTime, + state.length + change, + !checkBookingUseCase(event), + checkBookingUseCase.busyEvent(event) ?: EventInfo.emptyEvent + ) + ) + } + + fun checkBusy(state: BookingStore.State) = scope.launch { + dispatch( + Message.UpdateBusy( + !checkBookingUseCase(state.toEvent()), + checkBookingUseCase.busyEvent(state.toEvent()) ?: EventInfo.emptyEvent + ) + ) + } + } + + private fun BookingStore.State.toEvent(): EventInfo { + val finishDate = selectDate.clone() as Calendar + finishDate.add(Calendar.MINUTE, length) + return EventInfo( + startTime = selectDate.clone() as Calendar, + finishTime = finishDate, + organizer = organizer + ) + } + + private object ReducerImpl : Reducer { + override fun BookingStore.State.reduce(msg: Message): BookingStore.State = + when (msg) { + is Message.BookingCurrentRoom -> copy() + is Message.BookingOtherRoom -> copy() + is Message.ChangeEvent -> copy( + selectDate = msg.selectDate, + length = msg.length, + isBusy = msg.isBusy, + busyEvent = msg.busyEvent + ) + + is Message.ChangeOrganizer -> copy(organizer = msg.newOrganizer) + is Message.UpdateOrganizers -> copy(organizers = msg.organizers) + is Message.UpdateBusy -> copy(isBusy = msg.isBusy, busyEvent = msg.busyEvent) + } + + } + + private fun Calendar.dayUpdate(changeDay: Int): Calendar { + val result = clone() as Calendar + result.add(Calendar.DAY_OF_MONTH, changeDay) + return result + } +} diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/BusyAlertView.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/BusyAlertView.kt new file mode 100644 index 0000000000000000000000000000000000000000..410640d154ef1bfc20fd9cbe5c6d447dfad26fda --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/BusyAlertView.kt @@ -0,0 +1,74 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.uiComponents + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.domain.model.EventInfo +import band.effective.office.tablet.features.roomInfo.MainRes +import band.effective.office.tablet.utils.CalendarStringConverter +import io.github.skeptick.libres.compose.painterResource +import java.util.Calendar + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun BusyAlertView(modifier: Modifier, event: band.effective.office.tablet.domain.model.EventInfo, onClick: () -> Unit) { + Column(modifier = modifier) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = Modifier, + painter = painterResource(MainRes.image.allert), + contentDescription = null + ) + Spacer(Modifier.width(10.dp)) + Text( + text = MainRes.string.busy_time_string.format( + startTime = event.startTime.time(), + finishTime = event.finishTime.time(), + organizer = event.organizer + ), + color = Color(0xFFEB4C2A), + fontSize = 19.sp + ) + } + Spacer(modifier = Modifier.height(30.dp)) + Surface(color = Color(0xFF252322), onClick = { onClick() }) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = MainRes.string.see_free_room, + color = Color(0xFFA362F8), + fontSize = 19.sp + ) + Image( + modifier = Modifier, + painter = painterResource(MainRes.image.arrow_to_right), + contentDescription = null + ) + } + } + + } +} + +private fun Calendar.time() = CalendarStringConverter.calendarToString(this, "HH:mm") \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/DateTimeView.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/DateTimeView.kt new file mode 100644 index 0000000000000000000000000000000000000000..bb621344c5bd21b42ee9e2e0439de943f739ad65 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/DateTimeView.kt @@ -0,0 +1,95 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.uiComponents + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.roomInfo.MainRes +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.RealDateTimeComponent +import band.effective.office.tablet.utils.CalendarStringConverter +import io.github.skeptick.libres.compose.painterResource +import java.util.Calendar + +@Composable +fun DateTimeView(modifier: Modifier, component: RealDateTimeComponent, selectDate: Calendar) { + Column(modifier = modifier) { + Text( + text = MainRes.string.select_date_tine_title, + color = Color(0xFF808080), + fontSize = 16.sp + ) + Spacer(modifier = Modifier.height(10.dp)) + Row(modifier = Modifier.fillMaxSize()) { + Button( + modifier = Modifier.fillMaxHeight().weight(1f).clip(RoundedCornerShape(15.dp)), + onClick = { component.decrementDay() }, + colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFFFFFFFF), + backgroundColor = Color(0xFF302D2C) + ) + ) { + Text( + text = "<", + color = Color(0xFF777777), + fontSize = 20.sp + ) + } + Spacer(modifier = Modifier.width(10.dp)) + Button( + modifier = Modifier.fillMaxHeight().weight(4f).clip(RoundedCornerShape(15.dp)), + onClick = { }, + colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFFFFFFFF), + backgroundColor = Color(0xFF302D2C) + ) + ) { + Text( + text = selectDate.dateTime(), + color = Color(0xFFFAFAFA), + fontSize = 20.sp + ) + Spacer(Modifier.width(5.dp)) + Image( + modifier = Modifier, + painter = painterResource(MainRes.image.calendar), + contentDescription = null + ) + } + Spacer(modifier = Modifier.width(10.dp)) + Button( + modifier = Modifier.fillMaxHeight().weight(1f).clip(RoundedCornerShape(15.dp)), + onClick = { component.incrementDay() }, + colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFFFFFFFF), + backgroundColor = Color(0xFF302D2C) + ) + ) { + Text( + text = ">", + color = Color(0xFF777777), + fontSize = 20.sp + ) + } + } + } +} + + +private fun Calendar.time() = CalendarStringConverter.calendarToString(this, "HH:mm") +private fun Calendar.date() = CalendarStringConverter.calendarToString(this, "dd MMMM") +private fun Calendar.dateTime() = + MainRes.string.start_date_time.format(time = time(), date = date()) \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/EventLengthView.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/EventLengthView.kt new file mode 100644 index 0000000000000000000000000000000000000000..f0e17603998d56ae0e5edbd62c1d591e7087f3b4 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/EventLengthView.kt @@ -0,0 +1,86 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.uiComponents + +import android.util.Log +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.roomInfo.MainRes +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.RealEventLengthComponent + +@Composable +fun EventLengthView( + modifier: Modifier = Modifier, + component: RealEventLengthComponent, + currentLength: Int, + isBusy: Boolean +) { + val space = 50.dp + Column(modifier = modifier) { + Text( + text = MainRes.string.select_length_title, + color = Color(0xFF808080), + fontSize = 16.sp + ) + Spacer(modifier = Modifier.height(10.dp)) + Row( + modifier = Modifier.fillMaxSize(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Button( + modifier = Modifier.fillMaxHeight().weight(1f).clip(RoundedCornerShape(15.dp)), + onClick = { component.decrement() }, + colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFFFFFFFF), + backgroundColor = Color(0xFF302D2C) + ) + ) { + Text( + text = MainRes.string.minus_date_button_string, + color = Color(0xFFFAFAFA), + fontSize = 20.sp + ) + } + Spacer(modifier = Modifier.width(space)) + Text( + text = MainRes.string.current_length_string.format(currentLength.toString()), + color = if (isBusy) Color(0xFFA362F8) else Color(0xFFFAFAFA), + fontSize = 32.sp + ) + Spacer(modifier = Modifier.width(space)) + Button( + modifier = Modifier.fillMaxHeight().weight(1f).clip(RoundedCornerShape(15.dp)), + onClick = { + Log.e("checj","gbgdgh") + component.increment() }, + colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFFFFFFFF), + backgroundColor = Color(0xFF302D2C) + ) + ) { + Text( + text = MainRes.string.plus_date_button_string, + color = Color(0xFFFAFAFA), + fontSize = 20.sp + ) + } + } + } + +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/EventOrganizerView.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/EventOrganizerView.kt new file mode 100644 index 0000000000000000000000000000000000000000..e60d4f05eb42be5bd43d7aece600c158e30bd1fe --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/bookingRoomComponents/uiComponents/EventOrganizerView.kt @@ -0,0 +1,109 @@ +package band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.uiComponents + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.ExposedDropdownMenuBox +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.roomInfo.MainRes +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.RealEventOrganizerComponent +import io.github.skeptick.libres.compose.painterResource + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun EventOrganizerView( + modifier: Modifier = Modifier, + component: RealEventOrganizerComponent, + organizers: List +) { + val expended by component.expanded.collectAsState() + val selectedItem by component.selectedItem.collectAsState() + Column(modifier = modifier) { + Text( + text = MainRes.string.select_organizer_title, + color = Color(0xFF808080), + fontSize = 16.sp + ) + Spacer(modifier = Modifier.height(10.dp)) + ExposedDropdownMenuBox( + expanded = expended, + onExpandedChange = { component.onExpandedChange() } + ) { + Row( + modifier = Modifier + .clip(RoundedCornerShape(15.dp)) + .fillMaxSize() + .background(color = Color(0xFF302D2C)) + .padding(horizontal = 20.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + if (selectedItem.notSelect()) { + Text( + text = MainRes.string.selectbox_organizer_title, + color = Color(0xFF777777) + ) + } else { + Text( + text = selectedItem, + color = Color(0xFFFAFAFA) + ) + } + + Image( + modifier = Modifier, + painter = painterResource(MainRes.image.arrow_to_down), + contentDescription = null + ) + } + + ExposedDropdownMenu( + modifier = Modifier + .background( + color = Color(0xFF252322) + ), + expanded = expended, + onDismissRequest = { component.onExpandedChange() } + ) { + Column( + modifier = Modifier.background( + color = Color(0xFF302D2C), + shape = RoundedCornerShape(15.dp) + ) + ) { + organizers.forEach { organizer -> + DropdownMenuItem(onClick = { + component.onSelectItem(organizer) + }) { + Text(text = organizer, color = Color(0xFFFAFAFA)) + } + } + } + } + + } + } +} + +private fun String.notSelect() = this == "" \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/components/MainScreenView.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/components/MainScreenView.kt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/components/bookingRoomComponents/RealBookingRoomComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/components/bookingRoomComponents/RealBookingRoomComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..6083a5ff485556f44bd7a1848eaceb1e7be98130 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainComponent.kt @@ -0,0 +1,49 @@ +package band.effective.office.tablet.ui.mainScreen.mainScreen + +import band.effective.office.tablet.domain.MockBooking +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.BookingRoomComponent +import band.effective.office.tablet.ui.mainScreen.mainScreen.store.MainStore +import band.effective.office.tablet.ui.mainScreen.mainScreen.store.MainStoreFactory +import band.effective.office.tablet.ui.mainScreen.mockComponets.MockSettingsComponent +import band.effective.office.tablet.ui.mainScreen.mockComponets.RealMockSettingsComponent +import band.effective.office.tablet.ui.selectRoomScreen.RealSelectRoomComponent +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.childContext +import com.arkivanov.mvikotlin.core.instancekeeper.getStore +import com.arkivanov.mvikotlin.core.store.StoreFactory +import com.arkivanov.mvikotlin.extensions.coroutines.stateFlow +import kotlinx.coroutines.ExperimentalCoroutinesApi + +class MainComponent( + componentContext: ComponentContext, + storeFactory: StoreFactory, + private val OnSelectOtherRoomRequest: () -> Unit +) : ComponentContext by componentContext { + + val mockSettingsComponent: MockSettingsComponent = + RealMockSettingsComponent( + componentContext = childContext(key = "mock") + ) + val bookingRoomComponent: BookingRoomComponent = BookingRoomComponent( + componentContext = childContext(key = "bookingRoom"), + onCurrentBookingRoom = { mainStore.accept(MainStore.Intent.OnBookingCurrentRoomRequest) }, + storeFactory = storeFactory, + onBookingOtherRoom = { OnSelectOtherRoomRequest() } + ) + val selectRoomComponent: RealSelectRoomComponent = + RealSelectRoomComponent( + componentContext = childContext(key = "bookingCurrentRoom"), + booking = MockBooking.bookingCheckTime15min, + onCloseRequest = { mainStore.accept(MainStore.Intent.CloseModal) } + ) + + private val mainStore = instanceKeeper.getStore { + MainStoreFactory( + storeFactory = storeFactory + ).create() + } + + @OptIn(ExperimentalCoroutinesApi::class) + val state = mainStore.stateFlow + +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainScreen.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainScreen.kt new file mode 100644 index 0000000000000000000000000000000000000000..ebf18566fded044d844e4b92735d1020d33f291e --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainScreen.kt @@ -0,0 +1,26 @@ +package band.effective.office.tablet.ui.mainScreen.mainScreen + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue + +@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) +@Composable +fun MainScreen(component: MainComponent) { + val state by component.state.collectAsState() + when { + state.isError -> {} + state.isLoad -> {} + state.isData -> { + MainScreenView( + room = state.roomInfo, + showBookingModal = state.showBookingModal, + mockComponent = component.mockSettingsComponent, + bookingRoomComponent = component.bookingRoomComponent, + selectRoomComponent = component.selectRoomComponent + ) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainScreenView.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainScreenView.kt new file mode 100644 index 0000000000000000000000000000000000000000..42e022c8406a5b3e6dbea89cc8c91699bc8a99cc --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/MainScreenView.kt @@ -0,0 +1,60 @@ +package band.effective.office.tablet.ui.mainScreen.mainScreen + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import band.effective.office.tablet.domain.model.RoomInfo +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.BookingRoomComponent +import band.effective.office.tablet.ui.mainScreen.bookingRoomComponents.BookingRoomView +import band.effective.office.tablet.ui.mainScreen.mockComponets.MockSettingView +import band.effective.office.tablet.ui.mainScreen.mockComponets.MockSettingsComponent +import band.effective.office.tablet.ui.mainScreen.roomInfoComponents.RoomInfoComponent +import band.effective.office.tablet.ui.selectRoomScreen.RealSelectRoomComponent +import band.effective.office.tablet.ui.selectRoomScreen.SelectRoomView + +@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) +@Composable +fun MainScreenView( + room: RoomInfo, + showBookingModal: Boolean, + mockComponent: MockSettingsComponent, + bookingRoomComponent: BookingRoomComponent, + selectRoomComponent: RealSelectRoomComponent +) { + Box(modifier = Modifier.fillMaxSize()) { + /*NOTE(Maksim Mishenko): + * infoViewWidth is part of the width occupied by roomInfoView + * infoViewWidth = infoViewFrame.width / mainScreenFrame.width + * where infoViewFrame, mainScreenFrame is frames from figma and all width I get from figma*/ + val infoViewWidth = 627f / 1133f + Row(modifier = Modifier.fillMaxSize().background(color = Color(0xff1E1C1A))) { + RoomInfoComponent( + modifier = Modifier.fillMaxHeight().fillMaxWidth(infoViewWidth), + room = room + ) + Box(modifier = Modifier.fillMaxSize()) { + BookingRoomView( + modifier = Modifier.background(color = Color(0xFF252322)).fillMaxSize() + .padding(25.dp), + bookingRoomComponent = bookingRoomComponent + ) + MockSettingView(mockComponent) + } + } + Box(modifier = Modifier.fillMaxSize()) { + if (showBookingModal) + SelectRoomView(component = selectRoomComponent) + } + } + +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/store/MainStore.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/store/MainStore.kt new file mode 100644 index 0000000000000000000000000000000000000000..f0a30f351acad65118404c57f97c8911e1eeb14a --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/store/MainStore.kt @@ -0,0 +1,33 @@ +package band.effective.office.tablet.ui.mainScreen.mainScreen.store + +import band.effective.office.tablet.domain.model.RoomInfo +import com.arkivanov.mvikotlin.core.store.Store + +interface MainStore : Store { + sealed interface Intent { + object OnBookingCurrentRoomRequest : Intent + object OnBookingOtherRoomRequest : Intent + object CloseModal: Intent + } + + data class State( + val isLoad: Boolean, + val isData: Boolean, + val isError: Boolean, + val roomInfo: RoomInfo, + val error: String, + val showBookingModal: Boolean + ) { + companion object { + val defaultState = + State( + isLoad = true, + isData = false, + isError = false, + roomInfo = RoomInfo.defaultValue, + error = "", + showBookingModal = false + ) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/store/MainStoreFactory.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/store/MainStoreFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..bc3317f1da80423bc4ea04ea035bc6977804d8bf --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mainScreen/store/MainStoreFactory.kt @@ -0,0 +1,87 @@ +package band.effective.office.tablet.ui.mainScreen.mainScreen.store + +import band.effective.office.tablet.domain.model.RoomInfo +import band.effective.office.tablet.domain.useCase.UpdateUseCase +import com.arkivanov.mvikotlin.core.store.Reducer +import com.arkivanov.mvikotlin.core.store.Store +import com.arkivanov.mvikotlin.core.store.StoreFactory +import com.arkivanov.mvikotlin.core.utils.ExperimentalMviKotlinApi +import com.arkivanov.mvikotlin.extensions.coroutines.CoroutineExecutor +import com.arkivanov.mvikotlin.extensions.coroutines.coroutineBootstrapper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +class MainStoreFactory(private val storeFactory: StoreFactory) : KoinComponent { + + private val updateUseCase: UpdateUseCase by inject() + + @OptIn(ExperimentalMviKotlinApi::class) + fun create(): MainStore = + object : MainStore, + Store by storeFactory.create( + name = "MainStore", + initialState = MainStore.State.defaultState, + bootstrapper = coroutineBootstrapper { + launch() { + dispatch(Action.UpdateRoomInfo(updateUseCase.getRoomInfo())) + updateUseCase( + scope = this, + roomUpdateHandler = { roomInfo -> + dispatch( + Action.UpdateRoomInfo( + roomInfo + ) + ) + }, + organizerUpdateHandler = {}) + } + }, + executorFactory = ::ExecutorImpl, + reducer = ReducerImpl + ) {} + + private sealed interface Action { + data class UpdateRoomInfo(val roomInfo: RoomInfo) : Action + } + + private sealed interface Message { + data class UpdateRoomInfo(val roomInfo: RoomInfo) : Message + object BookingCurrentRoom : Message + object BookingOtherRoom : Message + object CloseModal : Message + } + + private inner class ExecutorImpl() : + CoroutineExecutor() { + override fun executeIntent(intent: MainStore.Intent, getState: () -> MainStore.State) { + when (intent) { + is MainStore.Intent.OnBookingCurrentRoomRequest -> dispatch(Message.BookingCurrentRoom) + is MainStore.Intent.OnBookingOtherRoomRequest -> dispatch(Message.BookingOtherRoom) + is MainStore.Intent.CloseModal -> dispatch(Message.CloseModal) + } + } + + override fun executeAction(action: Action, getState: () -> MainStore.State) { + when (action) { + is Action.UpdateRoomInfo -> dispatch(Message.UpdateRoomInfo(action.roomInfo)) + } + } + } + + private object ReducerImpl : Reducer { + override fun MainStore.State.reduce(message: Message): MainStore.State = + when (message) { + is Message.BookingCurrentRoom -> copy(showBookingModal = true) + is Message.BookingOtherRoom -> copy() + is Message.UpdateRoomInfo -> copy( + roomInfo = message.roomInfo, + isData = true, + isLoad = false + ) + + is Message.CloseModal -> copy(showBookingModal = false) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingView.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingView.kt new file mode 100644 index 0000000000000000000000000000000000000000..84c488acf84655ff622ec36db3a633b7acbc1c6c --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingView.kt @@ -0,0 +1,73 @@ +package band.effective.office.tablet.ui.mainScreen.mockComponets + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material.Checkbox +import androidx.compose.material.CheckboxDefaults +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun MockSettingView(component: MockSettingsComponent) { + val state by component.state.collectAsState() + Surface( + modifier = Modifier.fillMaxWidth().height(100.dp), + color = Color(0xFF252322), + onClick = { component.sendEvent(MockSettingsEvent.OnSwitchVisible) }) { + if (state.isVisible) { + Column { + Row { + Item( + checked = state.isBusy, + onCheckedChange = { component.sendEvent(MockSettingsEvent.OnSwitchBusy(it)) }, + text = "Комната занята" + ) + Item( + checked = state.isManyEvent, + onCheckedChange = { + component.sendEvent( + MockSettingsEvent.OnSwitchEventCount( + it + ) + ) + }, + text = "Много меропритий" + ) + Item( + checked = state.isHaveTv, + onCheckedChange = { component.sendEvent(MockSettingsEvent.OnSwitchTv(it)) }, + text = "Есть tv" + ) + } + } + } + } +} + +@Composable +private fun Item(checked: Boolean, onCheckedChange: (Boolean) -> Unit, text: String) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Checkbox( + checked = checked, + onCheckedChange = { onCheckedChange(it) }, + colors = CheckboxDefaults.colors(uncheckedColor = Color.White), + ) + Text(text = text, color = Color.White) + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingsComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingsComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..a4d5b0749883ae7004534218cd751c10f55012a2 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingsComponent.kt @@ -0,0 +1,8 @@ +package band.effective.office.tablet.ui.mainScreen.mockComponets + +import kotlinx.coroutines.flow.StateFlow + +interface MockSettingsComponent { + val state: StateFlow + fun sendEvent(event: MockSettingsEvent) +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingsEvent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingsEvent.kt new file mode 100644 index 0000000000000000000000000000000000000000..c581c91d2d8c88cbc043488f8e57c000b8209db4 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockSettingsEvent.kt @@ -0,0 +1,9 @@ +package band.effective.office.tablet.ui.mainScreen.mockComponets + +sealed interface MockSettingsEvent{ + data class OnSwitchEventCount(val newState: Boolean): MockSettingsEvent + data class OnSwitchBusy(val newState: Boolean): MockSettingsEvent + data class OnSwitchTv(val newState: Boolean): MockSettingsEvent + object OnSwitchVisible: MockSettingsEvent + +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockState.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockState.kt new file mode 100644 index 0000000000000000000000000000000000000000..ee01fcf29bad626c450ec68b848119e3a8873d9b --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/MockState.kt @@ -0,0 +1,9 @@ +package band.effective.office.tablet.ui.mainScreen.mockComponets + +data class MockState( + val isBusy: Boolean = false, + val isManyEvent: Boolean = false, + val isHaveTv: Boolean = false, + val isBusyTime: Boolean = false, + val isVisible: Boolean = false +) \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/RealMockSettingsComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/RealMockSettingsComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..41bb9eee2a525df9357d8bec889a24eca8472c28 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/mockComponets/RealMockSettingsComponent.kt @@ -0,0 +1,40 @@ +package band.effective.office.tablet.ui.mainScreen.mockComponets + +import band.effective.office.tablet.domain.MockController +import com.arkivanov.decompose.ComponentContext +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +class RealMockSettingsComponent( + componentContext: ComponentContext +) : ComponentContext by componentContext, KoinComponent, MockSettingsComponent { + private var mutableState = MutableStateFlow(MockState()) + override val state = mutableState.asStateFlow() + + private val mockController: MockController by inject() + + override fun sendEvent(event: MockSettingsEvent) { + when (event) { + is MockSettingsEvent.OnSwitchBusy -> { + mockController.changeBusy(event.newState) + mutableState.update { it.copy(isBusy = event.newState) } + } + + is MockSettingsEvent.OnSwitchEventCount -> { + mockController.changeEventCount(event.newState) + mutableState.update { it.copy(isManyEvent = event.newState) } + } + + is MockSettingsEvent.OnSwitchTv -> { + mockController.changeHaveTv(event.newState) + mutableState.update { it.copy(isHaveTv = event.newState) } + } + + is MockSettingsEvent.OnSwitchVisible -> mutableState.update { it.copy(isVisible = !it.isVisible) } + } + } + +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/BusyRoomInfoComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/BusyRoomInfoComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..2321563f33d63af7b712e2648ea72eaa38dda4c6 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/BusyRoomInfoComponent.kt @@ -0,0 +1,76 @@ +package band.effective.office.tablet.ui.mainScreen.roomInfoComponents + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import band.effective.office.tablet.domain.model.EventInfo +import band.effective.office.tablet.features.roomInfo.MainRes +import band.effective.office.tablet.utils.CalendarStringConverter +import java.util.Calendar + +@Composable +fun BusyRoomInfoComponent( + modifier: Modifier = Modifier, + name: String, + capacity: Int, + isHaveTv: Boolean, + electricSocketCount: Int, + event: EventInfo? +) { + val backgroundColor = Color(0xFFF94C4C) + Surface { + CommonRoomInfoComponent( + modifier = modifier, + name = name, + capacity = capacity, + isHaveTv = isHaveTv, + electricSocketCount = electricSocketCount, + roomOccupancy = MainRes.string.room_occupancy.format( + startTime = event?.startTime?.time() ?: "", + finishTime = event?.finishTime?.time() ?: "", + organizer = event?.organizer ?: "" + ), + backgroundColor = backgroundColor + ) + Box( + modifier = modifier.fillMaxWidth(), + contentAlignment = Alignment.TopEnd + ){ + Button( + modifier = Modifier + .clip(shape = RoundedCornerShape(70.dp)) + .height(60.dp) + .width(150.dp) + .background(color = backgroundColor).border( + width = 3.dp, + color = Color(0xFFFAFAFA), + shape = RoundedCornerShape(70.dp), + ), + colors = ButtonDefaults.buttonColors( + backgroundColor = backgroundColor, + contentColor = Color(0xFFFFFFFF) + ), + onClick = {}) { + Text(text = MainRes.string.stop_meeting_button, color = Color(0xFFFAFAFA)) + } + } + } + +} + +private fun Calendar.time() = CalendarStringConverter.calendarToString(this, "HH:mm") \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/CommonRoomInfoComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/CommonRoomInfoComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..07964acdb3370ee0faed1bdd03cdb7a4bdcda8d4 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/CommonRoomInfoComponent.kt @@ -0,0 +1,110 @@ +package band.effective.office.tablet.ui.mainScreen.roomInfoComponents + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.roomInfo.MainRes +import band.effective.office.tablet.utils.getCorrectDeclension +import io.github.skeptick.libres.compose.painterResource +import io.github.skeptick.libres.images.Image + +@Composable +fun CommonRoomInfoComponent( + modifier: Modifier = Modifier, + name: String, + capacity: Int, + isHaveTv: Boolean, + electricSocketCount: Int, + roomOccupancy: String, + backgroundColor: Color +) { + Surface( + modifier = Modifier.background(color = backgroundColor).fillMaxWidth(), + color = backgroundColor + ) { + Column(modifier = modifier) { + Text( + text = name, + color = Color(0xFFFAFAFA), + fontSize = 60.sp + ) + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = roomOccupancy, + color = Color(0xFFFAFAFA), + fontSize = 27.sp + ) + Spacer(modifier = Modifier.height(25.dp)) + Row(modifier = Modifier.padding(horizontal = 10.dp)) { + val spaceBetweenProperty = 40.dp + RoomPropertyComponent(image = MainRes.image.quantity, text = "$capacity") + if (isHaveTv) { + Spacer(modifier = Modifier.width(spaceBetweenProperty)) + RoomPropertyComponent( + image = MainRes.image.tv, + text = MainRes.string.tv_property + ) + } + //NOTE(Maksim Mishenko): designers have not fully defined all the properties, a condition will appear in if + //TODO(Maksim Mishenko): replace condition in if + if (true) { + Spacer(modifier = Modifier.width(spaceBetweenProperty)) + RoomPropertyComponent( + image = MainRes.image.usb, + text = MainRes.string.usb_property + ) + } + if (electricSocketCount > 0) { + Spacer(modifier = Modifier.width(spaceBetweenProperty)) + RoomPropertyComponent( + image = MainRes.image.power_socket, + text = "$electricSocketCount ${ + getCorrectDeclension( + number = electricSocketCount, + nominativeCase = MainRes.string.electric_socket_property_nominative, + genitive = MainRes.string.electric_socket_property_genitive, + genitivePlural = MainRes.string.electric_socket_property_plural + ) + }" + ) + } + } + Spacer(modifier = Modifier.height(20.dp)) + } + } +} + +@Composable +fun RoomPropertyComponent(image: Image, text: String) { + Row( + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = Modifier, + painter = painterResource(image), + contentDescription = null + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = text, color = Color(0xFFFAFAFA), fontSize = 16.sp) + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/DateTimeComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/DateTimeComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..d0a2fc63ea011c96e26c87ff4e43a2fe27512620 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/DateTimeComponent.kt @@ -0,0 +1,44 @@ +package band.effective.office.tablet.ui.mainScreen.roomInfoComponents + +import android.os.Build +import android.widget.TextClock +import androidx.annotation.RequiresApi +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView + +@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) +@Composable +fun DateTimeComponent(modifier: Modifier = Modifier) { + Row( + modifier = modifier, + verticalAlignment = Alignment.Bottom + ) { + AndroidView( + factory = { context -> + TextClock(context).apply { + format24Hour = "HH:mm" + format12Hour = "hh:mm a" + textSize = 30f + setTextColor(android.graphics.Color.WHITE) + } + } + ) + Spacer(modifier = Modifier.width(10.dp)) + AndroidView( + factory = { context -> + TextClock(context).apply { + format24Hour = "d MMMM, EEEE" + format12Hour = "d MMMM, EEEE" + textSize = 25f + setTextColor(android.graphics.Color.WHITE) + } + } + ) + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/FreeRoomInfoComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/FreeRoomInfoComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..fc11d324f7ffbb5aa1a175bc51361b33759c25b8 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/FreeRoomInfoComponent.kt @@ -0,0 +1,33 @@ +package band.effective.office.tablet.ui.mainScreen.roomInfoComponents + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import band.effective.office.tablet.domain.model.EventInfo +import band.effective.office.tablet.features.roomInfo.MainRes +import band.effective.office.tablet.utils.CalendarStringConverter +import java.util.Calendar + +@Composable +fun FreeRoomInfoComponent( + modifier: Modifier = Modifier, + name: String, + capacity: Int, + isHaveTv: Boolean, + electricSocketCount: Int, + nextEvent: EventInfo? +) { + CommonRoomInfoComponent( + modifier = modifier, + name = name, + capacity = capacity, + isHaveTv = isHaveTv, + electricSocketCount = electricSocketCount, + roomOccupancy = MainRes.string.free_room_occupancy.format( + time = nextEvent?.startTime?.time() ?: "" + ), + backgroundColor = Color(0xFF36C95F) + ) +} + +private fun Calendar.time() = CalendarStringConverter.calendarToString(this, "HH:mm") \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/RoomEventListComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/RoomEventListComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..657dce994fc79dc1fcced5feb223f1f11f577cab --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/RoomEventListComponent.kt @@ -0,0 +1,96 @@ +package band.effective.office.tablet.ui.mainScreen.roomInfoComponents + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.domain.model.EventInfo +import band.effective.office.tablet.utils.CalendarStringConverter +import java.util.Calendar + +@Composable +fun RoomEventListComponent(modifier: Modifier = Modifier, eventsList: List) { + Column(modifier = modifier) { + Text( + text = "Занятое время", + fontSize = 17.sp, + color = Color(0xFF808080) + ) + Row { + val lazyListState: LazyListState = rememberLazyListState() + LazyColumn( + modifier = Modifier.fillMaxWidth().simpleVerticalScrollbar(lazyListState), + state = lazyListState + ) { + items(eventsList) { event -> + Spacer(modifier = Modifier.height(30.dp)) + Row { + Text( + text = "${event.startTime.time()} - ${event.finishTime.time()}", + fontSize = 18.sp, + color = Color(0xFFFAFAFA) + ) + Text( + text = " · ${event.organizer}", + fontSize = 18.sp, + color = Color(0xFF808080) + ) + } + } + } + } + + } +} + +private fun Calendar.time() = CalendarStringConverter.calendarToString(this, "HH:mm") + +//NOTE(Maksim Mishenko): scrollBar: https://stackoverflow.com/questions/66341823/jetpack-compose-scrollbars +//drawRoundRect: https://semicolonspace.com/jetpack-compose-canvas-drawroundrect/ +@Composable +fun Modifier.simpleVerticalScrollbar( + state: LazyListState, + width: Dp = 8.dp +): Modifier { + return drawWithContent { + drawContent() + + val firstVisibleElementIndex = state.layoutInfo.visibleItemsInfo.firstOrNull()?.index + + val elementHeight = this.size.height / state.layoutInfo.totalItemsCount + val scrollbarOffsetY = (firstVisibleElementIndex ?: 0) * elementHeight + val scrollbarHeight = state.layoutInfo.visibleItemsInfo.size * elementHeight + val cornerRadius = CornerRadius(x = 36.dp.toPx(), y = 36.dp.toPx()) + + if (scrollbarHeight != size.height) { + drawRoundRect( + color = Color(0xFF4D4D4D), + topLeft = Offset(this.size.width - width.toPx(), 0f), + size = Size(width.toPx(), size.height), + cornerRadius = cornerRadius + ) + drawRoundRect( + color = Color(0xFF808080), + topLeft = Offset(this.size.width - width.toPx(), scrollbarOffsetY), + size = Size(width.toPx(), scrollbarHeight), + cornerRadius = cornerRadius + ) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/RoomInfoComponent.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/RoomInfoComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..dacc3459a7e0db3b7c5d74ad866086f043f39603 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/ui/mainScreen/roomInfoComponents/RoomInfoComponent.kt @@ -0,0 +1,49 @@ +package band.effective.office.tablet.ui.mainScreen.roomInfoComponents + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import band.effective.office.tablet.domain.model.RoomInfo + +@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) +@Composable +fun RoomInfoComponent(modifier: Modifier = Modifier, room: RoomInfo) { + val paddings = 30.dp + Column(modifier = modifier) { + DateTimeComponent(modifier = Modifier.padding(paddings)) + when { + room.isFree() -> { + FreeRoomInfoComponent( + modifier = Modifier.padding(paddings), + name = room.name, + capacity = room.capacity, + isHaveTv = room.isHaveTv, + electricSocketCount = room.electricSocketCount, + nextEvent = room.eventList.firstOrNull() + ) + } + + room.isBusy() -> { + BusyRoomInfoComponent( + modifier = Modifier.padding(paddings), + name = room.name, + capacity = room.capacity, + isHaveTv = room.isHaveTv, + electricSocketCount = room.electricSocketCount, + event = room.currentEvent + ) + } + } + Spacer(modifier = Modifier.height(30.dp)) + RoomEventListComponent(modifier = Modifier.padding(paddings), eventsList = room.eventList) + } +} + +private fun band.effective.office.tablet.domain.model.RoomInfo.isFree() = currentEvent == null +private fun band.effective.office.tablet.domain.model.RoomInfo.isBusy() = currentEvent != null \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/CalendarStringConverter.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/CalendarStringConverter.kt new file mode 100644 index 0000000000000000000000000000000000000000..a471be61c4b305ff55ad89ff48f7280ae8876f62 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/CalendarStringConverter.kt @@ -0,0 +1,14 @@ +package band.effective.office.tablet.utils + +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.GregorianCalendar + +object CalendarStringConverter { + fun calendarToString(calendar: Calendar,pattern: String): String = SimpleDateFormat(pattern).format(calendar.time) + fun stringToCalendar(str: String, pattern: String): Calendar { + val calendar = GregorianCalendar() + calendar.time = SimpleDateFormat(pattern).parse(str) + return calendar + } +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/CorrectDeclension.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/CorrectDeclension.kt new file mode 100644 index 0000000000000000000000000000000000000000..cc7ce859772dfe21ef71bca6864bc73378342bd2 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/CorrectDeclension.kt @@ -0,0 +1,11 @@ +package band.effective.office.tablet.utils + +fun getCorrectDeclension( + number: Int, nominativeCase: String, genitive: String, genitivePlural: String +): String = if (number in 10..20) genitivePlural +else when (number % 10) { + 0 -> genitivePlural + 1 -> nominativeCase + 2, 3, 4 -> genitive + else -> genitivePlural +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/DecomposeUtils.kt b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/DecomposeUtils.kt new file mode 100644 index 0000000000000000000000000000000000000000..07d0f0f6fa80e28d146be97e663773aa7bf7e8f8 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/kotlin/band/effective/office/tablet/utils/DecomposeUtils.kt @@ -0,0 +1,24 @@ +package band.effective.office.tablet.utils + +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.essenty.lifecycle.Lifecycle +import com.arkivanov.essenty.lifecycle.doOnDestroy +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel + +//NOTE(Maksim Mishenko): https://gist.github.com/aartikov/a56cc94bb306e05b7b7927353910da08 +fun ComponentContext.componentCoroutineScope(): CoroutineScope { + val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + if (lifecycle.state != Lifecycle.State.DESTROYED) { + lifecycle.doOnDestroy { + scope.cancel() + } + } else { + scope.cancel() + } + + return scope +} \ No newline at end of file diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/images/allert.svg b/tabletApp/features/roomInfo/src/commonMain/libres/images/allert.svg new file mode 100644 index 0000000000000000000000000000000000000000..e7d0fab9cc86869b4cdcd47d0a47ab947e5feb95 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/images/allert.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/images/arrow_to_down.svg b/tabletApp/features/roomInfo/src/commonMain/libres/images/arrow_to_down.svg new file mode 100644 index 0000000000000000000000000000000000000000..4d1b0627b75495d1bbfa9be8946ca94039283ff3 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/images/arrow_to_down.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/images/arrow_to_right.svg b/tabletApp/features/roomInfo/src/commonMain/libres/images/arrow_to_right.svg new file mode 100644 index 0000000000000000000000000000000000000000..3c9c9e414b5958546f4df2d45243a89def87b4ec --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/images/arrow_to_right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/images/calendar.svg b/tabletApp/features/roomInfo/src/commonMain/libres/images/calendar.svg new file mode 100644 index 0000000000000000000000000000000000000000..e342ef2a1f92808e739b3440a15835211e288bf0 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/images/calendar.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/images/power_socket.svg b/tabletApp/features/roomInfo/src/commonMain/libres/images/power_socket.svg new file mode 100644 index 0000000000000000000000000000000000000000..eb6cd537451c8aa061c31010c1a28d740395adde --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/images/power_socket.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/images/quantity.svg b/tabletApp/features/roomInfo/src/commonMain/libres/images/quantity.svg new file mode 100644 index 0000000000000000000000000000000000000000..bf3b341d0f7aaa4f89011444796ae104c3fac70c --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/images/quantity.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/images/tv.svg b/tabletApp/features/roomInfo/src/commonMain/libres/images/tv.svg new file mode 100644 index 0000000000000000000000000000000000000000..6d9873fb30306baf4feab79447ad4288e2982309 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/images/tv.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/images/usb.svg b/tabletApp/features/roomInfo/src/commonMain/libres/images/usb.svg new file mode 100644 index 0000000000000000000000000000000000000000..e66a800f2298cde99734a6ce64e63f3c6adac2f5 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/images/usb.svg @@ -0,0 +1,3 @@ + + + diff --git a/tabletApp/features/roomInfo/src/commonMain/libres/strings/strings_ru.xml b/tabletApp/features/roomInfo/src/commonMain/libres/strings/strings_ru.xml new file mode 100644 index 0000000000000000000000000000000000000000..7889fe304b4bd8ed62aebb2ac19d65e7e7864241 --- /dev/null +++ b/tabletApp/features/roomInfo/src/commonMain/libres/strings/strings_ru.xml @@ -0,0 +1,23 @@ + + + Занята c ${startTime} по ${finishTime} · ${organizer} + Свободна до ${time} + Освободить + TV + USB + Розетка + Розетки + Розеток + Занять + Занять ${roomName} + Время ${startTime} — ${finishTime} занято · ${organizer} + Смотреть свободные переговорки на это время + когда + на сколько + организатор + ${date} c ${time} + -30 + +15 + ${currentLength} мин + Организатор встречи + \ No newline at end of file diff --git a/tabletApp/features/selectRoom/build.gradle.kts b/tabletApp/features/selectRoom/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..56b4f878a22625af431d3578aee43ac143d11f50 --- /dev/null +++ b/tabletApp/features/selectRoom/build.gradle.kts @@ -0,0 +1,65 @@ +plugins { + id(Plugins.AndroidLib.plugin) + id(Plugins.MultiplatformCompose.plugin) + id(Plugins.Kotlin.plugin) + id(Plugins.Parcelize.plugin) + id(Plugins.Libres.plugin) +} + +android { + compileSdk = 33 + sourceSets["main"].apply { + res.srcDirs("src/androidMain/resources") + res.srcDir("build/generated/libres/android/resources") + } +} + +kotlin { + android { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } + + + sourceSets { + val commonMain by getting { + dependencies { + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + + // Decompose + implementation(Dependencies.Decompose.decompose) + implementation(Dependencies.Decompose.extensions) + + //Koin + api(Dependencies.Koin.core) + + //Libres + implementation(Dependencies.Libres.libresCompose) + + implementation(project(":tabletApp:features:core")) + } + } + + val androidMain by getting { + dependencies { + //Koin + api(Dependencies.Koin.android) + } + } + } + + libres { + // https://github.com/Skeptick/libres#setup + generatedClassName = "MainRes" // "Res" by default + generateNamedArguments = true // false by default + baseLocaleLanguageCode = "ru" // "en" by default + camelCaseNamesForAppleFramework = true // false by default + + } + +} diff --git a/tabletApp/features/selectRoom/src/androidMain/AndroidManifest.xml b/tabletApp/features/selectRoom/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..171f5fca8c0c1d9179f9be54b0f07616a20ceca2 --- /dev/null +++ b/tabletApp/features/selectRoom/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tabletApp/features/selectRoom/src/androidMain/kotlin/band/effective/office/tablet/di/initSelectRoomKoin.kt b/tabletApp/features/selectRoom/src/androidMain/kotlin/band/effective/office/tablet/di/initSelectRoomKoin.kt new file mode 100644 index 0000000000000000000000000000000000000000..30bfc57f587ec84ea0948120717168800187a66b --- /dev/null +++ b/tabletApp/features/selectRoom/src/androidMain/kotlin/band/effective/office/tablet/di/initSelectRoomKoin.kt @@ -0,0 +1,8 @@ +package band.effective.office.tablet.di + +import band.effective.office.tablet.di.selectRoomModule +import org.koin.core.context.startKoin + +fun initSelectRoomKoin() = startKoin { + modules(selectRoomModule) +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/di/SelectRoomModule.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/di/SelectRoomModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..a4fda7efeb58effb4110d8cf8425c6fe81657673 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/di/SelectRoomModule.kt @@ -0,0 +1,9 @@ +package band.effective.office.tablet.di + +import org.koin.dsl.module +import band.effective.office.tablet.domain.ISelectRoomInteractor +import band.effective.office.tablet.domain.SelectRoomInteractorImpl + +val selectRoomModule = module{ + single { SelectRoomInteractorImpl(get()) } +} diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/ISelectRoomInteractor.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/ISelectRoomInteractor.kt new file mode 100644 index 0000000000000000000000000000000000000000..16c84fcdd5a6892ba1dc8b42c5257b7394532f48 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/ISelectRoomInteractor.kt @@ -0,0 +1,8 @@ +package band.effective.office.tablet.domain + +import band.effective.office.tablet.domain.model.Booking +import band.effective.office.tablet.domain.model.EventInfo + +interface ISelectRoomInteractor { + suspend fun bookRoom(booking: Booking) +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/MockBooking.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/MockBooking.kt new file mode 100644 index 0000000000000000000000000000000000000000..0139ccf30078821e47c77b7b1880531b415999f4 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/MockBooking.kt @@ -0,0 +1,49 @@ +package band.effective.office.tablet.domain + +import band.effective.office.tablet.domain.model.Booking +import band.effective.office.tablet.domain.model.EventInfo +import java.util.Calendar + +object MockBooking { + val bookingCheckTime15min = band.effective.office.tablet.domain.model.Booking( + nameRoom = "Sirius", + eventInfo = EventInfo( + startTime = setTime(2023, 4, 20, 15, 20), + finishTime = setTime(2023, 4, 20, 15, 35), + organizer = "Ольга Белозёрова" + ) + ) + + val bookingCheckTime1h = band.effective.office.tablet.domain.model.Booking( + nameRoom = "Sirius", + eventInfo = EventInfo( + startTime = setTime(2023, 11, 11, 15, 20), + finishTime = setTime(2023, 11, 11, 16, 20), + organizer = "Ольга Белозёрова" + ) + ) + + val bookingCheckTime1h15min = band.effective.office.tablet.domain.model.Booking( + nameRoom = "Sirius", + eventInfo = EventInfo( + startTime = setTime(2023, 11, 11, 15, 20), + finishTime = setTime(2023, 11, 11, 16, 35), + organizer = "Ольга Белозёрова" + ) + ) + + val bookingCheckOrganizer = band.effective.office.tablet.domain.model.Booking( + nameRoom = "Sirius", + eventInfo = EventInfo( + startTime = setTime(2023, 1, 7, 9, 20), + finishTime = setTime(2023, 1, 7, 11, 35), + organizer = "Абдурахмангаджи Константинопольский" + ) + ) + + private fun setTime(y: Int, m: Int, d: Int, h: Int, min: Int): Calendar { + val currentTime = Calendar.getInstance() + currentTime.set(y, m, d, h, min) + return currentTime + } +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/SelectRoomInteractorImpl.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/SelectRoomInteractorImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..e20e70489233595cf9b7171a8f65cc5ab46e33fd --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/domain/SelectRoomInteractorImpl.kt @@ -0,0 +1,10 @@ +package band.effective.office.tablet.domain + +import band.effective.office.tablet.domain.model.Booking +import band.effective.office.tablet.domain.model.EventInfo +import band.effective.office.tablet.network.ISelectRoomRepository + +class SelectRoomInteractorImpl(private val repository: ISelectRoomRepository): + ISelectRoomInteractor { + override suspend fun bookRoom(booking: Booking) = repository.bookRoom(booking) +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/network/ISelectRoomRepository.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/network/ISelectRoomRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..865247fcd6bac986449b1b8873562993ea85022d --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/network/ISelectRoomRepository.kt @@ -0,0 +1,8 @@ +package band.effective.office.tablet.network + +import band.effective.office.tablet.domain.model.Booking +import band.effective.office.tablet.domain.model.EventInfo + +interface ISelectRoomRepository { + suspend fun bookRoom(booking: Booking) +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/RealSelectRoomComponent.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/RealSelectRoomComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..d9a6c8dba432d1d93007328a775bb2e554cdd3d1 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/RealSelectRoomComponent.kt @@ -0,0 +1,29 @@ +package band.effective.office.tablet.ui.selectRoomScreen + +import com.arkivanov.decompose.ComponentContext +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import band.effective.office.tablet.domain.ISelectRoomInteractor +import band.effective.office.tablet.domain.model.Booking + +class RealSelectRoomComponent( + componentContext: ComponentContext, + val booking: Booking, + private val onCloseRequest: () -> Unit +) : ComponentContext by componentContext, SelectRoomComponent, KoinComponent { + private val interactor: ISelectRoomInteractor by inject() + + private var _state = MutableStateFlow(SelectRoomScreenState.defaultState) + override val state = _state.asStateFlow() + + + override fun bookRoom() { + } + + fun close() { + onCloseRequest() + } + +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomComponent.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..a7e2ba39317877f7dc7642cb7ec4343edb88fb3e --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomComponent.kt @@ -0,0 +1,9 @@ +package band.effective.office.tablet.ui.selectRoomScreen + +import kotlinx.coroutines.flow.StateFlow +import band.effective.office.tablet.domain.model.Booking + +interface SelectRoomComponent { + val state: StateFlow + fun bookRoom() +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomScreen.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomScreen.kt new file mode 100644 index 0000000000000000000000000000000000000000..5967840eba9e26444ea940f8d2f2bd6674859858 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomScreen.kt @@ -0,0 +1,28 @@ +package band.effective.office.tablet.ui.selectRoomScreen + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue + +@Composable +fun SelectRoomScreen(component: RealSelectRoomComponent){ + val state by component.state.collectAsState() + + when{ + state.isData -> { + // SelectRoomView(component) + CheckButton(component) + } + + state.isLoad -> { + /* (Margarita Djinjolia) + not in design */ + } + + state.isError -> { + /* (Margarita Djinjolia) + not in design */ + } + } + +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomScreenState.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomScreenState.kt new file mode 100644 index 0000000000000000000000000000000000000000..9a09fb5fcefecf3601bb9c950f45fd1d0fa03a45 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomScreenState.kt @@ -0,0 +1,18 @@ +package band.effective.office.tablet.ui.selectRoomScreen + +data class SelectRoomScreenState( + val isLoad: Boolean, + val isData: Boolean, + val isError: Boolean, + val error: String +){ + companion object { + val defaultState = + SelectRoomScreenState( + isLoad = false, + isData = true, + isError = false, + error = "" + ) + } +} diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomView.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomView.kt new file mode 100644 index 0000000000000000000000000000000000000000..6003605ef8b23c7149634eaaae86a596a7cd6898 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/SelectRoomView.kt @@ -0,0 +1,136 @@ +package band.effective.office.tablet.ui.selectRoomScreen + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import band.effective.office.tablet.features.selectRoom.MainRes +import band.effective.office.tablet.ui.selectRoomScreen.uiComponents.BookingButtonView +import band.effective.office.tablet.ui.selectRoomScreen.uiComponents.CrossButtonView +import band.effective.office.tablet.ui.selectRoomScreen.uiComponents.DateTimeView +import band.effective.office.tablet.ui.selectRoomScreen.uiComponents.LengthEventView +import band.effective.office.tablet.ui.selectRoomScreen.uiComponents.OrganizerEventView +import band.effective.office.tablet.ui.selectRoomScreen.uiComponents.Title +import band.effective.office.tablet.ui.selectRoomScreen.uiComponents.TitleFieldView + +@Composable +fun CheckButton(component: RealSelectRoomComponent) { + val showDialog = remember { mutableStateOf(false) } + Button( + onClick = { showDialog.value = true } + ) { + Text( + text = "check", + ) + } + + if (showDialog.value) { + SelectRoomView(component) + } +} + +@Composable +fun SelectRoomView( + component: RealSelectRoomComponent +) { + // val showDialog = remember { mutableStateOf(true) } + val modifier = Modifier.background(Color(0xFF3A3736)) + val shape = RoundedCornerShape(16) + + Dialog( + onDismissRequest = { component.close() } + ) + { + Box( + modifier = Modifier + .size(575.dp, 510.dp) + .clip(RoundedCornerShape(5)) + .background(Color(0xFF302D2C)), + ) { + Column( + modifier = Modifier.matchParentSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Spacer(modifier = Modifier.height(30.dp)) + CrossButtonView( + Modifier.width(575.dp), + onDismissRequest = { component.close() } + ) + Title(component) + Spacer(modifier = Modifier.height(24.dp)) + TitleFieldView( + modifier = Modifier.width(415.dp), + title = MainRes.string.whenEvent + ) + Spacer(modifier = Modifier.height(16.dp)) + DateTimeView( + modifier = modifier.height(64.dp).width(415.dp), + shape = shape, + booking = component.booking + ) + Spacer(modifier = Modifier.height(24.dp)) + RowInfoLengthAndOrganizer(modifier, shape, component) + Spacer(modifier = Modifier.height(40.dp)) + BookingButtonView( + modifier = Modifier.height(64.dp).width(415.dp), + color = Color(0xFFEF7234), + shape = RoundedCornerShape(40), + booking = component.booking + ) + Spacer(modifier = Modifier.height(80.dp)) + } + } + } +} + +@Composable +fun RowInfoLengthAndOrganizer( + modifier: Modifier, + shape: RoundedCornerShape, + component: RealSelectRoomComponent +) { + Row { + Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { + TitleFieldView( + modifier = Modifier.width(156.dp), + title = MainRes.string.how_much + ) + LengthEventView( + modifier = modifier.height(64.dp).width(156.dp), + shape = shape, + booking = component.booking + ) + } + Spacer(modifier = Modifier.width(16.dp)) + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { + TitleFieldView( + modifier = Modifier.width(243.dp), + title = MainRes.string.organizer + ) + OrganizerEventView( + modifier = modifier.height(64.dp).width(243.dp), + shape = shape, + booking = component.booking + ) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/BookingButtonView.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/BookingButtonView.kt new file mode 100644 index 0000000000000000000000000000000000000000..b82bbb7bcbf004bd52bcc899b8762d3bbcb280f4 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/BookingButtonView.kt @@ -0,0 +1,47 @@ +package band.effective.office.tablet.ui.selectRoomScreen.uiComponents + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.selectRoom.MainRes +import band.effective.office.tablet.domain.model.Booking +import band.effective.office.tablet.utils.time24 + +@Composable +fun BookingButtonView(modifier: Modifier, color: Color, shape: RoundedCornerShape, booking: Booking) { + val isPressed = remember { mutableStateOf(false) } + val colorButton = if(isPressed.value) Color(0xFFED6521) else color + + Button( + modifier = modifier, + colors = ButtonDefaults.buttonColors(colorButton), + shape = shape, + onClick = { isPressed.value = !isPressed.value} + ) { + Box(contentAlignment = Alignment.Center) + { + Text( + text = MainRes.string.booking_time_button.format( + startTime = booking.eventInfo.startTime.time24(), + finishTime = booking.eventInfo.finishTime.time24() + ), + fontSize = 20.sp, + fontWeight = FontWeight(500), + color = Color(0xFFFAFAFA), + letterSpacing = 0.1.sp, + fontFamily = FontFamily.SansSerif + ) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/CrossButtonView.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/CrossButtonView.kt new file mode 100644 index 0000000000000000000000000000000000000000..ab21a65e096a6a7385943f8263f5eb542f9f735e --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/CrossButtonView.kt @@ -0,0 +1,39 @@ +package band.effective.office.tablet.ui.selectRoomScreen.uiComponents + +import androidx.compose.foundation.background +import androidx.compose.material.Icon +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.IconButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.unit.dp +import band.effective.office.tablet.features.selectRoom.MainRes +import band.effective.office.tablet.domain.model.Booking + +@Composable +fun CrossButtonView(modifier: Modifier, onDismissRequest:() -> Unit) { + + Box( + modifier = modifier.padding(end = 54.dp), + contentAlignment = Alignment.CenterEnd + ) { + IconButton( + onClick = { onDismissRequest() }, + modifier = Modifier + .size(40.dp) + ) { + Icon( + imageVector = ImageVector.vectorResource(MainRes.image.cross), + contentDescription = "Cross", + modifier = Modifier.size(25.dp), + tint = Color(0xFF808080) + ) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/DateTimeView.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/DateTimeView.kt new file mode 100644 index 0000000000000000000000000000000000000000..4cf008c15cbba937434248a7cac628b89a316310 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/DateTimeView.kt @@ -0,0 +1,58 @@ +package band.effective.office.tablet.ui.selectRoomScreen.uiComponents + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.selectRoom.MainRes +import band.effective.office.tablet.domain.model.Booking +import band.effective.office.tablet.utils.date +import band.effective.office.tablet.utils.time24 + +@Composable +fun DateTimeView(modifier: Modifier, shape: RoundedCornerShape, booking: Booking) { + Card( + shape = shape, + backgroundColor = Color(0xFF3A3736) + ) { + Box( + modifier = modifier, + contentAlignment = Alignment.Center + ) { + Row { + Text( + text = booking.eventInfo.startTime.date(), + fontSize = 20.sp, + fontWeight = FontWeight(700), + fontFamily = FontFamily.SansSerif, + color = Color(0xFFA362F8) + ) + + Spacer(modifier = Modifier.width(5.dp)) + + Text( + text = MainRes.string.booking_time.format( + startTime = booking.eventInfo.startTime.time24(), + finishTime = booking.eventInfo.finishTime.time24() + ), + fontSize = 20.sp, + fontWeight = FontWeight(500), + fontFamily = FontFamily.SansSerif, + color = Color(0xFFFAFAFA) + ) + } + } + + } +} diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/LengthEventView.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/LengthEventView.kt new file mode 100644 index 0000000000000000000000000000000000000000..616aaf6fa2a81ab6dea33b34a16cc9e2f2cf5b4e --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/LengthEventView.kt @@ -0,0 +1,53 @@ +package band.effective.office.tablet.ui.selectRoomScreen.uiComponents + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.selectRoom.MainRes +import band.effective.office.tablet.domain.model.Booking +import java.util.Calendar + +@Composable +fun LengthEventView(modifier: Modifier, shape: RoundedCornerShape, booking: Booking) { + + val hours = getLengthEvent(booking.eventInfo.startTime, booking.eventInfo.finishTime) / 60 + val minutes = getLengthEvent(booking.eventInfo.startTime, booking.eventInfo.finishTime) % 60 + val lengthEvent: String = when(hours){ + 0 -> MainRes.string.minutes.format( minutes = minutes.toString()) + else -> MainRes.string.hours_minutes.format( + hours = hours.toString(), + minutes = minutes.toString() + ) + } + + Card( + shape = shape, + backgroundColor = Color(0xFF3A3736) + ) { + Box( + modifier = modifier, + contentAlignment = Alignment.Center + ) { + Text( + text = lengthEvent, + fontSize = 20.sp, + fontWeight = FontWeight(700), + fontFamily = FontFamily.SansSerif, + color = Color(0xFFFAFAFA) + ) + } + } +} + +private fun getLengthEvent(start: Calendar, finish: Calendar) = + (finish.get(Calendar.HOUR) * 60 + finish.get(Calendar.MINUTE)) - + (start.get(Calendar.HOUR) * 60 + start.get(Calendar.MINUTE)) \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/OrganizerEventView.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/OrganizerEventView.kt new file mode 100644 index 0000000000000000000000000000000000000000..a2585dd7832453fef54e867ad9ec93289c668232 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/OrganizerEventView.kt @@ -0,0 +1,36 @@ +package band.effective.office.tablet.ui.selectRoomScreen.uiComponents + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.domain.model.Booking + +@Composable +fun OrganizerEventView(modifier: Modifier, shape: RoundedCornerShape, booking: Booking) { + Card( + shape = shape, + backgroundColor = Color(0xFF3A3736)) { + Box( + modifier = modifier, + contentAlignment = Alignment.Center) { + Text( + text = booking.eventInfo.organizer, + fontWeight = FontWeight(700), + fontSize = 20.sp, + fontFamily = FontFamily.SansSerif, + color = Color(0xFFFAFAFA), + textAlign = TextAlign.Center + ) + } + } +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/TitleFieldView.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/TitleFieldView.kt new file mode 100644 index 0000000000000000000000000000000000000000..7a22a571eb4fe0d81ca3a2028879033e9ba91540 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/TitleFieldView.kt @@ -0,0 +1,29 @@ +package band.effective.office.tablet.ui.selectRoomScreen.uiComponents + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun TitleFieldView(modifier: Modifier, title: String) { + Box( + modifier = modifier.padding(0.dp), + contentAlignment = Alignment.CenterStart + ) { + Text( + text = title, + fontSize = 16.sp, + fontWeight = FontWeight(500), + fontFamily = FontFamily.SansSerif, + color = Color(0xFF808080) + ) + } +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/TitleModal.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/TitleModal.kt new file mode 100644 index 0000000000000000000000000000000000000000..a9aa93da9e9b4ca52b48a32444bc3be9c4bad47a --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/ui/selectRoomScreen/uiComponents/TitleModal.kt @@ -0,0 +1,29 @@ +package band.effective.office.tablet.ui.selectRoomScreen.uiComponents + +import androidx.compose.foundation.layout.width +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.tablet.features.selectRoom.MainRes +import band.effective.office.tablet.ui.selectRoomScreen.RealSelectRoomComponent + +@Composable +fun Title(component: RealSelectRoomComponent){ + Text( + modifier = Modifier.width(415.dp), + text = MainRes.string.title_booking_dialog.format( + nameRoom = component.booking.nameRoom + ), + fontSize = 28.sp, + fontWeight = FontWeight(500), + fontFamily = FontFamily.SansSerif, + color = Color(0xFFFAFAFA), + textAlign = TextAlign.Center + ) +} \ No newline at end of file diff --git a/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/utils/ConvertCalendarToTime.kt b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/utils/ConvertCalendarToTime.kt new file mode 100644 index 0000000000000000000000000000000000000000..22157576183a85d0c8c7d92654ff8077335bb558 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/kotlin/band/effective/office/tablet/utils/ConvertCalendarToTime.kt @@ -0,0 +1,10 @@ +package band.effective.office.tablet.utils + +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale + +fun Calendar.date() = "${this.get(Calendar.DAY_OF_MONTH)} " + + SimpleDateFormat("MMMM", Locale("ru")).format(this.time) + +fun Calendar.time24() = SimpleDateFormat("HH:mm", Locale("ru")).format(this.time) diff --git a/tabletApp/features/selectRoom/src/commonMain/libres/images/cross.svg b/tabletApp/features/selectRoom/src/commonMain/libres/images/cross.svg new file mode 100644 index 0000000000000000000000000000000000000000..626d0499e70a23fa6440e54a072c50c4d66471aa --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/libres/images/cross.svg @@ -0,0 +1,3 @@ + + + diff --git a/tabletApp/features/selectRoom/src/commonMain/libres/strings/strings_ru.xml b/tabletApp/features/selectRoom/src/commonMain/libres/strings/strings_ru.xml new file mode 100644 index 0000000000000000000000000000000000000000..281a0ebf051cc5eed6a218ffe3de99a262c7a5f3 --- /dev/null +++ b/tabletApp/features/selectRoom/src/commonMain/libres/strings/strings_ru.xml @@ -0,0 +1,11 @@ + + + Занять c ${startTime} до ${finishTime} + с ${startTime} до ${finishTime} + Занять ${nameRoom}? + когда + на сколько + организатор + ${minutes} мин + ${hours}ч ${minutes}мин + \ No newline at end of file diff --git a/tabletApp/src/androidMain/AndroidManifest.xml b/tabletApp/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..20603a61d10ae30c603a1e942b2044f38baefa80 --- /dev/null +++ b/tabletApp/src/androidMain/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/tabletApp/src/androidMain/kotlin/band/effective/office/tablet/MainActivity.kt b/tabletApp/src/androidMain/kotlin/band/effective/office/tablet/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..d8c764c8307d6436bd57eda21f41d98ba5752eae --- /dev/null +++ b/tabletApp/src/androidMain/kotlin/band/effective/office/tablet/MainActivity.kt @@ -0,0 +1,20 @@ +package band.effective.office.tablet + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.activity.compose.setContent +import band.effective.office.tablet.di.initRoomInfoKoin +import com.arkivanov.decompose.defaultComponentContext +import band.effective.office.tablet.di.initSelectRoomKoin +import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory +import band.effective.office.tablet.di.initSelectRoomKoin + +class MainActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + initRoomInfoKoin() + setContent { + App(defaultComponentContext(),DefaultStoreFactory()) + } + } +} \ No newline at end of file diff --git a/tabletApp/src/androidMain/kotlin/band/effective/office/tablet/platform.kt b/tabletApp/src/androidMain/kotlin/band/effective/office/tablet/platform.kt new file mode 100644 index 0000000000000000000000000000000000000000..ed60478bec80b9320746dceeda859ef62c6db1e4 --- /dev/null +++ b/tabletApp/src/androidMain/kotlin/band/effective/office/tablet/platform.kt @@ -0,0 +1,5 @@ +package band.effective.office.tablet + +actual fun getPlatformName(): String { + return "Android" +} \ No newline at end of file diff --git a/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/App.kt b/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/App.kt new file mode 100644 index 0000000000000000000000000000000000000000..8d9baa50552a51674544d4d5238f7d18df4db4d5 --- /dev/null +++ b/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/App.kt @@ -0,0 +1,16 @@ +package band.effective.office.tablet + +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import band.effective.office.tablet.ui.root.Root +import band.effective.office.tablet.ui.root.RootComponent +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.mvikotlin.core.store.StoreFactory + +@Composable +fun App(componentContext: ComponentContext, storeFactory: StoreFactory) { + val rootComponent = RootComponent(componentContext, storeFactory) + MaterialTheme { + Root(rootComponent) + } +} diff --git a/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/platform.kt b/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/platform.kt new file mode 100644 index 0000000000000000000000000000000000000000..7d5c60662f432eaf965650a07d074a72b134405b --- /dev/null +++ b/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/platform.kt @@ -0,0 +1,3 @@ +package band.effective.office.tablet + +expect fun getPlatformName(): String \ No newline at end of file diff --git a/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/ui/root/Root.kt b/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/ui/root/Root.kt new file mode 100644 index 0000000000000000000000000000000000000000..3faad3de80cf5dacad05100af87d2252e52bb211 --- /dev/null +++ b/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/ui/root/Root.kt @@ -0,0 +1,18 @@ +package band.effective.office.tablet.ui.root + +import androidx.compose.runtime.Composable +import band.effective.office.tablet.ui.freeNegotiationsScreen.FreeNegotiationsScreen +import band.effective.office.tablet.ui.mainScreen.mainScreen.MainScreen +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children + +@Composable +fun Root(component: RootComponent) { + Children( + stack = component.childStack + ) { child -> + when (val instance = child.instance) { + is RootComponent.Child.MainChild -> MainScreen(instance.component) + is RootComponent.Child.SelectRoomChild -> FreeNegotiationsScreen(instance.component) + } + } +} \ No newline at end of file diff --git a/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/ui/root/RootComponent.kt b/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/ui/root/RootComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..3c94f4546d2ba87589c0286622ee4b0f08364c5f --- /dev/null +++ b/tabletApp/src/commonMain/kotlin/band/effective/office/tablet/ui/root/RootComponent.kt @@ -0,0 +1,60 @@ +package band.effective.office.tablet.ui.root + +import band.effective.office.tablet.ui.freeNegotiationsScreen.FreeNegotiationsComponent +import band.effective.office.tablet.ui.mainScreen.mainScreen.MainComponent +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.childStack +import com.arkivanov.decompose.router.stack.push +import com.arkivanov.essenty.parcelable.Parcelable +import com.arkivanov.mvikotlin.core.store.StoreFactory +import kotlinx.android.parcel.Parcelize + +class RootComponent(componentContext: ComponentContext, private val storeFactory: StoreFactory) : + ComponentContext by componentContext { + + private val navigation = StackNavigation() + + val childStack = childStack( + source = navigation, + initialConfiguration = Config.Main, + handleBackButton = true, + childFactory = ::createChild + ) + + private fun createChild( + config: Config, + componentContext: ComponentContext + ): Child = when (config) { + + is Config.Main -> { + Child.MainChild( + MainComponent( + componentContext = componentContext, + OnSelectOtherRoomRequest = { + navigation.push(Config.SelectRoom) + }, + storeFactory = storeFactory + ) + ) + } + + is Config.SelectRoom -> { + Child.SelectRoomChild(FreeNegotiationsComponent(componentContext)) + } + } + + sealed class Child { + data class SelectRoomChild(val component: FreeNegotiationsComponent) : Child() + data class MainChild(val component: MainComponent) : Child() + } + + sealed class Config : Parcelable { + + @Parcelize + object SelectRoom : Config() + + @Parcelize + object Main : Config() + } +} \ No newline at end of file