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