Skip to content

Commit

Permalink
카테고리 추가하기 화면 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
leesa-l committed Nov 13, 2023
1 parent 99349b7 commit 6c4fa6b
Show file tree
Hide file tree
Showing 16 changed files with 263 additions and 25 deletions.
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<nav-graph android:value="@navigation/nav_checklist" />
</activity>
</application>
</manifest>
1 change: 0 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ compose = [
"compose-bom",
"compose-ui",
"compose-activity",
"compose-navigation",
"compose-material3",
"compose-uiGraphics",
"compose-uiTooling",
Expand Down
1 change: 1 addition & 0 deletions presentation/checklist/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ dependencies {
implementation(project(":presentation:common"))
implementation(project(":presentation:deeplink"))
implementation(libs.coil.compose)
implementation(libs.compose.navigation)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.viewModels
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.findNavController
import com.dkin.chevit.core.mvi.MVIComposeFragment
import com.dkin.chevit.presentation.common.category.AddCategoryContents
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand All @@ -17,7 +22,6 @@ class CheckList : MVIComposeFragment<ChecklistIntent, ChecklistState, ChecklistE

override fun processEffect(effect: ChecklistEffect) {
when (effect) {
ChecklistEffect.NavigateToAddCategory -> {}
ChecklistEffect.NavigateToBringTemplate -> {}
ChecklistEffect.NavigateToSaveTemplate -> {}
is ChecklistEffect.NavigateToLink -> {}
Expand All @@ -35,11 +39,36 @@ class CheckList : MVIComposeFragment<ChecklistIntent, ChecklistState, ChecklistE
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
ChecklistScreen(
viewModel = viewModel,
onClickBack = { requireActivity().onBackPressed() }
)
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "checklist") {
composable("checklist") {
ChecklistScreen(
viewModel = viewModel,
onClickBack = {
findNavController().popBackStack()
},
navigateAddCategory = {
navController.navigate("addCategory")
}
)
}
composable("addCategory") {
AddCategoryContents(
saveCategory = { title, category ->
viewModel.addCategory(title, category)
navController.popBackStack()
},
onClickBack = { navController.popBackStack() }
)
}
}
}
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val id = arguments?.getString("checklistId")
id?.let { viewModel.getChecklist(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ data class ChecklistState(
}

sealed interface ChecklistEffect : ViewEffect {
object NavigateToAddCategory : ChecklistEffect
object NavigateToBringTemplate : ChecklistEffect
object NavigateToSaveTemplate : ChecklistEffect
data class NavigateToLink(val url: String) : ChecklistEffect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ import com.dkin.chevit.presentation.resource.util.clickableNoRipple
@Composable
fun ChecklistScreen(
viewModel: ChecklistViewModel,
onClickBack: () -> Unit
onClickBack: () -> Unit,
navigateAddCategory: () -> Unit
) {
val checklistState by viewModel.state.collectAsState()
var showCountryInfo by remember { mutableStateOf(true) }
Expand Down Expand Up @@ -185,7 +186,7 @@ fun ChecklistScreen(
FloatingContentItem(
icon = ChevitIcon.IconSuitcaseFill,
title = "카테고리 추가하기",
onClick = { viewModel.addCategory() }),
onClick = { navigateAddCategory() }),
FloatingContentItem(
icon = ChevitIcon.IconFolderReceivedFill,
title = "템플릿에서 불러오기",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.dkin.chevit.presentation.checklist

import com.dkin.chevit.core.mvi.MVIViewModel
import com.dkin.chevit.presentation.common.category.CategoryType
import dagger.hilt.android.lifecycle.HiltViewModel
import timber.log.Timber
import javax.inject.Inject

@HiltViewModel
Expand All @@ -16,6 +18,10 @@ class ChecklistViewModel @Inject constructor() :
}
}

fun getChecklist(id: String) {
Timber.d("checklistId = $id")
}

fun onClickUrl(url: String) {
setEffect { ChecklistEffect.NavigateToLink(url) }
}
Expand All @@ -24,15 +30,15 @@ class ChecklistViewModel @Inject constructor() :
setEffect { ChecklistEffect.NavigateToCategory(id) }
}

fun addCategory() {
setEffect { ChecklistEffect.NavigateToAddCategory }
}

fun bringTemplate() {
setEffect { ChecklistEffect.NavigateToBringTemplate }
}

fun saveTemplate() {
setEffect { ChecklistEffect.NavigateToSaveTemplate }
}

fun addCategory(title: String, category: CategoryType) {
//TODO
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package com.dkin.chevit.presentation.common.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.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.resource.ChevitButtonFillLarge
import com.dkin.chevit.presentation.resource.ChevitTextField
import com.dkin.chevit.presentation.resource.ChevitTheme
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
import com.dkin.chevit.presentation.resource.util.getCategoryIconResId

@Composable
fun AddCategoryContents(
saveCategory: (title: String, category: CategoryType) -> Unit,
onClickBack: () -> Unit,
) {
var input by remember { mutableStateOf("") }
var selectedCategory by remember { mutableStateOf<CategoryType?>(null) }
var isValidInput by remember { mutableStateOf(true) }
var saveable by remember { mutableStateOf(false) }

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

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 = ""
)
}
}
}
ChevitButtonFillLarge(
modifier = Modifier.fillMaxWidth(),
enabled = saveable,
onClick = { selectedCategory?.let { 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
Expand Up @@ -62,7 +62,7 @@ fun CategoryListContents(
) {
Box(
modifier = Modifier
.size(54.dp)
.size(48.dp)
.background(color = ChevitTheme.colors.white, shape = CircleShape),
contentAlignment = Alignment.Center
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
android:id="@+id/checklist"
android:name="com.dkin.chevit.presentation.checklist.CheckList"
android:label="Checklist">
<deepLink app:uri="chevit://checklist" />
<argument
android:name="checklistId"
app:argType="string" />
<deepLink app:uri="chevit://checklist/{checklistId}" />
</fragment>
</navigation>
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ sealed interface DeepLink {
override val deepLink: String = "$SCHEME://step"
}

object CheckList : DeepLink {
override val deepLink: String = "$SCHEME://checklist"
data class CheckList(val id: String) : DeepLink {
override val deepLink: String = "$SCHEME://checklist/$id"
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Home : MVIComposeFragment<HomeIntent, HomeState, HomeEffect>() {
deepLink(DeepLink.Step) { popUpTo(R.id.home) }

is HomeEffect.NavigateToCheckList -> {
deepLink(DeepLink.CheckList) { popUpTo(R.id.home) }
deepLink(DeepLink.CheckList(effect.id)) { popUpTo(R.id.home) }
}
}
}
Expand Down
Loading

0 comments on commit 6c4fa6b

Please sign in to comment.