Skip to content

Commit 7f4b476

Browse files
authored
[Fix/#99] 등록 뷰 UI 이슈
1 parent 194f14e commit 7f4b476

File tree

14 files changed

+177
-46
lines changed

14 files changed

+177
-46
lines changed

app/src/main/java/com/poti/android/core/designsystem/component/field/PotiBasicField.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ internal fun PotiBasicField(
4848
trailingIcon: (@Composable () -> Unit)? = null,
4949
enabled: Boolean = true,
5050
visualTransformation: VisualTransformation? = null,
51+
neverCoverField: Boolean = false,
5152
) {
5253
var isFocused by remember { mutableStateOf(false) }
5354
val requester = remember {
@@ -107,7 +108,7 @@ internal fun PotiBasicField(
107108
)
108109
}
109110

110-
if (singleLine && !isFocused && value.isNotEmpty()) {
111+
if (!neverCoverField && singleLine && !isFocused && value.isNotEmpty()) {
111112
Text(
112113
text = value,
113114
modifier = Modifier

app/src/main/java/com/poti/android/core/designsystem/component/field/PotiMenuItem.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import androidx.compose.material3.Text
1212
import androidx.compose.runtime.Composable
1313
import androidx.compose.runtime.getValue
1414
import androidx.compose.runtime.remember
15+
import androidx.compose.ui.Alignment
1516
import androidx.compose.ui.Modifier
1617
import androidx.compose.ui.res.stringResource
1718
import androidx.compose.ui.unit.dp
@@ -59,6 +60,7 @@ fun PotiMenuItem(
5960
)
6061
.padding(horizontal = 16.dp, vertical = 15.dp),
6162
horizontalArrangement = Arrangement.SpaceBetween,
63+
verticalAlignment = Alignment.CenterVertically,
6264
) {
6365
Text(
6466
text = option,

app/src/main/java/com/poti/android/core/designsystem/component/field/PotiShortTextField.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ fun PotiShortTextField(
5353
focusRequester: FocusRequester? = null,
5454
onFocusChanged: ((Boolean) -> Unit)? = null,
5555
visualTransformation: VisualTransformation? = null,
56+
neverCoverField: Boolean = false,
5657
) {
5758
var isFocused by remember { mutableStateOf(false) }
5859

@@ -98,6 +99,7 @@ fun PotiShortTextField(
9899
singleLine = true,
99100
trailingIcon = trailingIcon,
100101
visualTransformation = visualTransformation,
102+
neverCoverField = neverCoverField,
101103
)
102104

103105
if (error.isNotBlank()) {

app/src/main/java/com/poti/android/presentation/party/create/PartyArtistSelectScreen.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage
2424
import com.poti.android.core.designsystem.theme.PotiTheme
2525
import com.poti.android.domain.model.artist.ArtistSearchResult
2626
import com.poti.android.presentation.party.create.component.CreateDropdownField
27+
import com.poti.android.presentation.party.create.component.ViewType
2728
import com.poti.android.presentation.party.create.model.CreateUiEffect
2829
import com.poti.android.presentation.party.create.model.CreateUiIntent
2930
import com.poti.android.presentation.party.create.model.CreateUiState
@@ -47,8 +48,8 @@ fun PartyArtistSelectRoute(
4748
uiState = uiState,
4849
onSearchKeywordChange = { viewModel.processIntent(CreateUiIntent.OnArtistSearchKeywordChange(it)) },
4950
onArtistSelect = { viewModel.processIntent(CreateUiIntent.OnArtistSelect(it)) },
50-
onConfirmClick = { viewModel.processIntent(CreateUiIntent.OnBackClick) },
51-
onPopBackStack = { viewModel.processIntent(CreateUiIntent.OnBackClick) },
51+
onConfirmClick = { viewModel.processIntent(CreateUiIntent.OnBackToCreate) },
52+
onPopBackStack = { viewModel.processIntent(CreateUiIntent.OnBackToCreate) },
5253
modifier = modifier,
5354
)
5455
}
@@ -77,6 +78,7 @@ private fun PartyArtistSelectScreen(
7778
.padding(innerPadding),
7879
) {
7980
CreateDropdownField(
81+
viewType = ViewType.ARTSIT_SELECT,
8082
value = uiState.artistSearchKeyword,
8183
onValueChanged = onSearchKeywordChange,
8284
searchResults = uiState.artistSearchResultsState.getSuccessDataOrNull() ?: emptyList(),

app/src/main/java/com/poti/android/presentation/party/create/PartyCreateScreen.kt

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import androidx.compose.ui.text.input.KeyboardType
2525
import androidx.compose.ui.tooling.preview.Preview
2626
import androidx.compose.ui.unit.dp
2727
import androidx.lifecycle.compose.collectAsStateWithLifecycle
28-
import androidx.lifecycle.viewmodel.compose.viewModel
2928
import com.poti.android.R
3029
import com.poti.android.core.common.extension.getSuccessDataOrNull
3130
import com.poti.android.core.common.extension.noRippleClickable
@@ -48,13 +47,15 @@ import com.poti.android.presentation.party.create.component.CreateDropdownField
4847
import com.poti.android.presentation.party.create.component.CreateMemberSetting
4948
import com.poti.android.presentation.party.create.component.CreatePhotoUpload
5049
import com.poti.android.presentation.party.create.component.SellerNotice
50+
import com.poti.android.presentation.party.create.component.ViewType
5151
import com.poti.android.presentation.party.create.model.CreateUiEffect
5252
import com.poti.android.presentation.party.create.model.CreateUiIntent
5353
import com.poti.android.presentation.party.create.model.CreateUiIntent.*
5454
import com.poti.android.presentation.party.create.model.CreateUiState
5555
import com.poti.android.presentation.party.create.model.FieldError
5656
import com.poti.android.presentation.party.create.model.MemberSettingStatus
57-
import com.poti.android.presentation.party.util.toImageInfosForPresigned
57+
import com.poti.android.presentation.party.create.util.DateTransformation
58+
import com.poti.android.presentation.party.create.util.toImageInfosForPresigned
5859
import kotlinx.collections.immutable.persistentListOf
5960

6061
@Composable
@@ -77,6 +78,10 @@ fun PartyCreateRoute(
7778
}
7879
}
7980

81+
LaunchedEffect(Unit) {
82+
viewModel.processIntent(CreateUiIntent.InitializeScreen)
83+
}
84+
8085
HandleSideEffects(viewModel.sideEffect) { effect ->
8186
when (effect) {
8287
CreateUiEffect.NavigateToBack -> {
@@ -118,7 +123,6 @@ fun PartyCreateRoute(
118123
subBtnText = R.string.action_button_select_all,
119124
onSubBtnClick = {
120125
viewModel.processIntent(CreateUiIntent.OnAllMemberSelect)
121-
showBottomSheet = false
122126
},
123127
subEnabled = true,
124128
members = uiState.sheetDisplayMemberNames,
@@ -177,6 +181,7 @@ private fun PartyCreateScreen(
177181
modifier: Modifier = Modifier,
178182
) {
179183
val listState = rememberLazyListState()
184+
val dateTransformation = remember { DateTransformation() }
180185

181186
LaunchedEffect(
182187
uiState.imageError,
@@ -212,6 +217,12 @@ private fun PartyCreateScreen(
212217
onNavigationClick = onBackClick,
213218
)
214219
},
220+
bottomBar = {
221+
PotiBottomButton(
222+
text = stringResource(R.string.create_btn_create),
223+
onClick = onCreateBtnClick,
224+
)
225+
},
215226
) { innerPadding ->
216227
LazyColumn(
217228
state = listState,
@@ -267,6 +278,7 @@ private fun PartyCreateScreen(
267278

268279
item {
269280
CreateDropdownField(
281+
viewType = ViewType.CREATE_PARTY,
270282
value = uiState.productName,
271283
onValueChanged = onProductChanged,
272284
searchResults = uiState.productSearchResultsState.getSuccessDataOrNull() ?: emptyList(),
@@ -292,6 +304,8 @@ private fun PartyCreateScreen(
292304
error = uiState.deadlineError?.let { stringResource(it.message) } ?: "",
293305
keyboardType = KeyboardType.Number,
294306
imeAction = ImeAction.Next,
307+
visualTransformation = dateTransformation,
308+
neverCoverField = true,
295309
)
296310
}
297311

@@ -318,7 +332,7 @@ private fun PartyCreateScreen(
318332
.padding(bottom = 28.dp),
319333
label = stringResource(R.string.create_label_account_number),
320334
error = uiState.accountNumberError?.let { stringResource(it.message) } ?: "",
321-
keyboardType = KeyboardType.Text,
335+
keyboardType = KeyboardType.Number,
322336
imeAction = ImeAction.Next,
323337
)
324338
}
@@ -342,6 +356,7 @@ private fun PartyCreateScreen(
342356
)
343357

344358
CreateMemberSetting(
359+
neverShowHint = uiState.neverShowHint,
345360
status = uiState.memberSettingStatus,
346361
selectedMembersOption = uiState.editOptionDisplayMembers,
347362
onPriceChange = onMemberPriceChanged,
@@ -370,11 +385,6 @@ private fun PartyCreateScreen(
370385
modifier = Modifier
371386
.padding(bottom = 40.dp),
372387
)
373-
374-
PotiBottomButton(
375-
text = stringResource(R.string.create_btn_create),
376-
onClick = onCreateBtnClick,
377-
)
378388
}
379389
}
380390
}

app/src/main/java/com/poti/android/presentation/party/create/PartyCreateViewModel.kt

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.poti.android.presentation.party.create
22

3+
import androidx.core.text.isDigitsOnly
34
import androidx.lifecycle.viewModelScope
45
import com.poti.android.core.base.BaseViewModel
56
import com.poti.android.core.common.state.ApiState
@@ -17,6 +18,9 @@ import com.poti.android.presentation.party.create.model.CreateUiIntent
1718
import com.poti.android.presentation.party.create.model.CreateUiState
1819
import com.poti.android.presentation.party.create.model.FieldError
1920
import com.poti.android.presentation.party.create.model.MemberSettingStatus
21+
import com.poti.android.presentation.party.create.util.isTodayOrAfter
22+
import com.poti.android.presentation.party.create.util.toDashedDate
23+
import com.poti.android.presentation.party.create.util.toDateOrNull
2024
import dagger.hilt.android.lifecycle.HiltViewModel
2125
import kotlinx.collections.immutable.ImmutableList
2226
import kotlinx.collections.immutable.toPersistentList
@@ -48,10 +52,15 @@ class PartyCreateViewModel @Inject constructor(
4852

4953
override fun processIntent(intent: CreateUiIntent) {
5054
when (intent) {
55+
CreateUiIntent.InitializeScreen -> initializeDeliveryOptions()
56+
57+
CreateUiIntent.CleanScreen -> updateState { CreateUiState() }
58+
5159
CreateUiIntent.OnBackClick -> {
5260
if (uiState.value.isDirty) {
5361
sendEffect(CreateUiEffect.ShowDialog)
5462
} else {
63+
updateState { CreateUiState() }
5564
sendEffect(CreateUiEffect.NavigateToBack)
5665
}
5766
}
@@ -61,11 +70,14 @@ class PartyCreateViewModel @Inject constructor(
6170
sendEffect(CreateUiEffect.NavigateToBack)
6271
}
6372

73+
is CreateUiIntent.OnBackToCreate -> sendEffect(CreateUiEffect.NavigateToBack)
74+
6475
is CreateUiIntent.OnImagesChanged -> {
6576
updateState {
6677
copy(
6778
isDirty = true,
6879
selectedImages = intent.uris.toPersistentList(),
80+
imageError = if (intent.uris.isNotEmpty()) null else this.imageError,
6981
)
7082
}
7183
}
@@ -158,10 +170,6 @@ class PartyCreateViewModel @Inject constructor(
158170
}
159171

160172
init {
161-
viewModelScope.launch {
162-
initializeDeliveryOptions()
163-
}
164-
165173
viewModelScope.launch {
166174
artistSearchKeywordForDebounce
167175
.debounce(500)
@@ -183,23 +191,25 @@ class PartyCreateViewModel @Inject constructor(
183191
}
184192
}
185193

186-
private suspend fun initializeDeliveryOptions() {
187-
getDeliveryOptionsUseCase()
188-
.onSuccess { result ->
189-
updateState {
190-
copy(
191-
deliveryOptionsState = ApiState.Success(result.toPersistentList()),
192-
editableDeliveryOptions = result.toPersistentList(),
193-
selectedDeliveryIds = this.selectedDeliveryIds + result.first().deliveryId,
194-
)
195-
}
196-
}.onFailure { e ->
197-
updateState {
198-
copy(
199-
deliveryOptionsState = ApiState.Failure(e.message ?: "get delivery fail"),
200-
)
194+
private fun initializeDeliveryOptions() {
195+
viewModelScope.launch {
196+
getDeliveryOptionsUseCase()
197+
.onSuccess { result ->
198+
updateState {
199+
copy(
200+
deliveryOptionsState = ApiState.Success(result.toPersistentList()),
201+
editableDeliveryOptions = result.toPersistentList(),
202+
selectedDeliveryIds = this.selectedDeliveryIds + result.first().deliveryId,
203+
)
204+
}
205+
}.onFailure { e ->
206+
updateState {
207+
copy(
208+
deliveryOptionsState = ApiState.Failure(e.message ?: "get delivery fail"),
209+
)
210+
}
201211
}
202-
}
212+
}
203213
}
204214

205215
private fun handleAccountNumberChange(newValue: String) {
@@ -221,6 +231,7 @@ class PartyCreateViewModel @Inject constructor(
221231
val selectedMemberIds = getAllMemberIdSet(members)
222232

223233
updateState {
234+
val errorBefore = this.memberSettingStatus == MemberSettingStatus.ERROR_NO_PRICE || this.memberSettingStatus == MemberSettingStatus.ERROR_NO_MEMBER
224235
copy(
225236
isDirty = true,
226237
selectedArtist = newArtist,
@@ -230,6 +241,7 @@ class PartyCreateViewModel @Inject constructor(
230241
editableMemberOptions = members.toPersistentList(),
231242
selectedMemberIds = selectedMemberIds,
232243
memberSettingStatus = MemberSettingStatus.IN_PROGRESS,
244+
neverShowHint = errorBefore,
233245
)
234246
}
235247
}
@@ -321,6 +333,8 @@ class PartyCreateViewModel @Inject constructor(
321333
}
322334

323335
private fun handleDeadlineChange(newValue: String) {
336+
if (!newValue.isDigitsOnly() || newValue.length > 8) return
337+
324338
updateState {
325339
copy(
326340
isDirty = true,
@@ -415,10 +429,10 @@ class PartyCreateViewModel @Inject constructor(
415429
}
416430

417431
private fun handleAllMemberSelect() {
418-
val newIndices = if (uiState.value.sheetDisplayMemberIndices.isEmpty()) {
419-
uiState.value.editableMemberOptions.indices.toSet()
420-
} else {
432+
val newIndices = if (uiState.value.sheetDisplayMemberIndices.size == uiState.value.editableMemberOptions.size) {
421433
setOf()
434+
} else {
435+
uiState.value.editableMemberOptions.indices.toSet()
422436
}
423437

424438
updateState {
@@ -463,7 +477,15 @@ class PartyCreateViewModel @Inject constructor(
463477
val imageError = if (uiState.value.selectedImages.isEmpty()) FieldError.IMAGE_EMPTY_ERROR else null
464478
val artistError = if (uiState.value.selectedArtist == null) FieldError.ARTIST_EMPTY_ERROR else null
465479
val productError = if (uiState.value.productName.isBlank()) FieldError.PRODUCT_EMPTY_ERROR else null
466-
val deadlineError = if (uiState.value.deadline.isBlank()) FieldError.DEADLINE_EMPTY_ERROR else null
480+
val deadlineError = when (val date = uiState.value.deadline.toDateOrNull()) {
481+
null -> if (uiState.value.deadline.isBlank()) {
482+
FieldError.DEADLINE_EMPTY_ERROR
483+
} else {
484+
FieldError.DEADLINE_INVALID_ERROR
485+
}
486+
487+
else -> if (!date.isTodayOrAfter()) FieldError.DEADLINE_PAST_ERROR else null
488+
}
467489
val descriptionError = if (uiState.value.description.isBlank()) FieldError.DESCRIPTION_ERROR else null
468490
val accountNumberError = if (uiState.value.accountNumber.isBlank()) FieldError.ACCOUNT_NUMBER_ERROR else null
469491
val bankError = if (uiState.value.bank.isBlank()) FieldError.BANK_ERROR else null
@@ -493,6 +515,7 @@ class PartyCreateViewModel @Inject constructor(
493515
accountNumberError = accountNumberError,
494516
bankError = bankError,
495517
memberSettingStatus = currentSettingStatus,
518+
neverShowHint = if (hasMemberOptionError) true else this.neverShowHint,
496519
)
497520
}
498521
}
@@ -507,7 +530,7 @@ class PartyCreateViewModel @Inject constructor(
507530
artistId = uiState.value.selectedArtist?.artistId ?: 0L,
508531
product = uiState.value.productName,
509532
description = uiState.value.description,
510-
deadline = uiState.value.deadline,
533+
deadline = uiState.value.deadline.toDashedDate(),
511534
bank = uiState.value.bank,
512535
accountNumber = uiState.value.accountNumber,
513536
imageUrls = urls,
@@ -540,6 +563,7 @@ class PartyCreateViewModel @Inject constructor(
540563
copy(createPartyState = ApiState.Success(partyId))
541564
}
542565
sendEffect(CreateUiEffect.NavigateToDetail(partyId))
566+
updateState { CreateUiState() }
543567
}
544568
.onFailure {
545569
updateState {

0 commit comments

Comments
 (0)