Skip to content

Commit

Permalink
카테고리 수정하기 화면 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
leesa-l committed Nov 27, 2023
1 parent 9827a42 commit 0877f02
Show file tree
Hide file tree
Showing 17 changed files with 565 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.dkin.chevit.presentation.checklist.category

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.viewModels
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import com.dkin.chevit.core.mvi.MVIComposeFragment
import com.dkin.chevit.presentation.common.model.getCategoryTypeByName
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class EditCategory :
MVIComposeFragment<EditCategoryIntent, EditCategoryState, EditCategoryEffect>() {
override val viewModel: EditCategoryViewModel by viewModels()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
EditCategoryScreen(
viewModel = viewModel,
onClickBack = { findNavController().popBackStack() }
)
}
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val planId = arguments?.getString("planId")
val categoryId = arguments?.getString("categoryId")
val title = arguments?.getString("title")
val type = arguments?.getString("type")
if (planId == null || categoryId == null || title == null || type == null) {
//todo alert
findNavController().popBackStack()
} else {
viewModel.initState(planId, categoryId, title, getCategoryTypeByName(type))
}
}

override fun processEffect(effect: EditCategoryEffect) {
when (effect) {
else -> {}
}
}

override fun processState(state: EditCategoryState) {}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.dkin.chevit.presentation.checklist.category

import com.dkin.chevit.core.mvi.ViewEffect
import com.dkin.chevit.core.mvi.ViewIntent
import com.dkin.chevit.core.mvi.ViewState
import com.dkin.chevit.presentation.common.model.CategoryType

sealed interface EditCategoryIntent : ViewIntent {
}

data class EditCategoryState(
val planId: String,
val categoryId: String,
val title: String,
val type: CategoryType
) : ViewState {
companion object {
fun empty() = EditCategoryState("", "", "", CategoryType.REQUIRES)
}
}

sealed interface EditCategoryEffect : ViewEffect {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package com.dkin.chevit.presentation.checklist.category

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.PaddingValues
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.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
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.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.dkin.chevit.presentation.common.model.CategoryType
import com.dkin.chevit.presentation.resource.ChevitButtonFillMedium
import com.dkin.chevit.presentation.resource.ChevitTextField
import com.dkin.chevit.presentation.resource.ChevitTheme
import com.dkin.chevit.presentation.resource.getCategoryIconResId
import com.dkin.chevit.presentation.resource.icon.ChevitIcon
import com.dkin.chevit.presentation.resource.icon.IconArrowLeftLine
import com.dkin.chevit.presentation.resource.icon.IconCloseCircleFill
import com.dkin.chevit.presentation.resource.util.clickableNoRipple

@Composable
fun EditCategoryScreen(
viewModel: EditCategoryViewModel,
onClickBack: () -> Unit
) {
val state = viewModel.state.collectAsState().value
var input by remember { mutableStateOf(state.title) }
var selectedCategory by remember { mutableStateOf<CategoryType>(state.type) }
var isValidInput by remember { mutableStateOf(true) }
var saveable by remember { mutableStateOf(false) }

LaunchedEffect(input) {
isValidInput = input.length < 9
saveable = input.isNotBlank() && isValidInput
}
LaunchedEffect(selectedCategory) {
saveable = input.isNotBlank() && isValidInput
}

val categories = CategoryType.values()

Column(
modifier = Modifier.fillMaxSize()
) {
TopBar(modifier = Modifier.fillMaxWidth(), onClickBack = onClickBack)
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 24.dp),
) {
Spacer(modifier = Modifier.height(25.dp))
Text(
text = "새 카테고리",
style = ChevitTheme.typhography.headlineMedium.copy(color = ChevitTheme.colors.textPrimary),
)
Spacer(modifier = Modifier.height(18.dp))
Text(
text = "카테고리 제목을 입력해 주세요.",
style = ChevitTheme.typhography.bodyMedium.copy(color = ChevitTheme.colors.grey6),
)
Spacer(modifier = Modifier.height(8.dp))
ChevitTextField(
modifier = Modifier.fillMaxWidth(),
value = input,
isInputError = !isValidInput,
onValueChange = {
input = it
},
placeholder = {
Text(
modifier = Modifier,
text = "ex. 기내 아이템",
style = ChevitTheme.typhography.bodyLarge.copy(color = ChevitTheme.colors.grey4),
)
},
trailingIcon = {
if (input.isNotEmpty()) {
Icon(
modifier = Modifier
.size(20.dp)
.clickableNoRipple {
input = ""
},
imageVector = ChevitIcon.IconCloseCircleFill,
contentDescription = "",
)
}
}
)
if (!isValidInput) {
Spacer(modifier = Modifier.height(2.dp))
Text(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp),
text = "최대 8글자까지 입력해주세요.",
style = ChevitTheme.typhography.bodySmall.copy(color = ChevitTheme.colors.statusError),
)
}
Spacer(modifier = Modifier.height(32.dp))
Text(
text = "아이콘",
style = ChevitTheme.typhography.headlineMedium.copy(color = ChevitTheme.colors.textPrimary),
)
LazyVerticalGrid(
modifier = Modifier.weight(1f),
columns = GridCells.Fixed(5),
horizontalArrangement = Arrangement.spacedBy(22.dp),
verticalArrangement = Arrangement.spacedBy(22.dp),
contentPadding = PaddingValues(vertical = 18.dp)
) {
items(categories) { category ->
val isSelected = category == selectedCategory
Box(
modifier = Modifier
.size(48.dp)
.background(color = ChevitTheme.colors.grey0, shape = CircleShape)
.border(
width = if (isSelected) 1.dp else (-1).dp,
color = ChevitTheme.colors.grey10,
shape = CircleShape,
)
.clickable { selectedCategory = category },
contentAlignment = Alignment.Center
) {
Image(
painter = painterResource(id = category.getCategoryIconResId()),
contentDescription = ""
)
}
}
}
ChevitButtonFillMedium(
modifier = Modifier.fillMaxWidth(),
enabled = saveable,
onClick = { selectedCategory.let { viewModel.saveCategory(input, it) } }
) {
Text(text = "수정하기")
}
Spacer(modifier = Modifier.height(24.dp))
}
}
}

