From 99bf894c929ba6185845ff130af256bef18482ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=A7=80=EC=9B=90?= Date: Sun, 8 Dec 2024 15:57:21 +0900 Subject: [PATCH] =?UTF-8?q?[UI]=20#82=20=EB=A7=81=ED=81=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=202=EC=B0=A8=20=EA=B8=B0=ED=9A=8D=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20(#85)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ui] 리마인드 UI 삭제 * [ui] 포킷 추가 버튼 삭제 * [chore] 포킷 버튼 이미지 추가 * [ui] 포킷 추가하기 UI 영역 추가 * [chore] 주석 및 height값 수정 * [chore] Pokit data class 수정 - image 프로퍼티 추가 * [chore] coil 라이브러리 추가 * [feature] 링크 수정 포킷 리스트 v2 구현 * [ui] icon_24_xs 추가 및 UI 적용 * [chore] 코딩 컨벤션 적용 * [chore] PokitInput 롤백 * [feature] 아이콘 클릭 시 title, url clear 구현 * [chore] idle 상태 추가 * [ui] 디자인 시스템 컬러 값 파라미터 추가 * [chore] 코딩 컨벤션 반영 * [chore] 디자인 시스템 컬러 값 파라미터 롤백 * [chore] 코딩 컨벤션 반영 --- core/ui/build.gradle.kts | 1 + .../ui/components/atom/input/PokitInput.kt | 12 +- .../subcomponents/icon/PokitInputIcon.kt | 4 +- .../block/labeledinput/LabeledInput.kt | 18 ++- .../block/pokitlist/PokitListVer2.kt | 97 ++++++++++++++ core/ui/src/main/res/drawable/icon_24_xs.xml | 10 ++ .../src/main/res/drawable/image_add_pokit.xml | 18 +++ .../com/strayalpaca/addlink/AddLinkScreen.kt | 118 +++++++++--------- .../strayalpaca/addlink/AddLinkViewModel.kt | 9 ++ .../java/com/strayalpaca/addlink/Preview.kt | 4 +- .../com/strayalpaca/addlink/model/Pokit.kt | 4 +- 11 files changed, 229 insertions(+), 66 deletions(-) create mode 100644 core/ui/src/main/java/pokitmons/pokit/core/ui/components/block/pokitlist/PokitListVer2.kt create mode 100644 core/ui/src/main/res/drawable/icon_24_xs.xml create mode 100644 core/ui/src/main/res/drawable/image_add_pokit.xml diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index ebf7dcf7..8c9214e6 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -45,6 +45,7 @@ dependencies { implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) + implementation(libs.coil.compose) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/core/ui/src/main/java/pokitmons/pokit/core/ui/components/atom/input/PokitInput.kt b/core/ui/src/main/java/pokitmons/pokit/core/ui/components/atom/input/PokitInput.kt index 79e24e41..65c50669 100644 --- a/core/ui/src/main/java/pokitmons/pokit/core/ui/components/atom/input/PokitInput.kt +++ b/core/ui/src/main/java/pokitmons/pokit/core/ui/components/atom/input/PokitInput.kt @@ -80,7 +80,11 @@ fun PokitInput( } if (icon?.position == PokitInputIconPosition.LEFT) { - PokitInputIcon(state = state, resourceId = icon.resourceId, onClick = onClickIcon) + PokitInputIcon( + state = state, + resourceId = icon.resourceId, + onClick = onClickIcon + ) Box(modifier = Modifier.width(8.dp)) } @@ -93,7 +97,11 @@ fun PokitInput( } if (icon?.position == PokitInputIconPosition.RIGHT) { - PokitInputIcon(state = state, resourceId = icon.resourceId, onClick = onClickIcon) + PokitInputIcon( + state = state, + resourceId = icon.resourceId, + onClick = onClickIcon + ) } } } diff --git a/core/ui/src/main/java/pokitmons/pokit/core/ui/components/atom/input/subcomponents/icon/PokitInputIcon.kt b/core/ui/src/main/java/pokitmons/pokit/core/ui/components/atom/input/subcomponents/icon/PokitInputIcon.kt index 0dec8891..a2c6493b 100644 --- a/core/ui/src/main/java/pokitmons/pokit/core/ui/components/atom/input/subcomponents/icon/PokitInputIcon.kt +++ b/core/ui/src/main/java/pokitmons/pokit/core/ui/components/atom/input/subcomponents/icon/PokitInputIcon.kt @@ -38,9 +38,7 @@ internal fun PokitInputIcon( } @Composable -private fun getColor( - state: PokitInputState, -): Color { +private fun getColor(state: PokitInputState): Color { return when (state) { PokitInputState.DEFAULT -> PokitTheme.colors.iconSecondary diff --git a/core/ui/src/main/java/pokitmons/pokit/core/ui/components/block/labeledinput/LabeledInput.kt b/core/ui/src/main/java/pokitmons/pokit/core/ui/components/block/labeledinput/LabeledInput.kt index 76934443..1fb1b01c 100644 --- a/core/ui/src/main/java/pokitmons/pokit/core/ui/components/block/labeledinput/LabeledInput.kt +++ b/core/ui/src/main/java/pokitmons/pokit/core/ui/components/block/labeledinput/LabeledInput.kt @@ -22,6 +22,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import pokitmons.pokit.core.ui.R import pokitmons.pokit.core.ui.components.atom.input.PokitInput +import pokitmons.pokit.core.ui.components.atom.input.attributes.PokitInputIcon +import pokitmons.pokit.core.ui.components.atom.input.attributes.PokitInputIconPosition import pokitmons.pokit.core.ui.components.atom.input.attributes.PokitInputState import pokitmons.pokit.core.ui.theme.PokitTheme @@ -37,8 +39,10 @@ fun LabeledInput( readOnly: Boolean = false, enable: Boolean = true, isError: Boolean = false, + onClickRemove: () -> Unit = {}, ) { var focused by remember { mutableStateOf(false) } + val state = remember(focused, isError, readOnly, enable) { getState( enabled = enable, @@ -67,7 +71,19 @@ fun LabeledInput( text = inputText, hintText = hintText, onChangeText = onChangeText, - icon = null, + icon = if (inputText.isNotEmpty()) { + PokitInputIcon( + position = PokitInputIconPosition.RIGHT, + resourceId = R.drawable.icon_24_xs + ) + } else { + null + }, + onClickIcon = remember { + { + onClickRemove() + } + }, isError = isError, enable = enable, readOnly = readOnly diff --git a/core/ui/src/main/java/pokitmons/pokit/core/ui/components/block/pokitlist/PokitListVer2.kt b/core/ui/src/main/java/pokitmons/pokit/core/ui/components/block/pokitlist/PokitListVer2.kt new file mode 100644 index 00000000..d36d4ba2 --- /dev/null +++ b/core/ui/src/main/java/pokitmons/pokit/core/ui/components/block/pokitlist/PokitListVer2.kt @@ -0,0 +1,97 @@ +package pokitmons.pokit.core.ui.components.block.pokitlist + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import pokitmons.pokit.core.ui.components.block.pokitlist.attributes.PokitListState +import pokitmons.pokit.core.ui.theme.PokitTheme + +@Composable +fun PokitListVer2( + item: T, + title: String, + sub: String, + imageUrl: String, + onClickItem: (T) -> Unit, + modifier: Modifier = Modifier, + state: PokitListState = PokitListState.DEFAULT, +) { + val titleTextColor = getTitleTextColor(state = state) + val subTextColor = getSubTextColor(state = state) + + Row( + modifier = modifier + .clickable( + enabled = state != PokitListState.DISABLE, + onClick = { onClickItem(item) }, + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) + .padding(horizontal = 20.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + AsyncImage( + model = imageUrl, + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier.size(60.dp) + ) + + Spacer(modifier = Modifier.width(12.dp)) + + Column( + modifier = Modifier.weight(1f) + ) { + Text( + text = title, + style = PokitTheme.typography.body1Bold.copy(color = titleTextColor), + overflow = TextOverflow.Ellipsis + ) + + Spacer(modifier = Modifier.height(4.dp)) + + Text( + text = sub, + style = PokitTheme.typography.detail1.copy(color = subTextColor) + ) + } + } +} + +@Composable +private fun getTitleTextColor( + state: PokitListState, +): Color { + return when (state) { + PokitListState.DEFAULT -> PokitTheme.colors.textPrimary + PokitListState.ACTIVE -> PokitTheme.colors.textPrimary + PokitListState.DISABLE -> PokitTheme.colors.textDisable + } +} + +@Composable +private fun getSubTextColor( + state: PokitListState, +): Color { + return when (state) { + PokitListState.DEFAULT -> PokitTheme.colors.textTertiary + PokitListState.ACTIVE -> PokitTheme.colors.textTertiary + PokitListState.DISABLE -> PokitTheme.colors.textDisable + } +} diff --git a/core/ui/src/main/res/drawable/icon_24_xs.xml b/core/ui/src/main/res/drawable/icon_24_xs.xml new file mode 100644 index 00000000..940737b2 --- /dev/null +++ b/core/ui/src/main/res/drawable/icon_24_xs.xml @@ -0,0 +1,10 @@ + + + diff --git a/core/ui/src/main/res/drawable/image_add_pokit.xml b/core/ui/src/main/res/drawable/image_add_pokit.xml new file mode 100644 index 00000000..c09f35d8 --- /dev/null +++ b/core/ui/src/main/res/drawable/image_add_pokit.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/feature/addlink/src/main/java/com/strayalpaca/addlink/AddLinkScreen.kt b/feature/addlink/src/main/java/com/strayalpaca/addlink/AddLinkScreen.kt index bfeaf753..024e81da 100644 --- a/feature/addlink/src/main/java/com/strayalpaca/addlink/AddLinkScreen.kt +++ b/feature/addlink/src/main/java/com/strayalpaca/addlink/AddLinkScreen.kt @@ -1,8 +1,11 @@ package com.strayalpaca.addlink import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image import androidx.compose.foundation.LocalOverscrollConfiguration import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -11,12 +14,13 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -24,9 +28,11 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -42,17 +48,13 @@ import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect import pokitmons.pokit.core.feature.model.paging.PagingState import pokitmons.pokit.core.ui.components.atom.button.PokitButton -import pokitmons.pokit.core.ui.components.atom.button.attributes.PokitButtonIcon -import pokitmons.pokit.core.ui.components.atom.button.attributes.PokitButtonIconPosition import pokitmons.pokit.core.ui.components.atom.button.attributes.PokitButtonSize import pokitmons.pokit.core.ui.components.atom.inputarea.PokitInputArea import pokitmons.pokit.core.ui.components.block.labeledinput.LabeledInput -import pokitmons.pokit.core.ui.components.block.pokitlist.PokitList +import pokitmons.pokit.core.ui.components.block.pokitlist.PokitListVer2 import pokitmons.pokit.core.ui.components.block.pokitlist.attributes.PokitListState import pokitmons.pokit.core.ui.components.block.pokittoast.PokitToast import pokitmons.pokit.core.ui.components.block.select.PokitSelect -import pokitmons.pokit.core.ui.components.block.switchradio.PokitSwitchRadio -import pokitmons.pokit.core.ui.components.block.switchradio.attributes.PokitSwitchRadioStyle import pokitmons.pokit.core.ui.components.template.bottomsheet.PokitBottomSheet import pokitmons.pokit.core.ui.theme.PokitTheme @@ -112,15 +114,47 @@ fun AddLinkScreenContainer( } } + Row( + modifier = Modifier + .fillMaxWidth() + .height(84.dp) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() }, + onClick = viewModel::checkPokitCount + ), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = Modifier.padding(start = 30.dp), + painter = painterResource(id = pokitmons.pokit.core.ui.R.drawable.image_add_pokit), + contentDescription = "포킷 추가 버튼" + ) + + Spacer(modifier = Modifier.size(20.dp)) + + Text( + text = "포킷 추가하기", + style = PokitTheme.typography.body1Bold + ) + } + + HorizontalDivider( + modifier = Modifier.fillMaxWidth(), + thickness = 1.dp, + color = PokitTheme.colors.borderTertiary + ) + LazyColumn( state = lazyColumnListState ) { items( items = pokitList ) { pokit -> - PokitList( + PokitListVer2( item = pokit, title = pokit.title, + imageUrl = pokit.image, sub = stringResource(id = R.string.count_format, pokit.count), onClickItem = viewModel::selectPokit, state = PokitListState.ACTIVE @@ -143,7 +177,9 @@ fun AddLinkScreenContainer( toggleRemindRadio = viewModel::setRemind, onBackPressed = viewModel::onBackPressed, onClickSaveButton = viewModel::saveLink, - closeToast = viewModel::closeToastMessage + closeToast = viewModel::closeToastMessage, + clearTitle = viewModel::clearTitle, + clearUrl = viewModel::clearUrl ) } @@ -164,6 +200,8 @@ fun AddLinkScreen( onBackPressed: () -> Unit, onClickSaveButton: () -> Unit, closeToast: () -> Unit, + clearUrl: () -> Unit, + clearTitle: () -> Unit, ) { val scrollState = rememberScrollState() val enable = remember(state.step) { @@ -174,6 +212,10 @@ fun AddLinkScreen( ) } + var currentUrl = remember { + mutableStateOf(url) + } + Column( modifier = Modifier .fillMaxSize() @@ -221,7 +263,10 @@ fun AddLinkScreen( inputText = url, hintText = stringResource(id = R.string.placeholder_link), onChangeText = inputUrl, - enable = enable + enable = enable, + onClickRemove = { + clearUrl() + } ) Spacer(modifier = Modifier.height(24.dp)) @@ -232,7 +277,10 @@ fun AddLinkScreen( inputText = title, hintText = stringResource(id = R.string.placeholder_title), onChangeText = inputTitle, - enable = enable + enable = enable, + onClickRemove = { + clearTitle() + } ) Spacer(modifier = Modifier.height(24.dp)) @@ -249,21 +297,10 @@ fun AddLinkScreen( onClick = onClickSelectPokit, enable = enable ) - - Spacer(modifier = Modifier.width(8.dp)) - - PokitButton( - text = null, - icon = PokitButtonIcon( - resourceId = pokitmons.pokit.core.ui.R.drawable.icon_24_plus, - position = PokitButtonIconPosition.LEFT - ), - size = PokitButtonSize.LARGE, - onClick = onClickAddPokit, - enable = enable - ) } + // onClickAddPokit + Spacer(modifier = Modifier.height(24.dp)) Text( @@ -303,41 +340,6 @@ fun AddLinkScreen( ) } - Spacer(modifier = Modifier.height(24.dp)) - - Text( - text = stringResource(id = R.string.title_remind), - style = PokitTheme.typography.body2Medium.copy(color = PokitTheme.colors.textSecondary) - ) - - Spacer(modifier = Modifier.height(12.dp)) - - PokitSwitchRadio( - modifier = Modifier.fillMaxWidth(), - itemList = listOf( - Pair(stringResource(id = R.string.reject_remind), false), - Pair(stringResource(id = R.string.accept_remind), true) - ), - style = PokitSwitchRadioStyle.STROKE, - selectedItem = if (state.useRemind) { - Pair(stringResource(id = R.string.accept_remind), true) - } else { - Pair(stringResource(id = R.string.reject_remind), false) - }, - onClickItem = { - toggleRemindRadio(it.second) - }, - getTitleFromItem = { it.first }, - enabled = false - ) - - Spacer(modifier = Modifier.height(8.dp)) - - Text( - text = stringResource(id = R.string.see_you_soon), - style = PokitTheme.typography.detail1.copy(color = PokitTheme.colors.textTertiary) - ) - Spacer(modifier = Modifier.height(32.dp)) } } diff --git a/feature/addlink/src/main/java/com/strayalpaca/addlink/AddLinkViewModel.kt b/feature/addlink/src/main/java/com/strayalpaca/addlink/AddLinkViewModel.kt index b7c11ab3..4a5c2e6d 100644 --- a/feature/addlink/src/main/java/com/strayalpaca/addlink/AddLinkViewModel.kt +++ b/feature/addlink/src/main/java/com/strayalpaca/addlink/AddLinkViewModel.kt @@ -191,6 +191,14 @@ class AddLinkViewModel @Inject constructor( } } + fun clearUrl() { + this._linkUrl.update { "" } + } + + fun clearTitle() { + this._title.update { "" } + } + private suspend fun getLinkMetaData(linkUrl: String) = intent { val response = getLinkCardUseCase.getLinkCard(linkUrl) if (response is PokitResult.Success) { @@ -327,6 +335,7 @@ class AddLinkViewModel @Inject constructor( if (response.result >= MAX_POKIT_COUNT) { reduce { state.copy(toastMessage = ToastMessageEvent.CANNOT_CREATE_POKIT_MORE) } } else { + reduce { state.copy(step = ScreenStep.IDLE) } postSideEffect(AddLinkScreenSideEffect.OnNavigateToAddPokit) } } else { diff --git a/feature/addlink/src/main/java/com/strayalpaca/addlink/Preview.kt b/feature/addlink/src/main/java/com/strayalpaca/addlink/Preview.kt index f7bab065..b30375e3 100644 --- a/feature/addlink/src/main/java/com/strayalpaca/addlink/Preview.kt +++ b/feature/addlink/src/main/java/com/strayalpaca/addlink/Preview.kt @@ -30,7 +30,9 @@ fun AddLinkScreenPreview() { toggleRemindRadio = {}, onBackPressed = {}, onClickSaveButton = {}, - closeToast = {} + closeToast = {}, + clearUrl = {}, + clearTitle = {} ) } } diff --git a/feature/addlink/src/main/java/com/strayalpaca/addlink/model/Pokit.kt b/feature/addlink/src/main/java/com/strayalpaca/addlink/model/Pokit.kt index 79c6450d..1619ee3e 100644 --- a/feature/addlink/src/main/java/com/strayalpaca/addlink/model/Pokit.kt +++ b/feature/addlink/src/main/java/com/strayalpaca/addlink/model/Pokit.kt @@ -6,13 +6,15 @@ data class Pokit( val title: String, val id: String, val count: Int, + val image: String = "", ) { companion object { fun fromDomainPokit(pokit: DomainPokit): Pokit { return Pokit( title = pokit.name, id = pokit.categoryId.toString(), - count = pokit.linkCount + count = pokit.linkCount, + image = pokit.image.url ) } }