diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/components/EffectiveButton.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/components/EffectiveButton.kt index af55640e46a98d9124ed6b4e3eb837dfe87b10bd..097fe93bc6968a044a363cff4c82318f235a3f2a 100644 --- a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/components/EffectiveButton.kt +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/components/EffectiveButton.kt @@ -31,8 +31,7 @@ fun EffectiveButton( ) { Text( text = buttonText, - fontFamily = MaterialTheme.typography.button.fontFamily, - fontSize = 15.sp, + style = MaterialTheme.typography.button, modifier = Modifier.padding(vertical = 10.dp) ) } diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/booking/BookingComponent.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/booking/BookingComponent.kt index f38f26a5eb910fcd92c45af27183a71110ea823f..aa9b636dcc504938474865a693a6974f6cb4ab33 100644 --- a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/booking/BookingComponent.kt +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/booking/BookingComponent.kt @@ -1,15 +1,7 @@ package band.effective.office.elevator.ui.booking -import band.effective.office.elevator.ui.profile.store.ProfileStore -import band.effective.office.elevator.ui.profile.store.ProfileStoreFactory import com.arkivanov.decompose.ComponentContext -import com.arkivanov.mvikotlin.core.instancekeeper.getStore import com.arkivanov.mvikotlin.core.store.StoreFactory -import com.arkivanov.mvikotlin.extensions.coroutines.labels -import com.arkivanov.mvikotlin.extensions.coroutines.stateFlow -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.StateFlow class BookingComponent( componentContext: ComponentContext, diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/content/Content.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/content/Content.kt index 4893f6ccb0dec43e60798094a9da75a66ce2654e..b7cefee2f3b10571a749b251e70ed06d6aee15ed 100644 --- a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/content/Content.kt +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/content/Content.kt @@ -4,14 +4,12 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding import androidx.compose.material.BottomNavigation -import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import band.effective.office.elevator.components.TabNavigationItem -import band.effective.office.elevator.lightGray import band.effective.office.elevator.navigation.BookingTab import band.effective.office.elevator.navigation.EmployeesTab import band.effective.office.elevator.navigation.MainTab @@ -19,7 +17,8 @@ import band.effective.office.elevator.navigation.ProfileTab import band.effective.office.elevator.ui.booking.BookingScreen import band.effective.office.elevator.ui.employee.EmployeeScreen import band.effective.office.elevator.ui.main.MainScreen -import band.effective.office.elevator.ui.profile.ProfileScreen +import band.effective.office.elevator.ui.profile.Profile +import band.effective.office.elevator.ui.profile.mainProfile.ProfileScreen import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.Direction import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.StackAnimation @@ -28,6 +27,8 @@ import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.isEn import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.slide import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.stackAnimation import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState +import com.arkivanov.decompose.router.children.children +import com.arkivanov.decompose.router.stack.childStack @Composable fun Content (component: ContentComponent) { @@ -44,7 +45,7 @@ fun Content (component: ContentComponent) { ) { when (val child = it.instance) { is ContentComponent.Child.Main -> MainScreen(child.component) - is ContentComponent.Child.Profile -> ProfileScreen(child.component) + is ContentComponent.Child.Profile -> Profile(child.component) is ContentComponent.Child.Booking -> BookingScreen(child.component) is ContentComponent.Child.Employee -> EmployeeScreen(child.component) } diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/content/ContentComponent.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/content/ContentComponent.kt index 9ed96e6596051094edf9032060d193ff34b6c6d1..8286002775123e0c4e79b4e26fa3bfddf0299424 100644 --- a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/content/ContentComponent.kt +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/content/ContentComponent.kt @@ -35,7 +35,7 @@ class ContentComponent( ProfileComponent( componentContext, storeFactory, - ::profileOutput + openAuthorizationFlow ) ) is Config.Booking -> Child.Booking(BookingComponent(componentContext, storeFactory)) @@ -51,11 +51,6 @@ class ContentComponent( } } - private fun profileOutput(output: ProfileComponent.Output) { - when (output) { - ProfileComponent.Output.OpenAuthorizationFlow -> openAuthorizationFlow() - } - } sealed class Child { class Main(val component: MainComponent) : Child() diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/Profile.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/Profile.kt new file mode 100644 index 0000000000000000000000000000000000000000..748761703606d788ff8b9019c2ae1c073d2f7142 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/Profile.kt @@ -0,0 +1,23 @@ +package band.effective.office.elevator.ui.profile + +import androidx.compose.runtime.Composable +import band.effective.office.elevator.ui.profile.editProfile.ProfileEditScreen +import band.effective.office.elevator.ui.profile.mainProfile.ProfileScreen +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.plus +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.scale +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.stackAnimation + +@Composable +fun Profile (component: ProfileComponent){ + Children( + stack = component.childStack, + animation = stackAnimation(fade() + scale()), + ){ + when(val child = it.instance){ + is ProfileComponent.Child.MainProfileChild -> ProfileScreen(child.component) + is ProfileComponent.Child.EditProfileChild -> ProfileEditScreen(child.component) + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/ProfileComponent.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/ProfileComponent.kt index 31371be75c646226ff8c994c3ebdb77003fd6ea3..12a2afcabff14295cc37623a87f19e1dfc5cbfab 100644 --- a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/ProfileComponent.kt +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/ProfileComponent.kt @@ -1,44 +1,85 @@ package band.effective.office.elevator.ui.profile -import band.effective.office.elevator.ui.profile.store.ProfileStore -import band.effective.office.elevator.ui.profile.store.ProfileStoreFactory +import band.effective.office.elevator.ui.profile.editProfile.ProfileEditComponent +import band.effective.office.elevator.ui.profile.mainProfile.MainProfileComponent +import band.effective.office.elevator.ui.profile.mainProfile.store.ProfileStore +import band.effective.office.elevator.ui.profile.mainProfile.store.ProfileStoreFactory import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.router.stack.ChildStack +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.bringToFront +import com.arkivanov.decompose.router.stack.childStack +import com.arkivanov.decompose.router.stack.replaceAll +import com.arkivanov.decompose.value.Value +import com.arkivanov.essenty.parcelable.Parcelable +import com.arkivanov.essenty.parcelable.Parcelize import com.arkivanov.mvikotlin.core.instancekeeper.getStore import com.arkivanov.mvikotlin.core.store.StoreFactory import com.arkivanov.mvikotlin.extensions.coroutines.labels import com.arkivanov.mvikotlin.extensions.coroutines.stateFlow +import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow class ProfileComponent( componentContext: ComponentContext, - storeFactory: StoreFactory, - private val output: (Output) -> Unit -) : + private val storeFactory: StoreFactory, + private val openAuthorizationFlow: () -> Unit) : ComponentContext by componentContext { - private val profileStore = instanceKeeper.getStore { - ProfileStoreFactory( - storeFactory = storeFactory - ).create() - } + private val navigation = StackNavigation() + + private val stack = childStack( + source = navigation, + initialStack = { listOf(Config.MainProfile) }, + childFactory = ::child, + handleBackButton = true + ) - @OptIn(ExperimentalCoroutinesApi::class) - val user: StateFlow = profileStore.stateFlow + val childStack: Value> = stack - val label: Flow = profileStore.labels + private fun child(config: Config, componentContext: ComponentContext):Child = + when(config){ + is Config.MainProfile -> Child.MainProfileChild( + MainProfileComponent( + componentContext, + storeFactory, + ::mainProfileOutput, + ) + ) + is Config.EditProfile -> Child.EditProfileChild( + ProfileEditComponent( + componentContext, + storeFactory, + ::editProfileOutput, + ) + ) + } - fun onEvent(event: ProfileStore.Intent) { - profileStore.accept(event) + private fun editProfileOutput(output: ProfileEditComponent.Output) { + when(output){ + ProfileEditComponent.Output.OpenProfileFlow -> navigation.replaceAll(Config.MainProfile) + } } - fun onOutput(output: Output) { - output(output) + private fun mainProfileOutput(output: MainProfileComponent.Output) { + when(output){ + MainProfileComponent.Output.OpenAuthorizationFlow -> openAuthorizationFlow() + MainProfileComponent.Output.OpenEditProfile -> navigation.bringToFront(Config.EditProfile) + } } - sealed interface Output { - object OpenAuthorizationFlow : Output + sealed class Child{ + class MainProfileChild(val component: MainProfileComponent) : Child() + class EditProfileChild(val component: ProfileEditComponent): Child() } + sealed class Config: Parcelable{ + @Parcelize + object MainProfile: Config() + + @Parcelize + object EditProfile: Config() + } } diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/ProfileEditComponent.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/ProfileEditComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..b346312b81b5b3d932e8cae98129a2478483ebd5 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/ProfileEditComponent.kt @@ -0,0 +1,41 @@ +package band.effective.office.elevator.ui.profile.editProfile + +import band.effective.office.elevator.ui.profile.editProfile.store.ProfileEditStore +import band.effective.office.elevator.ui.profile.editProfile.store.ProfileEditStoreFactory +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.mvikotlin.core.instancekeeper.getStore +import com.arkivanov.mvikotlin.core.store.StoreFactory +import com.arkivanov.mvikotlin.core.utils.ExperimentalMviKotlinApi +import com.arkivanov.mvikotlin.extensions.coroutines.labels +import com.arkivanov.mvikotlin.extensions.coroutines.stateFlow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow + +class ProfileEditComponent ( + componentContext: ComponentContext, + storeFactory: StoreFactory, + private val output: (Output) -> Unit + ) : ComponentContext by componentContext { + + private val profileEditStore = instanceKeeper.getStore { + ProfileEditStoreFactory( + storeFactory = storeFactory + ).create() + } + + @OptIn(ExperimentalMviKotlinApi::class) + val user: StateFlow = profileEditStore.stateFlow + + val label: Flow = profileEditStore.labels + + fun onEvent(event:ProfileEditStore.Intent){ + profileEditStore.accept(event) + } + fun onOutput(output: Output){ + output(output) + } + + sealed interface Output { + object OpenProfileFlow:Output + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/ProfileEditScreen.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/ProfileEditScreen.kt new file mode 100644 index 0000000000000000000000000000000000000000..150afdcfa936a63a46220507943961c77fadd308 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/ProfileEditScreen.kt @@ -0,0 +1,204 @@ +package band.effective.office.elevator.ui.profile.editProfile + +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.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.material.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import band.effective.office.elevator.MainRes +import band.effective.office.elevator.components.EffectiveButton +import band.effective.office.elevator.ui.profile.editProfile.store.ProfileEditStore +import dev.icerock.moko.resources.ImageResource +import dev.icerock.moko.resources.StringResource +import dev.icerock.moko.resources.compose.painterResource +import dev.icerock.moko.resources.compose.stringResource +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +@Composable +fun ProfileEditScreen(component: ProfileEditComponent){ + val user by component.user.collectAsState() + + LaunchedEffect(component){ + component.label.collect{label-> + when(label){ + ProfileEditStore.Label.ReturnedInProfile ->component.onOutput(ProfileEditComponent.Output.OpenProfileFlow) + else-> {} + } + } + } + ProfileEditScreenContent( + userName = user.userName, + post = user.post, + telegram = user.telegram, + phoneNumber = user.phoneNumber + ) { component.onEvent(ProfileEditStore.Intent.BackInProfileClicked) } +} + +@Composable +private fun ProfileEditScreenContent( + userName: String?, + post: String?, + telegram: String?, + phoneNumber: String?, + onReturnToProfile: () -> Unit +) { + Column ( + modifier = Modifier.fillMaxSize().padding(top = 48.dp).padding(horizontal = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top + ){ + ProfileEditHeader(onReturnToProfile) + + var listPrepared by remember { + mutableStateOf(false) + } + + LaunchedEffect(Unit){ + withContext(Dispatchers.Default){ + fieldsList.clear() + prepareFieldsData("Петров Иван","Android-разработчик","petrov","89654561232") + listPrepared = true + } + } + + if(listPrepared){ + LazyColumn(modifier = Modifier.padding(top= 28.dp)){ + items(fieldsList){item-> + FieldsItemStyle(item = item) + } + } + } + Spacer(modifier = Modifier.weight(.1f)) + EffectiveButton( + onClick = {}, + buttonText = stringResource(MainRes.strings.save), + modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp) + ) + } +} + +@Composable +private fun FieldsItemStyle(item:FieldsData){ + var itemText by remember { mutableStateOf(item.value) } + Column( + modifier = Modifier.padding(top = 16.dp).fillMaxWidth() + ) { + Text(stringResource(item.title), modifier = Modifier.padding(bottom = 8.dp), style = TextStyle( + fontSize = 16.sp, + color = Color.Black)) + itemText?.let { it -> + OutlinedTextField( + value = it, + modifier = Modifier.fillMaxWidth(), + onValueChange = {itemText = it}, + shape = RoundedCornerShape(12.dp), + singleLine = true, + textStyle = TextStyle( + fontSize = 16.sp, + + ), + leadingIcon = { + Icon( + painter= painterResource(item.icon), + contentDescription = null, + ) + }, + trailingIcon = { + Icon( + painter = painterResource(MainRes.images.clear_icon), + contentDescription = null, + ) + }, + colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = Color(0x80000000), + leadingIconColor = Color(0x66000000), + trailingIconColor = Color(0x66000000) + ) + ) + } + } +} + +private fun prepareFieldsData(username: String?, post: String?, telegram: String?, phoneNumber: String?) { + + fieldsList.add( + FieldsData( + icon = MainRes.images.person_ic, + title = MainRes.strings.last_name_and_first_name, + value = username, + ) + ) + fieldsList.add( + FieldsData( + icon = MainRes.images.symbols_work, + title = MainRes.strings.post, + value = post, + ) + ) + fieldsList.add( + FieldsData( + icon = MainRes.images.mask_number, + title = MainRes.strings.phone_number, + value = phoneNumber, + ) + ) + fieldsList.add( + FieldsData( + icon = MainRes.images.mask_commercial_at, + title = MainRes.strings.telegram, + value = telegram, + ) + ) +} + +private val fieldsList: ArrayList = ArrayList() //TODO("Added in fun ProfileEditScreenContent") +private data class FieldsData(val title:StringResource,val icon:ImageResource,val value: String?) + +@Composable +fun ProfileEditHeader(onReturnToProfile: () -> Unit) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ){ + IconButton(onClick = onReturnToProfile){ + Icon( + painter = painterResource(MainRes.images.back_button), + contentDescription = null, + tint = Color.Black + ) + } + Text( + text = stringResource(MainRes.strings.profile_data), + style = TextStyle( + fontSize = 20.sp, color = Color.Black, + fontWeight = FontWeight.Bold + ), + modifier = Modifier.padding(start = 16.dp) + ) + } +} diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/store/ProfileEditStore.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/store/ProfileEditStore.kt new file mode 100644 index 0000000000000000000000000000000000000000..cca4d96f6598cc761fad185e15eba35e8006bf6d --- /dev/null +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/store/ProfileEditStore.kt @@ -0,0 +1,22 @@ +package band.effective.office.elevator.ui.profile.editProfile.store + +import com.arkivanov.mvikotlin.core.store.Store + +interface ProfileEditStore : Store{ + sealed interface Intent { + object BackInProfileClicked : Intent + object SaveChangeClicked : Intent + } + + data class User( + val userName: String?, + val post:String?, + val phoneNumber:String?, + val telegram: String? + ) + + sealed interface Label { + object ReturnedInProfile : Label + object SavedChange : Label + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/store/ProfileEditStoreFactory.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/store/ProfileEditStoreFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..c4c073d47e19d297f00391365efb5138ef60bc84 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/editProfile/store/ProfileEditStoreFactory.kt @@ -0,0 +1,83 @@ +package band.effective.office.elevator.ui.profile.editProfile.store + +import com.arkivanov.mvikotlin.core.store.Reducer +import com.arkivanov.mvikotlin.core.store.Store +import band.effective.office.elevator.ui.profile.editProfile.store.ProfileEditStore.* +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 org.koin.core.component.KoinComponent + +internal class ProfileEditStoreFactory( + private val storeFactory: StoreFactory +) : KoinComponent { + @OptIn(ExperimentalMviKotlinApi::class) + fun create(): ProfileEditStore = + object : ProfileEditStore, + Store + by storeFactory.create( + name = "ProfileEditStore", + initialState = User( + userName = null, + telegram = null, + post = null, + phoneNumber = null + ), + bootstrapper = coroutineBootstrapper { + dispatch(Action.FetchUserInfo) + }, + executorFactory = ::ExecutorImpl, + reducer = ReducerImpl + ) {} + + private sealed interface Action { + object FetchUserInfo : Action + } + + private sealed interface Msg { + data class ProfileData(val user: User) : Msg + } + + private inner class ExecutorImpl : + CoroutineExecutor() { + override fun executeIntent( + intent: Intent, + getState: () -> User + ) { + when (intent) { + Intent.BackInProfileClicked -> doReturnProfile() + Intent.SaveChangeClicked -> doSaveChange() + } + } + private fun doSaveChange() { + publish(Label.SavedChange) + } + override fun executeAction(action: Action, getState: () -> User) { + when (action) { + Action.FetchUserInfo -> fetchUserInfo() + } + } + + private fun fetchUserInfo() { + } + + + + private fun doReturnProfile() { + publish(Label.ReturnedInProfile) + } + } + + private object ReducerImpl : Reducer { + override fun User.reduce(message: Msg): User = + when (message) { + is Msg.ProfileData -> User( + userName = null, + telegram = null, + post = null, + phoneNumber = null, + ) + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/MainProfileComponent.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/MainProfileComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..f80e920528d01fbb4e76cccaa57d3e7536eb4b90 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/MainProfileComponent.kt @@ -0,0 +1,41 @@ +package band.effective.office.elevator.ui.profile.mainProfile + +import band.effective.office.elevator.ui.profile.mainProfile.store.ProfileStore +import band.effective.office.elevator.ui.profile.mainProfile.store.ProfileStoreFactory +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.mvikotlin.core.instancekeeper.getStore +import com.arkivanov.mvikotlin.core.store.StoreFactory +import com.arkivanov.mvikotlin.extensions.coroutines.labels +import com.arkivanov.mvikotlin.extensions.coroutines.stateFlow +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow + +class MainProfileComponent( + componentContext: ComponentContext, + storeFactory: StoreFactory, + private val output: (Output) -> Unit) : + ComponentContext by componentContext { + + private val profileStore = instanceKeeper.getStore { + ProfileStoreFactory( + storeFactory = storeFactory + ).create() + } + + @OptIn(ExperimentalCoroutinesApi::class) + val user: StateFlow = profileStore.stateFlow + + val label: Flow = profileStore.labels + fun onEvent(event: ProfileStore.Intent) { + profileStore.accept(event) + } + fun onOutput(output: Output){ + output(output) + } + sealed interface Output { + object OpenAuthorizationFlow : Output + object OpenEditProfile: Output + } + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/ProfileScreen.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/ProfileScreen.kt similarity index 85% rename from composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/ProfileScreen.kt rename to composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/ProfileScreen.kt index 1fa43ab503545c497ee1b9f1abee2427ac010907..acde2cb8b1682586dc67d16ca793f7fa86231a98 100644 --- a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/ProfileScreen.kt +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/ProfileScreen.kt @@ -1,4 +1,4 @@ -package band.effective.office.elevator.ui.profile +package band.effective.office.elevator.ui.profile.mainProfile import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image @@ -9,12 +9,15 @@ 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.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -38,7 +41,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import band.effective.office.elevator.MainRes -import band.effective.office.elevator.ui.profile.store.ProfileStore +import band.effective.office.elevator.ui.profile.mainProfile.store.ProfileStore import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.rememberAsyncImagePainter import dev.icerock.moko.resources.ImageResource @@ -50,13 +53,14 @@ import kotlinx.coroutines.withContext @Composable -fun ProfileScreen(component: ProfileComponent) { +fun ProfileScreen(component: MainProfileComponent) { val user by component.user.collectAsState() - LaunchedEffect(component) { + LaunchedEffect(component){ component.label.collect { label -> - when (label) { - ProfileStore.Label.OnSignedOut -> component.onOutput(ProfileComponent.Output.OpenAuthorizationFlow) + when(label){ + ProfileStore.Label.OnSignedOut -> component.onOutput(MainProfileComponent.Output.OpenAuthorizationFlow) + ProfileStore.Label.OnClickedEdit -> component.onOutput(MainProfileComponent.Output.OpenEditProfile) } } } @@ -67,7 +71,8 @@ fun ProfileScreen(component: ProfileComponent) { post = user.post, telegram = user.telegram, phoneNumber = user.phoneNumber, - onSignOut = { component.onEvent(ProfileStore.Intent.SignOutClicked) } + onSignOut = { component.onEvent(ProfileStore.Intent.SignOutClicked) }, + onEditProfile = {component.onEvent(ProfileStore.Intent.EditProfileClicked)} ) } @@ -78,7 +83,8 @@ internal fun ProfileScreenContent( post: String?, telegram: String?, phoneNumber: String?, - onSignOut: () -> Unit + onSignOut: () -> Unit, + onEditProfile: ()-> Unit ) { Column( modifier = Modifier.fillMaxSize().padding(top = 48.dp), @@ -86,7 +92,7 @@ internal fun ProfileScreenContent( verticalArrangement = Arrangement.Top ) { ProfileHeader(onSignOut) - ProfileInfoAboutUser(imageUrl, username, post) + ProfileInfoAboutUser(imageUrl, username, post, onEditProfile) var listPrepared by remember { mutableStateOf(false) } @@ -103,7 +109,7 @@ internal fun ProfileScreenContent( .fillMaxSize().padding(top = 24.dp) ) { items(optionsList) { item -> - OptionsItemStyle(item = item) + OptionsItemStyle(item = item, onEditProfile) } } } @@ -111,7 +117,7 @@ internal fun ProfileScreenContent( } @Composable -fun ProfileInfoAboutUser(imageUrl: String?, username: String?, post: String?) { +fun ProfileInfoAboutUser(imageUrl: String?, username: String?, post: String?, onEditProfile: ()-> Unit) { imageUrl?.let { url -> val request = remember(url) { ImageRequest { @@ -132,11 +138,15 @@ fun ProfileInfoAboutUser(imageUrl: String?, username: String?, post: String?) { contentDescription = null, ) } - Image( - modifier = Modifier.size(24.dp).align(Alignment.TopEnd), - painter = painterResource(MainRes.images.edit_profile_image), - contentDescription = null, - ) + Button(onClick = onEditProfile, + shape = CircleShape, + modifier = Modifier.size(24.dp).align(Alignment.TopEnd)){ + Image( + painter = painterResource(MainRes.images.edit_profile_image), + contentDescription = null, + contentScale = ContentScale.Fit + ) + } } } username?.let { @@ -199,7 +209,7 @@ private fun ProfileHeader(onSignOut: () -> Unit) { } @Composable -private fun OptionsItemStyle(item: OptionsData) { +private fun OptionsItemStyle(item: OptionsData, onEditProfile: () -> Unit) { Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .padding(horizontal = 16.dp).fillMaxWidth() @@ -227,7 +237,7 @@ private fun OptionsItemStyle(item: OptionsData) { ) ) } - IconButton(onClick = {}) { + IconButton(onClick = onEditProfile) { Icon( painter = painterResource(MainRes.images.next), contentDescription = null, diff --git a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/store/ProfileStore.kt b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/store/ProfileStore.kt similarity index 76% rename from composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/store/ProfileStore.kt rename to composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/store/ProfileStore.kt index 4026f5aa9f0bb25221ac3a323bee4aa84453864b..60f845627d6cf5b4474c3fc21255ff7ab701b29b 100644 --- a/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/store/ProfileStore.kt +++ b/composeApp/src/commonMain/kotlin/band/effective/office/elevator/ui/profile/mainProfile/store/ProfileStore.kt @@ -1,4 +1,4 @@ -package band.effective.office.elevator.ui.profile.store +package band.effective.office.elevator.ui.profile.mainProfile.store import com.arkivanov.mvikotlin.core.store.Store @@ -6,6 +6,7 @@ interface ProfileStore : Store User) { when (intent) { Intent.SignOutClicked -> doSignOut() + Intent.EditProfileClicked -> doTransaction() } } + private fun doTransaction(){ + publish(Label.OnClickedEdit) + } + private fun doSignOut() { signInClient.signOut() publish(Label.OnSignedOut) diff --git a/composeApp/src/commonMain/resources/MR/base/strings_ru.xml b/composeApp/src/commonMain/resources/MR/base/strings_ru.xml index d6161090aa0fce5225af7f4c3423fcafed777cd5..f93703b841d6d6cf9073122ae62c45049cd53984 100644 --- a/composeApp/src/commonMain/resources/MR/base/strings_ru.xml +++ b/composeApp/src/commonMain/resources/MR/base/strings_ru.xml @@ -37,6 +37,13 @@ Выход - Телефон + Телефон Telegram + + + Данные профиля + Фамилия и Имя + Должность + Номер телефона + Сохранить diff --git a/composeApp/src/commonMain/resources/MR/en/strings_en.xml b/composeApp/src/commonMain/resources/MR/en/strings_en.xml index 12d489c96acfd2c37f65629069e2bc631e19f430..66da5a8f8cc55f7667ef549c68d40e939603dd1e 100644 --- a/composeApp/src/commonMain/resources/MR/en/strings_en.xml +++ b/composeApp/src/commonMain/resources/MR/en/strings_en.xml @@ -30,6 +30,13 @@ Exit - Phone number + Phone number Telegram + + + Profile Data + Last name and First name + Post + Telephone number + Save diff --git a/composeApp/src/commonMain/resources/MR/images/back_button.svg b/composeApp/src/commonMain/resources/MR/images/back_button.svg new file mode 100644 index 0000000000000000000000000000000000000000..5a163615d520c64aeaeedadf240709be4dd69da7 --- /dev/null +++ b/composeApp/src/commonMain/resources/MR/images/back_button.svg @@ -0,0 +1,3 @@ + + + diff --git a/composeApp/src/commonMain/resources/MR/images/clear_icon.svg b/composeApp/src/commonMain/resources/MR/images/clear_icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..3ec11b40d4b5c3740478b2629c41b10660c52679 --- /dev/null +++ b/composeApp/src/commonMain/resources/MR/images/clear_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/composeApp/src/commonMain/resources/MR/images/edit_profile_image.svg b/composeApp/src/commonMain/resources/MR/images/edit_profile_image.svg index 004e5775ee969c08f0b34db3cd3ec9856267a5fb..3707765ca033133867d89f07318f167e1a393114 100644 --- a/composeApp/src/commonMain/resources/MR/images/edit_profile_image.svg +++ b/composeApp/src/commonMain/resources/MR/images/edit_profile_image.svg @@ -1,11 +1,3 @@ - - - - - - - - - - + + diff --git a/composeApp/src/commonMain/resources/MR/images/mask_commercial_at.svg b/composeApp/src/commonMain/resources/MR/images/mask_commercial_at.svg new file mode 100644 index 0000000000000000000000000000000000000000..80f75b8e0757b9c17e294ef55b386af109fefb0d --- /dev/null +++ b/composeApp/src/commonMain/resources/MR/images/mask_commercial_at.svg @@ -0,0 +1,3 @@ + + + diff --git a/composeApp/src/commonMain/resources/MR/images/mask_number.svg b/composeApp/src/commonMain/resources/MR/images/mask_number.svg new file mode 100644 index 0000000000000000000000000000000000000000..bc9ecf52b1dc4ebb23831db5cc9928b91f601b69 --- /dev/null +++ b/composeApp/src/commonMain/resources/MR/images/mask_number.svg @@ -0,0 +1,3 @@ + + + diff --git a/composeApp/src/commonMain/resources/MR/images/person_icon.svg b/composeApp/src/commonMain/resources/MR/images/person_icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..f0525e13c25a7c15bf5040d0b8429edc4be82ce5 --- /dev/null +++ b/composeApp/src/commonMain/resources/MR/images/person_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/composeApp/src/commonMain/resources/MR/images/symbols_work.svg b/composeApp/src/commonMain/resources/MR/images/symbols_work.svg new file mode 100644 index 0000000000000000000000000000000000000000..4264454ba7bf89129b85debbe147a34936d3e496 --- /dev/null +++ b/composeApp/src/commonMain/resources/MR/images/symbols_work.svg @@ -0,0 +1,3 @@ + + +