@Composable
private fun TopBar(modifier: Modifier, onClickBack: () -> Unit) {
Box(
modifier = modifier
.height(58.dp)
.padding(vertical = 16.dp, horizontal = 24.dp),
contentAlignment = Alignment.Center
) {
Icon(
modifier = Modifier
.align(Alignment.CenterStart)
.clickableNoRipple { onClickBack() },
imageVector = ChevitIcon.IconArrowLeftLine,
contentDescription = "",
)
Text(
modifier = Modifier.align(Alignment.Center),
text = "카테고리 수정하기",
textAlign = TextAlign.Center,
style = ChevitTheme.typhography.headlineMedium.copy(color = ChevitTheme.colors.textPrimary)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.dkin.chevit.presentation.checklist.category

import com.dkin.chevit.core.mvi.MVIViewModel
import com.dkin.chevit.presentation.common.model.CategoryType
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class EditCategoryViewModel @Inject constructor() :
MVIViewModel<EditCategoryIntent, EditCategoryState, EditCategoryEffect>() {
override fun createInitialState(): EditCategoryState = EditCategoryState.empty()

override suspend fun processIntent(intent: EditCategoryIntent) {
when (intent) {
else -> {}
}
}

fun initState(planId: String,categoryId: String, title: String, type: CategoryType) {
setState {
EditCategoryState(planId, categoryId, title, type)
}
}

fun saveCategory(title: String, category: CategoryType) {
//todo
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.window.DialogProperties
import androidx.fragment.app.viewModels
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.dialog
import androidx.navigation.compose.rememberNavController
import androidx.navigation.findNavController
import androidx.navigation.navArgument
import com.dkin.chevit.core.mvi.MVIComposeFragment
import com.dkin.chevit.presentation.checklist.R
import com.dkin.chevit.presentation.checklist.main.contents.FloatingContents
import com.dkin.chevit.presentation.checklist.main.contents.MoreCategoryBottomSheet
import com.dkin.chevit.presentation.checklist.main.contents.SaveTemplateContents
import com.dkin.chevit.presentation.deeplink.DeepLink
import com.dkin.chevit.presentation.deeplink.deepLink
Expand Down Expand Up @@ -66,7 +69,10 @@ class Checklist : MVIComposeFragment<ChecklistIntent, ChecklistState, ChecklistE
)
) { popUpTo(R.id.checklist) }
},
openFloatingContents = { navController.navigate("floating") }
openFloatingContents = { navController.navigate("floating") },
openCategoryMoreSheet = { id, title, type ->
navController.navigate("categoryMore/${id}?title=${title}?type=${type.name}")
}
)
}
dialog(
Expand Down Expand Up @@ -94,6 +100,38 @@ class Checklist : MVIComposeFragment<ChecklistIntent, ChecklistState, ChecklistE
onClickBringTemplate = { viewModel.bringTemplate() },
)
}
dialog(
route = "categoryMore/{categoryId}?title={title}?type={type}",
arguments = listOf(
navArgument("categoryId") { type = NavType.StringType },
navArgument("title") { type = NavType.StringType; defaultValue = "" },
navArgument("type") { type = NavType.StringType; defaultValue = "" },
),
dialogProperties = DialogProperties(usePlatformDefaultWidth = false),
) {
val categoryId = it.arguments?.getString("categoryId") ?: ""
val title = it.arguments?.getString("title") ?: ""
val type = it.arguments?.getString("type") ?: ""
MoreCategoryBottomSheet(
title = title,
navigateEditItem = {
navController.popBackStack()
deepLink(
DeepLink.EditCategory(
planId = planId,
categoryId = categoryId,
title = title,
type = type
)
) { popUpTo(R.id.checklist) }
},
deleteItem = {
navController.popBackStack()
viewModel.deleteCategory(planId, categoryId)
},
onClose = { navController.popBackStack() }
)
}
}
}
}
Expand Down
Loading

0 comments on commit 0877f02

Please sign in to comment.