From a3279de8ab188655c9ca67c871fc2a8f17d39b10 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Wed, 10 Jul 2024 00:33:29 +0900 Subject: [PATCH] =?UTF-8?q?=EC=82=AC=EC=9E=A5=EB=8B=98=20=EB=A9=94?= =?UTF-8?q?=EB=89=B4=EA=B0=80=EA=B2=A9=20=EB=93=B1=EB=A1=9D=20UI=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessMainActivity.kt | 5 +- .../OperatingTimeSettingScreen.kt | 4 +- .../navigator/RegisterMenuNavigator.kt | 34 ++ .../navigator/RegisterMenuRoute.kt | 6 + .../registermenu/InsertMenuScreen.kt | 565 ++++++++++++++++++ .../registermenu/RegisterMenuSideEffect.kt | 4 + .../registermenu/RegisterMenuState.kt | 18 + .../registermenu/RegisterMenuViewModel.kt | 132 ++++ .../feature/textfield/BorderTextField.kt | 50 ++ .../in/koreatech/business/ui/theme/Color.kt | 1 + .../main/res/drawable/ic_add_menu_image.xml | 26 + .../main/res/drawable/ic_white_arrow_back.xml | 9 + core/src/main/res/values/strings.xml | 19 +- .../in/koreatech/koin/data/api/StoreApi.kt | 4 + .../koreatech/koin/data/mapper/StoreMapper.kt | 9 + .../data/repository/StoreRepositoryImpl.kt | 6 +- .../store/StoreMenuCategoryResponse.kt | 13 + .../source/remote/StoreRemoteDataSource.kt | 4 + .../domain/model/owner/StoreMenuCategory.kt | 6 + .../koin/domain/repository/StoreRepository.kt | 3 + .../business/menu/GetMenuCategoryUseCase.kt | 15 + 21 files changed, 927 insertions(+), 6 deletions(-) create mode 100644 business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/navigator/RegisterMenuNavigator.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/navigator/RegisterMenuRoute.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/InsertMenuScreen.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuSideEffect.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuState.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuViewModel.kt create mode 100644 business/src/main/java/in/koreatech/business/feature/textfield/BorderTextField.kt create mode 100644 core/src/main/res/drawable/ic_add_menu_image.xml create mode 100644 core/src/main/res/drawable/ic_white_arrow_back.xml create mode 100644 data/src/main/java/in/koreatech/koin/data/response/store/StoreMenuCategoryResponse.kt create mode 100644 domain/src/main/java/in/koreatech/koin/domain/model/owner/StoreMenuCategory.kt create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/business/menu/GetMenuCategoryUseCase.kt diff --git a/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt b/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt index 0881d75cb..80afa0415 100644 --- a/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt +++ b/business/src/main/java/in/koreatech/business/BusinessMainActivity.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import dagger.hilt.android.AndroidEntryPoint import `in`.koreatech.business.feature.store.MyStoreDetailScreen +import `in`.koreatech.business.feature.storemenu.registermenu.navigator.RegisterMenuNavigator import `in`.koreatech.business.ui.theme.KOIN_ANDROIDTheme @AndroidEntryPoint @@ -25,8 +26,8 @@ class BusinessMainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background ) { - // InsertStoreNavigator() - MyStoreDetailScreen(modifier = Modifier.fillMaxSize(),) + //MyStoreDetailScreen(modifier = Modifier.fillMaxSize(),) + RegisterMenuNavigator() } } } diff --git a/business/src/main/java/in/koreatech/business/feature/insertstore/insertdetailinfo/operatingTime/OperatingTimeSettingScreen.kt b/business/src/main/java/in/koreatech/business/feature/insertstore/insertdetailinfo/operatingTime/OperatingTimeSettingScreen.kt index 05534f841..6dea582aa 100644 --- a/business/src/main/java/in/koreatech/business/feature/insertstore/insertdetailinfo/operatingTime/OperatingTimeSettingScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/insertstore/insertdetailinfo/operatingTime/OperatingTimeSettingScreen.kt @@ -328,7 +328,7 @@ fun ShowOpenTimeDialog( onClick = { operatingTimeDialog.closeDialog() }) { - Text(stringResource(id = R.string.neutral)) + Text(stringResource(id = R.string.cancel)) } } ) @@ -387,7 +387,7 @@ fun ShowCloseTimeDialog( onClick = { operatingTimeDialog.closeDialog() }) { - Text(stringResource(id = R.string.neutral)) + Text(stringResource(id = R.string.cancel)) } } ) diff --git a/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/navigator/RegisterMenuNavigator.kt b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/navigator/RegisterMenuNavigator.kt new file mode 100644 index 000000000..d11d9209d --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/navigator/RegisterMenuNavigator.kt @@ -0,0 +1,34 @@ +package `in`.koreatech.business.feature.storemenu.registermenu.navigator + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import `in`.koreatech.business.feature.storemenu.registermenu.registermenu.RegisterMenuScreen +import `in`.koreatech.business.feature.storemenu.registermenu.registermenu.RegisterMenuViewModel + +@Composable +fun RegisterMenuNavigator( + modifier: Modifier = Modifier, + navController: NavHostController = rememberNavController(), + registerMenuViewModel: RegisterMenuViewModel = hiltViewModel() +) { + NavHost( + navController = navController, + startDestination = RegisterMenuRoute.INSERT_MENU.name, + modifier = modifier + ) { + + composable( + route = RegisterMenuRoute.INSERT_MENU.name, + ) { + RegisterMenuScreen( + viewModel = registerMenuViewModel, + onBackPressed = {} + ) + } + } +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/navigator/RegisterMenuRoute.kt b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/navigator/RegisterMenuRoute.kt new file mode 100644 index 000000000..148ab4b16 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/navigator/RegisterMenuRoute.kt @@ -0,0 +1,6 @@ +package `in`.koreatech.business.feature.storemenu.registermenu.navigator + +enum class RegisterMenuRoute { + INSERT_MENU, + CHECK_MENU +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/InsertMenuScreen.kt b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/InsertMenuScreen.kt new file mode 100644 index 000000000..c36748225 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/InsertMenuScreen.kt @@ -0,0 +1,565 @@ +package `in`.koreatech.business.feature.storemenu.registermenu.registermenu + +import android.util.Log +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +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.fillMaxHeight +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.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Divider +import androidx.compose.material.IconButton +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.graphics.RectangleShape +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import `in`.koreatech.business.feature.insertstore.insertdetailinfo.operatingTime.OperatingTimeState +import `in`.koreatech.business.feature.insertstore.selectcategory.CategoryItem +import `in`.koreatech.business.ui.theme.Blue1 +import `in`.koreatech.business.ui.theme.ColorAccent +import `in`.koreatech.business.ui.theme.ColorDisabledButton +import `in`.koreatech.business.ui.theme.ColorMinor +import `in`.koreatech.business.ui.theme.ColorPrimary +import `in`.koreatech.business.ui.theme.ColorSecondary +import `in`.koreatech.business.ui.theme.ColorSecondaryText +import `in`.koreatech.business.ui.theme.ColorTextBackgrond +import `in`.koreatech.business.ui.theme.ColorTransparency +import `in`.koreatech.business.ui.theme.Gray6 +import `in`.koreatech.koin.core.R +import `in`.koreatech.koin.domain.model.owner.StoreMenuCategory +import org.orbitmvi.orbit.compose.collectAsState + + +@Composable +fun RegisterMenuScreen( + modifier: Modifier = Modifier, + onBackPressed: () -> Unit, + viewModel: RegisterMenuViewModel +) { + val state = viewModel.collectAsState().value + + RegisterMenuScreenImpl( + goToSelectCategoryScreen = {} , + onBackPressed = {}, + menuCategory = state.menuCategory, + registerMenuState = state, + menuName = state.menuName, + changeMenuName = { + viewModel.changeMenuName(it) + }, + changeMenuPrice = { + viewModel.changeMenuPrice(it.first, it.second) + }, + onChangeMenuDetail = { + viewModel.changeMenuDetail(it) + }, + menuPrice = state.menuPrice, + addPriceButtonClicked = { + viewModel.addPrice() + }, + onRecommendMenuButtonClicked = { + viewModel.recommendMenuIsClicked() + }, + onMainMenuButtonClicked = { + viewModel.mainMenuIsClicked() + }, + onSetMenuButtonClicked = { + viewModel.setMenuIsClicked() + }, + onSideMenuButtonClicked = { + viewModel.sideMenuIsClicked() + }, + ) +} + +@Composable +fun RegisterMenuScreenImpl( + modifier: Modifier = Modifier, + goToSelectCategoryScreen: () -> Unit, + onBackPressed: () -> Unit, + menuCategory: List = emptyList(), + registerMenuState: RegisterMenuState = RegisterMenuState(), + menuName: String = "", + changeMenuName: (String) -> Unit = {}, + onChangeMenuDetail: (String) -> Unit = {}, + changeMenuPrice: (Pair) -> Unit = {}, + menuPrice: List = emptyList(), + addPriceButtonClicked: () -> Unit = {}, + onRecommendMenuButtonClicked: () -> Unit = {}, + onMainMenuButtonClicked: () -> Unit = {}, + onSetMenuButtonClicked: () -> Unit = {}, + onSideMenuButtonClicked: () -> Unit = {} +) { + Column( + modifier = Modifier.fillMaxSize() + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(62.dp) + .background(ColorPrimary), + ) { + IconButton( + modifier = Modifier + .align(Alignment.CenterStart) + .padding(start = 16.dp) + , + onClick = { /*TODO*/ } + ) { + Image( + painter = painterResource(id = R.drawable.ic_white_arrow_back), + contentDescription = stringResource(R.string.back), + ) + } + Text( + text = stringResource(R.string.menu_add), + modifier = Modifier.align(Alignment.Center), + style = TextStyle(color = Color.White, fontSize = 20.sp), + ) + } + + LazyColumn( + modifier = Modifier.fillMaxSize() + ){ + item{ + DivideOption(16.dp, stringResource(id = R.string.menu_info)) + + Text( + modifier = Modifier.padding(start = 16.dp, top = 16.dp), + text = stringResource(id = R.string.menu_name), + fontSize = 15.sp, + color = ColorPrimary, + fontWeight = FontWeight.Bold + ) + + BorderTextField( + height = 37.dp, + inputString = registerMenuState.menuName, + onStringChange = changeMenuName + ) + + Divider( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = 27.dp) + , + thickness = 1.dp, + color = Gray6 + ) + } + + item{ + Text( + modifier = Modifier.padding(start = 16.dp, top = 16.dp), + text = stringResource(id = R.string.menu_price), + fontSize = 15.sp, + color = ColorPrimary, + fontWeight = FontWeight.Bold + ) + + registerMenuState.menuPrice.forEachIndexed { index, menuName -> + + Row( + modifier = Modifier.fillMaxWidth() + ) { + Box( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = 8.dp) + .border(width = 1.dp, color = ColorMinor) + .height(37.dp), + contentAlignment = Alignment.CenterStart + ) { + BasicTextField( + value = menuName, + onValueChange = { newValue -> + changeMenuPrice(Pair(index, newValue)) + }, + textStyle = TextStyle( + color = Color.Black, + fontSize = 14.sp + ), + modifier = Modifier + .fillMaxWidth() + ) + } + } + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp, start = 16.dp) + .clickable { + addPriceButtonClicked() + } + , + verticalAlignment = Alignment.CenterVertically + + ){ + Image( + painter = painterResource(id = R.drawable.ic_add), + contentDescription = null + ) + + Text( + text = stringResource(id = R.string.add_price), + color = ColorAccent, + fontSize = 13.sp, + fontWeight = FontWeight.Bold + ) + } + + Divider( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = 27.dp) + , + thickness = 1.dp, + color = Gray6 + ) + } + + item{ + Text( + modifier = Modifier.padding(start = 16.dp, top = 16.dp), + text = stringResource(id = R.string.menu_category), + fontSize = 15.sp, + color = ColorPrimary, + fontWeight = FontWeight.Bold + ) + if(registerMenuState.menuCategory.isNotEmpty()) + { + CategoryRadioButtonScreen( + menuCategory = registerMenuState.menuCategory, + onRecommendMenuButtonClicked = onRecommendMenuButtonClicked, + onMainMenuButtonClicked = onMainMenuButtonClicked, + onSetMenuButtonClicked = onSetMenuButtonClicked, + onSideMenuButtonClicked = onSideMenuButtonClicked, + isRecommendMenu = registerMenuState.isRecommendMenu, + isMainMenu = registerMenuState.isMainMenu, + isSetMenu = registerMenuState.isSetMenu, + isSideMenu = registerMenuState.isSideMenu + ) + } + } + + item{ + DivideOption(22.dp, stringResource(id = R.string.menu_detail)) + + Text( + modifier = Modifier.padding(start = 16.dp, top = 16.dp), + text = stringResource(id = R.string.menu_composition), + fontSize = 15.sp, + color = ColorPrimary, + fontWeight = FontWeight.Bold + ) + + Box( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = 8.dp) + .border(width = 1.dp, color = ColorMinor) + .height(105.dp), + contentAlignment = Alignment.CenterStart + ) { + BasicTextField( + value = registerMenuState.description, + onValueChange = onChangeMenuDetail, + textStyle = TextStyle( + color = Color.Black, + fontSize = 14.sp + ), + modifier = Modifier + .fillMaxSize(), + decorationBox = { innerTextField -> + if (registerMenuState.description.isEmpty()) { + Text( + text = stringResource(id = R.string.menu_description_example), + style = TextStyle( + color = Color.Gray, + fontSize = 14.sp + ) + ) + } + innerTextField() + } + ) + } + + Divider( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = 24.dp) + , + thickness = 1.dp, + color = Gray6 + ) + } + + item{ + Row( + modifier = Modifier.padding(start = 16.dp, top = 16.dp) + ){ + Text( + text = stringResource(id = R.string.menu_image), + fontSize = 15.sp, + color = ColorPrimary, + fontWeight = FontWeight.Bold + ) + + Text( + modifier = Modifier.padding(start= 12.dp), + text = stringResource(id = R.string.menu_image_maximum), + fontSize = 15.sp, + color = Gray6, + fontWeight = FontWeight.Bold + ) + } + + LazyRow( + modifier = modifier + .padding(horizontal = 16.dp) + .padding(top = 16.dp) + ){ + itemsIndexed(registerMenuState.imageUriList){ index, item -> + if(item == ""){ + Image( + modifier = Modifier + .size(137.dp) + .padding(bottom = 16.dp) + , + painter = painterResource(id = R.drawable.ic_add_menu_image), + contentDescription = "이미지 삽입" + ) + } + } + } + } + + item{ + Row( + modifier = Modifier.padding(horizontal = 16.dp) + .padding(top = 24.dp, bottom = 52.dp) + .fillMaxWidth() + .height(43.dp) + ){ + Button( + onClick = {}, + shape = RectangleShape, + colors = ButtonDefaults.buttonColors(Color.White), + modifier = modifier + .fillMaxHeight() + .width(93.dp) + .border(1.dp, ColorSecondary), + ) { + Text( + text = stringResource(id = R.string.cancel), + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = ColorSecondary + ) + } + + Spacer(modifier = Modifier.weight(1f)) + + Button( + onClick = {}, + shape = RectangleShape, + colors = ButtonDefaults.buttonColors(ColorPrimary), + modifier = modifier + .height(43.dp) + .width(226.dp) + ) { + Text( + text = stringResource(id = R.string.next), + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ) + } + } + } + } + } +} + +@Composable +fun CategoryRadioButton( + modifier: Modifier = Modifier, + startDp: Dp = 0.dp, + endDp: Dp = 0.dp, + buttonName: String = "", + isClicked: Boolean = false, + onButtonClicked: () ->Unit = {} +) { + Box( + modifier = Modifier + .width(185.dp) + .height(50.dp) + .padding(start = startDp, end = endDp) + .border(width = 0.5.dp, color = if (isClicked) ColorSecondary else Gray6) + .background(color = if (isClicked) ColorSecondary else ColorTransparency) + .clickable { + onButtonClicked() + } + , + contentAlignment = Alignment.Center + ){ + Text( + text = buttonName, + color = if(isClicked) Color.White else Color.Black, + fontWeight = FontWeight.Bold + ) + + } +} + +@Composable +private fun CategoryRadioButtonScreen( + menuCategory: List = emptyList(), + onRecommendMenuButtonClicked: () -> Unit = {}, + onMainMenuButtonClicked: () -> Unit = {}, + onSetMenuButtonClicked: () -> Unit = {}, + onSideMenuButtonClicked: () -> Unit = {}, + isRecommendMenu : Boolean = false, + isMainMenu: Boolean = true, + isSetMenu: Boolean = true, + isSideMenu: Boolean = false +) { + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 16.dp) + .padding(top = 8.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth() + ){ + CategoryRadioButton( + buttonName = menuCategory[0].menuCategoryName, + isClicked = isRecommendMenu, + onButtonClicked = onRecommendMenuButtonClicked + ) + + Spacer(modifier = Modifier.weight(1f)) + + CategoryRadioButton( + buttonName = menuCategory[1].menuCategoryName, + isClicked = isMainMenu, + onButtonClicked = onMainMenuButtonClicked + ) + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp) + ){ + CategoryRadioButton( + buttonName = menuCategory[2].menuCategoryName, + isClicked = isSetMenu, + onButtonClicked = onSetMenuButtonClicked + ) + + Spacer(modifier = Modifier.weight(1f)) + + CategoryRadioButton( + buttonName = menuCategory[3].menuCategoryName, + isClicked = isSideMenu, + onButtonClicked = onSideMenuButtonClicked + ) + } + } +} + +@Composable +fun BorderTextField( + height: Dp = 20.dp, + inputString: String = "", + onStringChange: (String) -> Unit = {}, +){ + Box( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = 8.dp) + .border(width = 1.dp, color = ColorMinor) + .height(height), + contentAlignment = Alignment.CenterStart + ) { + BasicTextField( + value = inputString, + onValueChange = onStringChange, + textStyle = TextStyle( + color = Color.Black, + fontSize = 14.sp + ), + modifier = Modifier + .fillMaxWidth() + ) + } +} + +@Composable +fun DivideOption( + padding: Dp, + optionText: String +) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(top = padding) + .height(35.dp) + .background(ColorTextBackgrond), + contentAlignment = Alignment.CenterStart + ){ + Text( + modifier = Modifier + .padding(start = 16.dp), + text = optionText, + color = ColorSecondaryText + ) + } +} + +@Preview +@Composable +fun PreviewRegisterMenuScreen(){ + RegisterMenuScreenImpl( + modifier = Modifier, + goToSelectCategoryScreen = {} , + onBackPressed = {} + ) +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuSideEffect.kt b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuSideEffect.kt new file mode 100644 index 000000000..e03d50a67 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuSideEffect.kt @@ -0,0 +1,4 @@ +package `in`.koreatech.business.feature.storemenu.registermenu.registermenu + +class RegisterMenuSideEffect { +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuState.kt b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuState.kt new file mode 100644 index 000000000..85c6fc9a9 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuState.kt @@ -0,0 +1,18 @@ +package `in`.koreatech.business.feature.storemenu.registermenu.registermenu + +import `in`.koreatech.koin.domain.model.owner.StoreMenuCategory + +data class RegisterMenuState( + + val shopId: Int = -1, + val menuName: String = "", + val menuPrice: List = emptyList(), + val menuCategory: List = emptyList(), + val description: String = "", + val imageUriList: List = emptyList(), + val isRecommendMenu : Boolean = false, + val isMainMenu: Boolean = false, + val isSetMenu: Boolean = false, + val isSideMenu: Boolean = false + +) \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuViewModel.kt b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuViewModel.kt new file mode 100644 index 000000000..ee4e9bc50 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuViewModel.kt @@ -0,0 +1,132 @@ +package `in`.koreatech.business.feature.storemenu.registermenu.registermenu + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import `in`.koreatech.koin.domain.usecase.business.menu.GetMenuCategoryUseCase +import kotlinx.coroutines.launch +import org.orbitmvi.orbit.ContainerHost +import org.orbitmvi.orbit.syntax.simple.intent +import org.orbitmvi.orbit.syntax.simple.reduce +import org.orbitmvi.orbit.viewmodel.container +import javax.inject.Inject + +@HiltViewModel +class RegisterMenuViewModel @Inject constructor( + private val getMenuCategoryUseCase : GetMenuCategoryUseCase +): ViewModel(), ContainerHost { + override val container = container(RegisterMenuState()) + + + init { + getStoreMenuCategory() + addPrice() + addImage() + } + + private fun getStoreMenuCategory(){ + intent { + viewModelScope.launch { + val menuCategory = getMenuCategoryUseCase(197) + reduce { + state.copy( + menuCategory = menuCategory + ) + } + } + } + } + + private fun addImage(){ + intent{ + reduce { + val newMenuUriList = state.imageUriList.toMutableList() + newMenuUriList.add("") + state.copy( + imageUriList = newMenuUriList + ) + } + } + } + + fun changeMenuName(menuName: String) = intent{ + reduce { + state.copy( + menuName = menuName + ) + } + } + + fun changeMenuPrice(index: Int, price: String){ + intent{ + if (index in state.menuPrice.indices) { + reduce { + val newMenuPrice = state.menuPrice.toMutableList() + newMenuPrice[index] = price + state.copy(menuPrice = newMenuPrice) + } + } + } + } + + fun addPrice(){ + intent{ + reduce { + val newMenuPrice = state.menuPrice.toMutableList() + newMenuPrice.add("") + state.copy( + menuPrice = newMenuPrice + ) + } + } + } + + fun recommendMenuIsClicked(){ + intent{ + reduce { + state.copy( + isRecommendMenu = !state.isRecommendMenu + ) + } + } + } + + fun mainMenuIsClicked(){ + intent{ + reduce { + state.copy( + isMainMenu = !state.isMainMenu + ) + } + } + } + + fun setMenuIsClicked(){ + intent{ + reduce { + state.copy( + isSetMenu = !state.isSetMenu + ) + } + } + } + + fun sideMenuIsClicked(){ + intent{ + reduce { + state.copy( + isSideMenu = !state.isSideMenu + ) + } + } + } + + fun changeMenuDetail(menuDetail: String) = intent{ + reduce { + state.copy( + description = menuDetail + ) + } + } +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/textfield/BorderTextField.kt b/business/src/main/java/in/koreatech/business/feature/textfield/BorderTextField.kt new file mode 100644 index 000000000..a3e0d88f4 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/textfield/BorderTextField.kt @@ -0,0 +1,50 @@ +package `in`.koreatech.business.feature.textfield + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.BasicTextField +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.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import `in`.koreatech.business.ui.theme.ColorMinor + +@Composable +fun BorderTextField( + startPadding: Dp = 10.dp, + inputString: String = "", + onStringChange: (String) -> Unit = {}, +){ + Box( + modifier = Modifier + .padding(start = startPadding) + .border(width = 1.dp, color = ColorMinor) + .height(37.dp), + contentAlignment = Alignment.CenterStart + ) { + BasicTextField( + value = inputString, + onValueChange = onStringChange, + textStyle = TextStyle( + color = Color.Black, + fontSize = 14.sp + ), + modifier = Modifier + .fillMaxWidth() + ) + } +} + +@Preview +@Composable +fun PreviewBorderTextField() { + BorderTextField() +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/ui/theme/Color.kt b/business/src/main/java/in/koreatech/business/ui/theme/Color.kt index 6bd9bdc3c..40bb446e7 100644 --- a/business/src/main/java/in/koreatech/business/ui/theme/Color.kt +++ b/business/src/main/java/in/koreatech/business/ui/theme/Color.kt @@ -38,3 +38,4 @@ val ColorUnarchived = Color(0xFFF4F4F4) val ColorDescription = Color(0xFFA1A1A1) val ColorMinor = Color(0xFF858585) val ColorSearch = Color(0xFFF6F8F9) +val ColorTransparency = Color(0x00FF0000) diff --git a/core/src/main/res/drawable/ic_add_menu_image.xml b/core/src/main/res/drawable/ic_add_menu_image.xml new file mode 100644 index 000000000..ecc0b0842 --- /dev/null +++ b/core/src/main/res/drawable/ic_add_menu_image.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/core/src/main/res/drawable/ic_white_arrow_back.xml b/core/src/main/res/drawable/ic_white_arrow_back.xml new file mode 100644 index 000000000..05a778259 --- /dev/null +++ b/core/src/main/res/drawable/ic_white_arrow_back.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 45b2cec74..0f25eaecb 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -7,9 +7,10 @@ 권한이 필요합니다. + 뒤로가기 확인 아니오 - 취소 + 취소 다음 1 / 4 2 / 4 @@ -30,6 +31,8 @@ 개점시간 폐점시간 메인 화면 바로가기 + 가격 추가 + @@ -131,4 +134,18 @@ 가게 등록 완료 가게 등록이 완료되었습니다.\n업체 정보 수정은 내 상점에서 가능합니다. + + + + 메뉴 추가 + 메뉴 정보 + 메뉴명 + 가격 + 메뉴 카테고리 + 메뉴 세부 + 메뉴구성 + 보쌈 + 막국수 (1인 세트) / 음료 별도 + 메뉴 사진 + (최대 이미지 3장) + diff --git a/data/src/main/java/in/koreatech/koin/data/api/StoreApi.kt b/data/src/main/java/in/koreatech/koin/data/api/StoreApi.kt index dd9e15ac6..05db76161 100644 --- a/data/src/main/java/in/koreatech/koin/data/api/StoreApi.kt +++ b/data/src/main/java/in/koreatech/koin/data/api/StoreApi.kt @@ -5,8 +5,10 @@ import `in`.koreatech.koin.data.response.store.StoreCategoriesResponse import `in`.koreatech.koin.data.response.store.StoreDetailEventResponse import `in`.koreatech.koin.data.response.store.StoreEventResponse import `in`.koreatech.koin.data.response.store.StoreItemWithMenusResponse +import `in`.koreatech.koin.data.response.store.StoreMenuCategoryResponse import `in`.koreatech.koin.data.response.store.StoreMenuResponse import `in`.koreatech.koin.data.response.store.StoreResponse +import `in`.koreatech.koin.domain.model.owner.StoreMenuCategory import retrofit2.http.GET import retrofit2.http.Path @@ -25,6 +27,8 @@ interface StoreApi { @GET(URLConstant.SHOPS.SHOPS + "/{id}") suspend fun getStore(@Path("id") uid: Int): StoreItemWithMenusResponse + @GET(URLConstant.SHOPS.SHOPS + "/{shopId}/menus/categories") + suspend fun getStoreMenuCategory(@Path("shopId") uid: Int): StoreMenuCategoryResponse @GET(URLConstant.SHOPS.SHOPS + "/{id}" + "/menus") suspend fun getShopMenus(@Path("id") uid: Int): StoreMenuResponse diff --git a/data/src/main/java/in/koreatech/koin/data/mapper/StoreMapper.kt b/data/src/main/java/in/koreatech/koin/data/mapper/StoreMapper.kt index 43098935b..383f2d304 100644 --- a/data/src/main/java/in/koreatech/koin/data/mapper/StoreMapper.kt +++ b/data/src/main/java/in/koreatech/koin/data/mapper/StoreMapper.kt @@ -10,7 +10,9 @@ import `in`.koreatech.koin.data.response.store.StoreEventItemReponse import `in`.koreatech.koin.data.response.store.StoreItemResponse import `in`.koreatech.koin.data.response.store.StoreItemWithMenusResponse import `in`.koreatech.koin.data.response.store.StoreMenuCategoriesResponse +import `in`.koreatech.koin.data.response.store.StoreMenuCategoryResponse import `in`.koreatech.koin.data.response.store.StoreMenuResponse +import `in`.koreatech.koin.domain.model.owner.StoreMenuCategory import `in`.koreatech.koin.domain.model.owner.insertstore.OperatingTime import `in`.koreatech.koin.domain.model.store.ShopEvent import `in`.koreatech.koin.domain.model.store.ShopEvents @@ -88,6 +90,13 @@ fun StoreItemWithMenusResponse.toStoreWithMenu(): StoreWithMenu = StoreWithMenu( accountNumber = accountNumber ?: null ) +fun List.toCategory(): List{ + val responseList = ArrayList() + for (category in this){ + responseList.add(StoreMenuCategory(category.id, category.name)) + } + return responseList +} fun StoreItemWithMenusResponse.CategoriesResponseDTO.toCategory() = StoreWithMenu.Category( id = id, name = name diff --git a/data/src/main/java/in/koreatech/koin/data/repository/StoreRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/StoreRepositoryImpl.kt index 42e1bf9bf..a5224ee35 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/StoreRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/StoreRepositoryImpl.kt @@ -1,5 +1,6 @@ package `in`.koreatech.koin.data.repository +import `in`.koreatech.koin.data.mapper.toCategory import `in`.koreatech.koin.data.mapper.toStore import `in`.koreatech.koin.data.mapper.toStoreCategories import `in`.koreatech.koin.data.mapper.toStoreEvent @@ -7,6 +8,7 @@ import `in`.koreatech.koin.data.mapper.toStoreDetailEvents import `in`.koreatech.koin.data.mapper.toStoreMenu import `in`.koreatech.koin.data.mapper.toStoreWithMenu import `in`.koreatech.koin.data.source.remote.StoreRemoteDataSource +import `in`.koreatech.koin.domain.model.owner.StoreMenuCategory import `in`.koreatech.koin.domain.model.store.ShopEvents import `in`.koreatech.koin.domain.model.store.Store import `in`.koreatech.koin.domain.model.store.StoreCategories @@ -51,7 +53,9 @@ class StoreRepositoryImpl @Inject constructor( return storeRemoteDataSource.getStoreMenu(storeId).toStoreWithMenu() } - + override suspend fun getStoreMenuCategory(storeId: Int): List{ + return storeRemoteDataSource.getStoreMenuCategory(storeId).toCategory() + } override suspend fun getShopMenus(storeId: Int): StoreMenu { return storeRemoteDataSource.getShopMenus(storeId).toStoreMenu() diff --git a/data/src/main/java/in/koreatech/koin/data/response/store/StoreMenuCategoryResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/store/StoreMenuCategoryResponse.kt new file mode 100644 index 000000000..065d550ca --- /dev/null +++ b/data/src/main/java/in/koreatech/koin/data/response/store/StoreMenuCategoryResponse.kt @@ -0,0 +1,13 @@ +package `in`.koreatech.koin.data.response.store + +import com.google.gson.annotations.SerializedName + +data class StoreMenuCategoryResponse( + @SerializedName("count") val count: Int, + @SerializedName("menu_categories") val menuCategories: List +){ + data class MenuCategory( + @SerializedName("id") val id: Int, + @SerializedName("name") val name: String + ) +} \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/source/remote/StoreRemoteDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/remote/StoreRemoteDataSource.kt index 1e434e4e4..d4a66e6e6 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/remote/StoreRemoteDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/remote/StoreRemoteDataSource.kt @@ -6,6 +6,7 @@ import `in`.koreatech.koin.data.response.store.StoreEventItemReponse import `in`.koreatech.koin.data.response.store.StoreDetailEventResponse import `in`.koreatech.koin.data.response.store.StoreItemResponse import `in`.koreatech.koin.data.response.store.StoreItemWithMenusResponse +import `in`.koreatech.koin.data.response.store.StoreMenuCategoryResponse import `in`.koreatech.koin.data.response.store.StoreMenuResponse import javax.inject.Inject @@ -28,6 +29,9 @@ class StoreRemoteDataSource @Inject constructor( return storeApi.getStore(storeUid) } + suspend fun getStoreMenuCategory(storeUid: Int): List { + return storeApi.getStoreMenuCategory(storeUid).menuCategories + } suspend fun getShopMenus(storeUid: Int): StoreMenuResponse { return storeApi.getShopMenus(storeUid) diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/owner/StoreMenuCategory.kt b/domain/src/main/java/in/koreatech/koin/domain/model/owner/StoreMenuCategory.kt new file mode 100644 index 000000000..3c23d0e36 --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/model/owner/StoreMenuCategory.kt @@ -0,0 +1,6 @@ +package `in`.koreatech.koin.domain.model.owner + +data class StoreMenuCategory( + val menuCategoryId: Int, + val menuCategoryName: String +) \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/repository/StoreRepository.kt b/domain/src/main/java/in/koreatech/koin/domain/repository/StoreRepository.kt index a012ec6a3..336975500 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/repository/StoreRepository.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/repository/StoreRepository.kt @@ -1,5 +1,6 @@ package `in`.koreatech.koin.domain.repository +import `in`.koreatech.koin.domain.model.owner.StoreMenuCategory import `in`.koreatech.koin.domain.model.store.ShopEvents import `in`.koreatech.koin.domain.model.store.Store import `in`.koreatech.koin.domain.model.store.StoreCategories @@ -13,6 +14,8 @@ interface StoreRepository { suspend fun getStoreCategories(): List suspend fun getStoreWithMenu(storeId: Int): StoreWithMenu + suspend fun getStoreMenuCategory(storeId: Int): List + suspend fun getShopMenus(storeId: Int): StoreMenu suspend fun getShopEvents(storeId: Int): ShopEvents diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/business/menu/GetMenuCategoryUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/business/menu/GetMenuCategoryUseCase.kt new file mode 100644 index 000000000..de5d086bd --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/business/menu/GetMenuCategoryUseCase.kt @@ -0,0 +1,15 @@ +package `in`.koreatech.koin.domain.usecase.business.menu + +import `in`.koreatech.koin.domain.model.owner.StoreMenuCategory +import `in`.koreatech.koin.domain.repository.StoreRepository +import javax.inject.Inject + +class GetMenuCategoryUseCase @Inject constructor( + private val storeRepository: StoreRepository, +) { + suspend operator fun invoke( + storeId: Int + ): List { + return storeRepository.getStoreMenuCategory(storeId) + } +} \ No newline at end of file