From ca87651c54da5f607e955cfe03d2e36a16701261 Mon Sep 17 00:00:00 2001 From: wjchoi96 Date: Thu, 14 Sep 2023 15:56:08 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:TOP-77=20ToHotCard=20=EC=84=B8?= =?UTF-8?q?=EB=B6=84=ED=99=94=ED=95=98=EC=97=AC=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 토픽을 선택하고 앱에 다시 로그인 한 경우 - 토픽을 선택하기 이전 - 다음 페이지에 유저가 없는 경우 - 주제어를 선택했는데 유저가 없는 경우 - 유저를 대기하면서 조회 결과가 유효할 때 --- .../tohot/component/card/ToHotEnterCard.kt | 6 +- .../card/ToHotNoneInitialUserCard.kt | 33 ++++ ...tEmptyCard.kt => ToHotNoneNextUserCard.kt} | 16 +- .../tohot/component/card/ToHotNotifyCard.kt | 2 +- .../component/card/ToHotQuerySuccessCard.kt | 29 +++ .../src/main/res/drawable/ic_mudy_enter.xml | 168 ++++-------------- .../drawable/ic_mudy_none_initial_user.xml | 146 +++++++++++++++ ...c_mudy_empty.xml => ic_mudy_none_next.xml} | 0 .../res/drawable/ic_mudy_query_success.xml | 60 +++++++ feature/tohot/src/main/res/values/strings.xml | 13 +- 10 files changed, 331 insertions(+), 142 deletions(-) create mode 100644 feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNoneInitialUserCard.kt rename feature/tohot/src/main/java/tht/feature/tohot/component/card/{ToHotEmptyCard.kt => ToHotNoneNextUserCard.kt} (55%) create mode 100644 feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotQuerySuccessCard.kt create mode 100644 feature/tohot/src/main/res/drawable/ic_mudy_none_initial_user.xml rename feature/tohot/src/main/res/drawable/{ic_mudy_empty.xml => ic_mudy_none_next.xml} (100%) create mode 100644 feature/tohot/src/main/res/drawable/ic_mudy_query_success.xml diff --git a/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotEnterCard.kt b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotEnterCard.kt index 46928efb..6e7a661c 100644 --- a/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotEnterCard.kt +++ b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotEnterCard.kt @@ -7,6 +7,10 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import tht.feature.tohot.R +/** + * 이미 주제어를 선택한 상태로 앱에 접속 + * 유저 List가 보여지기 전에 보여지는 EnterCard + */ @Composable fun ToHotEnterCard( modifier: Modifier = Modifier, @@ -17,7 +21,7 @@ fun ToHotEnterCard( image = painterResource(id = R.drawable.ic_mudy_enter), title = stringResource(id = R.string.to_hot_enter_card_title), description = stringResource(id = R.string.to_hot_enter_card_description), - buttonText = stringResource(id = R.string.waiting), + buttonText = stringResource(id = R.string.entering), onClick = onClick ) } diff --git a/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNoneInitialUserCard.kt b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNoneInitialUserCard.kt new file mode 100644 index 00000000..e0aa624e --- /dev/null +++ b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNoneInitialUserCard.kt @@ -0,0 +1,33 @@ +package tht.feature.tohot.component.card + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import tht.feature.tohot.R + +/** + * 처음 주제어를 선택 시 유저가 없는 경우 + * - 기다리는 무디 조회 버튼 + */ +@Composable +fun ToHotNoneInitialUserCard( + modifier: Modifier = Modifier, + onClick: () -> Unit = { } +) { + ToHotNotifyCard( + modifier = modifier, + image = painterResource(id = R.drawable.ic_mudy_none_initial_user), + title = stringResource(id = R.string.to_hot_none_initial_user_card_title), + description = stringResource(id = R.string.to_hot_none_initial_user_card_description), + buttonText = stringResource(id = R.string.waiting), + onClick = onClick + ) +} + +@Composable +@Preview +private fun ToHotNoneInitialUserCardPreview() { + ToHotNoneInitialUserCard() +} diff --git a/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotEmptyCard.kt b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNoneNextUserCard.kt similarity index 55% rename from feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotEmptyCard.kt rename to feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNoneNextUserCard.kt index 09261c20..c64c97d9 100644 --- a/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotEmptyCard.kt +++ b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNoneNextUserCard.kt @@ -7,16 +7,20 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import tht.feature.tohot.R +/** + * 주제어에 더 이상 유저가 없는 경우 + * - 기다리는 무디 조회 버튼 + */ @Composable -fun ToHotEmptyCard( +fun ToHotNoneNextUserCard( modifier: Modifier = Modifier, onClick: () -> Unit = { } ) { ToHotNotifyCard( modifier = modifier, - image = painterResource(id = R.drawable.ic_mudy_empty), - title = stringResource(id = R.string.to_hot_empty_card_title), - description = stringResource(id = R.string.to_hot_empty_card_description), + image = painterResource(id = R.drawable.ic_mudy_none_next), + title = stringResource(id = R.string.to_hot_none_next_user_card_title), + description = stringResource(id = R.string.to_hot_none_next_user_card_description), buttonText = stringResource(id = R.string.waiting), onClick = onClick ) @@ -24,6 +28,6 @@ fun ToHotEmptyCard( @Composable @Preview -private fun ToHotEmptyCardPreview() { - ToHotEmptyCard() +private fun ToHotNoneNextUserCardPreview() { + ToHotNoneNextUserCard() } diff --git a/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNotifyCard.kt b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNotifyCard.kt index dd8eaf56..a82ede08 100644 --- a/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNotifyCard.kt +++ b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotNotifyCard.kt @@ -97,7 +97,7 @@ fun ToHotNotifyCard( @Preview private fun ToHotNotifyCardPreview() { ToHotNotifyCard( - image = painterResource(id = R.drawable.ic_mudy_enter), + image = painterResource(id = R.drawable.ic_mudy_none_initial_user), title = "가나다라마바사", description = "preview", buttonText = "테스트" diff --git a/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotQuerySuccessCard.kt b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotQuerySuccessCard.kt new file mode 100644 index 00000000..2125d0bf --- /dev/null +++ b/feature/tohot/src/main/java/tht/feature/tohot/component/card/ToHotQuerySuccessCard.kt @@ -0,0 +1,29 @@ +package tht.feature.tohot.component.card + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import tht.feature.tohot.R + +@Composable +fun ToHotQuerySuccessCard( + modifier: Modifier = Modifier, + onClick: () -> Unit = { } +) { + ToHotNotifyCard( + modifier = modifier, + image = painterResource(id = R.drawable.ic_mudy_query_success), + title = stringResource(id = R.string.to_hot_query_success_card_title), + description = stringResource(id = R.string.to_hot_query_success_card_description), + buttonText = stringResource(id = R.string.starting), + onClick = onClick + ) +} + +@Composable +@Preview +private fun ToHotQuerySuccessCardPreview() { + ToHotQuerySuccessCard() +} diff --git a/feature/tohot/src/main/res/drawable/ic_mudy_enter.xml b/feature/tohot/src/main/res/drawable/ic_mudy_enter.xml index c81e88cf..e93b129c 100644 --- a/feature/tohot/src/main/res/drawable/ic_mudy_enter.xml +++ b/feature/tohot/src/main/res/drawable/ic_mudy_enter.xml @@ -1,146 +1,54 @@ - - - - - - - - + + + + + + + + + + + + android:pathData="M102.83,72.14C104.71,69.45 107.12,67.03 109.23,64.98C110.75,63.5 112.04,62.31 113.28,61.23C113.81,60.76 114.04,60.12 113.91,59.46C113.76,58.75 113.21,58.13 112.5,57.89C111.85,57.67 111.17,57.81 110.62,58.28C109.31,59.42 107.97,60.66 106.39,62.2C103.61,64.91 101.38,67.27 99.51,69.95C99.39,70.12 99.3,70.31 99.24,70.49C98.97,71.33 99.38,72.14 100.04,72.59C100.85,73.14 102.11,73.17 102.83,72.13L102.83,72.14Z" + android:fillColor="#3D3D3D"/> + android:pathData="M55.37,129.99L47.32,102.61C47.13,101.94 47.31,101.23 47.8,100.74C48.18,100.35 48.72,100.15 49.27,100.19L66.69,101.43C67.51,101.49 68.21,102.05 68.45,102.84L76.83,129.9C77.04,130.57 76.86,131.3 76.36,131.8C75.98,132.18 75.46,132.38 74.93,132.35L57.19,131.42C56.34,131.38 55.61,130.8 55.37,129.99Z" + android:fillColor="#3D3D3D"/> - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/feature/tohot/src/main/res/drawable/ic_mudy_none_initial_user.xml b/feature/tohot/src/main/res/drawable/ic_mudy_none_initial_user.xml new file mode 100644 index 00000000..c81e88cf --- /dev/null +++ b/feature/tohot/src/main/res/drawable/ic_mudy_none_initial_user.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/feature/tohot/src/main/res/drawable/ic_mudy_empty.xml b/feature/tohot/src/main/res/drawable/ic_mudy_none_next.xml similarity index 100% rename from feature/tohot/src/main/res/drawable/ic_mudy_empty.xml rename to feature/tohot/src/main/res/drawable/ic_mudy_none_next.xml diff --git a/feature/tohot/src/main/res/drawable/ic_mudy_query_success.xml b/feature/tohot/src/main/res/drawable/ic_mudy_query_success.xml new file mode 100644 index 00000000..9ea5fb61 --- /dev/null +++ b/feature/tohot/src/main/res/drawable/ic_mudy_query_success.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + diff --git a/feature/tohot/src/main/res/values/strings.xml b/feature/tohot/src/main/res/values/strings.xml index 12927f35..f707fa78 100644 --- a/feature/tohot/src/main/res/values/strings.xml +++ b/feature/tohot/src/main/res/values/strings.xml @@ -17,6 +17,7 @@ "해당 사용자와 서로 차단됩니다.? 차단하기 + 입장하기 시작하기 기다리기 다시 시작 @@ -27,12 +28,16 @@ 토픽을 선택할 수 없어요.. - 무디들을 모두 만나봤어요! - 아직 무디들이 들어오고있어요. - 주제어를 가장 먼저 선택하셨어요! - 아직 무디들이 들어오고있어요. + 무디들을 모두 만나봤어요! + 아직 무디들이 들어오고있어요. + 주제어를 가장 먼저 선택하셨어요! + 아직 무디들이 들어오고있어요. 무디들을 다시 불러올까요? 무디들을 불러오는데 문제가 발생했어요! + 무디들을 만나러 가볼까요? + 버튼을 눌러 시작하기 + 무디들이 들어왔어요! + 바로 무디들을 만나볼까요? "같은 주제어를 선택한\n무디들을 찾고 있어요.." "무디를 신고 중 이예요.." From 7dc1aa3d5058c4a3dd12ec354a1423286500aee7 Mon Sep 17 00:00:00 2001 From: wjchoi96 Date: Thu, 14 Sep 2023 15:56:57 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:TOP-77=20ToHotCardState=20=EC=84=B8?= =?UTF-8?q?=EB=B6=84=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/tohot/tohot/route/ToHotRoute.kt | 8 ++----- .../feature/tohot/tohot/screen/ToHotScreen.kt | 24 ++++++++++--------- .../feature/tohot/tohot/state/ToHotState.kt | 10 +++++--- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/feature/tohot/src/main/java/tht/feature/tohot/tohot/route/ToHotRoute.kt b/feature/tohot/src/main/java/tht/feature/tohot/tohot/route/ToHotRoute.kt index d47abe50..7b0d5f37 100644 --- a/feature/tohot/src/main/java/tht/feature/tohot/tohot/route/ToHotRoute.kt +++ b/feature/tohot/src/main/java/tht/feature/tohot/tohot/route/ToHotRoute.kt @@ -148,11 +148,6 @@ internal fun ToHotRoute( onDismiss = toHotViewModel::reportDialogDismissEvent ) -// ToHotHoldDialog( -// isShow = toHotState.holdDialogShow, -// onRestartClick = toHotViewModel::releaseHoldEvent -// ) - val modalBottomSheetState = rememberModalBottomSheetState( initialValue = ModalBottomSheetValue.Hidden, skipHalfExpanded = true, @@ -224,7 +219,8 @@ internal fun ToHotRoute( onUnLikeClick = toHotViewModel::userDislikeEvent, onReportMenuClick = toHotViewModel::reportMenuEvent, onHoldDoubleTab = toHotViewModel::releaseHoldEvent, - onRefreshClick = toHotViewModel::refreshEvent + onEnterClick = toHotViewModel::enterEvent, + onRefreshClick = toHotViewModel::queryUserListEvent ) } diff --git a/feature/tohot/src/main/java/tht/feature/tohot/tohot/screen/ToHotScreen.kt b/feature/tohot/src/main/java/tht/feature/tohot/tohot/screen/ToHotScreen.kt index 2b9f9abe..d9d6a8b1 100644 --- a/feature/tohot/src/main/java/tht/feature/tohot/tohot/screen/ToHotScreen.kt +++ b/feature/tohot/src/main/java/tht/feature/tohot/tohot/screen/ToHotScreen.kt @@ -14,9 +14,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import tht.feature.tohot.component.card.ToHotCard -import tht.feature.tohot.component.card.ToHotEmptyCard import tht.feature.tohot.component.card.ToHotEnterCard +import tht.feature.tohot.component.card.ToHotNoneNextUserCard +import tht.feature.tohot.component.card.ToHotNoneInitialUserCard import tht.feature.tohot.component.card.ToHotErrorCard +import tht.feature.tohot.component.card.ToHotQuerySuccessCard import tht.feature.tohot.component.toolbar.ToHotToolBar import tht.feature.tohot.component.toolbar.ToHotToolBarContent import tht.feature.tohot.mockUserList @@ -51,6 +53,7 @@ internal fun ToHotScreen( onLikeClick: (Int) -> Unit = { }, onUnLikeClick: (Int) -> Unit = { }, onReportMenuClick: () -> Unit = { }, + onEnterClick: () -> Unit = { }, onRefreshClick: () -> Unit = { }, onHoldDoubleTab: () -> Unit = { }, loadFinishListener: (Int, Boolean, Throwable?) -> Unit = { _, _, _ -> } @@ -69,16 +72,15 @@ internal fun ToHotScreen( ) } - when (cardList.list.isEmpty()) { - true -> { - when (toHotCardState) { - ToHotCardState.Initialize -> ToHotEnterCard(onClick = onRefreshClick) - ToHotCardState.Running -> ToHotEmptyCard(onClick = onRefreshClick) - ToHotCardState.Error -> ToHotErrorCard(onClick = onRefreshClick) - } - } + when (toHotCardState) { + ToHotCardState.NoneSelectTopic -> ToHotEnterCard() + ToHotCardState.Enter -> ToHotEnterCard(onClick = onEnterClick) + ToHotCardState.NoneInitializeUser -> ToHotNoneInitialUserCard(onClick = onRefreshClick) + ToHotCardState.NoneNextUser -> ToHotNoneNextUserCard(onClick = onRefreshClick) + ToHotCardState.QuerySuccess -> ToHotQuerySuccessCard(onClick = onEnterClick) + ToHotCardState.Error -> ToHotErrorCard(onClick = onRefreshClick) - else -> { + ToHotCardState.Running -> { VerticalPager( userScrollEnabled = false, pageCount = cardList.list.size, @@ -130,7 +132,7 @@ internal fun ToHotScreen( fun ToHotScreenPreview() { val toHotState = ToHotState( userList = ImmutableListWrapper(mockUserList.toList()), - userCardState = ToHotCardState.Initialize, + userCardState = ToHotCardState.Running, timers = ImmutableListWrapper( Array(mockUserList.size) { CardTimerUiModel( diff --git a/feature/tohot/src/main/java/tht/feature/tohot/tohot/state/ToHotState.kt b/feature/tohot/src/main/java/tht/feature/tohot/tohot/state/ToHotState.kt index 21ae821c..19ef3738 100644 --- a/feature/tohot/src/main/java/tht/feature/tohot/tohot/state/ToHotState.kt +++ b/feature/tohot/src/main/java/tht/feature/tohot/tohot/state/ToHotState.kt @@ -11,7 +11,7 @@ import tht.feature.tohot.model.TopicUiModel data class ToHotState( val loading: ToHotLoading, val userList: ImmutableListWrapper, - val userCardState: ToHotCardState, // Empty 일 경우 보여줄 View 를 정함 + val userCardState: ToHotCardState = ToHotCardState.NoneSelectTopic, // Start, Empty 경우 보여줄 View 를 정함 val timers: ImmutableListWrapper, val enableTimerIdx: Int, // 현재 표시 되는 Card Idx -> 해당 Card 의 Timer 진행됨 val fallingAnimationIdx: Int = -1, // 신고, 차단 Animation Idx @@ -49,7 +49,11 @@ enum class ToHotLoading { } enum class ToHotCardState { - Initialize, - Running, + NoneSelectTopic, // Topic 선택 이전 + Enter, // Topic 선택 후 앱 접속 + NoneInitializeUser, // Topic 선택 후, 유저가 없는 경우 + NoneNextUser, // 페이징 중 다음 유저 없는 경우 + QuerySuccess, // 새로운 유저 조회 성공 + Running, // 정상 동작 Error } From 3d3cb6061c19a4a9e412d49458074cc54ab69d90 Mon Sep 17 00:00:00 2001 From: wjchoi96 Date: Thu, 14 Sep 2023 15:57:42 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:TOP-77=20ToHotCardState=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=A0=90=EC=9D=84=20ToHotViewModel=EC=97=90=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 대기하며 유저 조회 기능 구현 --- .../tohot/tohot/viewmodel/ToHotViewModel.kt | 149 +++++++++++++----- 1 file changed, 110 insertions(+), 39 deletions(-) diff --git a/feature/tohot/src/main/java/tht/feature/tohot/tohot/viewmodel/ToHotViewModel.kt b/feature/tohot/src/main/java/tht/feature/tohot/tohot/viewmodel/ToHotViewModel.kt index 1d86225d..22e025e2 100644 --- a/feature/tohot/src/main/java/tht/feature/tohot/tohot/viewmodel/ToHotViewModel.kt +++ b/feature/tohot/src/main/java/tht/feature/tohot/tohot/viewmodel/ToHotViewModel.kt @@ -54,7 +54,6 @@ class ToHotViewModel @Inject constructor( ) : ViewModel(), Container { private val initializeState get() = ToHotState( userList = ImmutableListWrapper(emptyList()), - userCardState = ToHotCardState.Initialize, timers = ImmutableListWrapper(emptyList()), enableTimerIdx = 0, cardMoveAllow = true, @@ -84,10 +83,12 @@ class ToHotViewModel @Inject constructor( get() = store.state.value.userList.list.indices init { - fetchToHotState() + fetchToHotState(autoRunToHot = false) } - private fun fetchToHotState() { + private fun fetchToHotState( + autoRunToHot: Boolean + ) { intent { reduce { it.copy(loading = ToHotLoading.TopicList) } fetchToHotStateUseCase( @@ -95,21 +96,28 @@ class ToHotViewModel @Inject constructor( size = CARD_SIZE ).onSuccess { toHotState -> reduce { + val newList = toHotState.cards.map { c -> c.toUiModel() } + val cardState = if (toHotState.needSelectTopic) { + ToHotCardState.NoneSelectTopic + } else if (newList.isEmpty()) { + ToHotCardState.NoneInitializeUser + } else if (autoRunToHot) { + ToHotCardState.Running + } else { + ToHotCardState.Enter + } it.copy( - userList = ImmutableListWrapper( - store.state.value.userList.list + toHotState.cards.map { c -> c.toUiModel() } - ), - userCardState = ToHotCardState.Initialize, + userList = ImmutableListWrapper(newList), + userCardState = cardState, timers = ImmutableListWrapper( - store.state.value.timers.list + - List(toHotState.cards.size) { - CardTimerUiModel( - maxSec = MAX_TIMER_SEC.toInt(), - currentSec = MAX_TIMER_SEC, - destinationSec = MAX_TIMER_SEC, - startAble = false - ) - } + List(toHotState.cards.size) { + CardTimerUiModel( + maxSec = MAX_TIMER_SEC.toInt(), + currentSec = MAX_TIMER_SEC, + destinationSec = MAX_TIMER_SEC, + startAble = false + ) + } ), enableTimerIdx = 0, topicList = ImmutableListWrapper(toHotState.topic.topics.map { t -> t.toUiModel() }), @@ -236,26 +244,97 @@ class ToHotViewModel @Inject constructor( ToHotSideEffect.Scroll(currentIdx + 1, animate) ) } - else -> removeAllCard() + else -> { + intent { + reduce { + it.copy( + userList = ImmutableListWrapper(emptyList()), + timers = ImmutableListWrapper(emptyList()), + userCardState = ToHotCardState.NoneNextUser, + enableTimerIdx = 0 + ) + } + } + } } } } - fun refreshEvent() { + fun enterEvent() { + intent { + reduce { + it.copy( + userCardState = ToHotCardState.Running + ) + } + } + } + + /** + * 20초동안 10초 간격 으로 2번 조회 시도 + */ + fun queryUserListEvent() { if (store.state.value.loading != ToHotLoading.None) return - viewModelScope.launch { - intent { reduce { it.copy(loading = ToHotLoading.UserList) } } - fetchUserCard( - lastUserIdx = if (passedUserCardStack.empty()) null else passedUserCardStack.peek().idx - ) - intent { reduce { it.copy(loading = ToHotLoading.None) } } + val prevUserSize = store.state.value.userList.list.size + var queryCount = 0 + intent { + reduce { it.copy(loading = ToHotLoading.UserList) } + while (true) { + queryUserCard() + if (store.state.value.userList.list.size != prevUserSize) { + reduce { it.copy(userCardState = ToHotCardState.QuerySuccess) } + break + } + if (++queryCount >= QUERY_USER_COUNT) { + break + } + delay(QUERY_USER_SUSPEND_TIME_MILL) + } + reduce { it.copy(loading = ToHotLoading.None) } + } + } + + /** + * 대기 하며 유저 조회 + */ + private suspend fun queryUserCard() { + val lastUserIdx = if (passedUserCardStack.empty()) null else passedUserCardStack.peek().idx + fetchDailyUserCardUseCase( + passedUserIdList = passedUserCardStack.map { it.id }.toList(), + lastUserDailyFallingCourserIdx = lastUserIdx, + size = CARD_SIZE + ).onSuccess { dailyUserCardList -> + intent { + reduce { + it.copy( + userList = ImmutableListWrapper( + store.state.value.userList.list + dailyUserCardList.cards.map { c -> c.toUiModel() } + ), + timers = ImmutableListWrapper( + store.state.value.timers.list + + List(dailyUserCardList.cards.size) { + CardTimerUiModel( + maxSec = MAX_TIMER_SEC.toInt(), + currentSec = MAX_TIMER_SEC, + destinationSec = MAX_TIMER_SEC, + startAble = false + ) + } + ), + topicResetRemainingTime = parseRemainingTime(dailyUserCardList.topicResetTimeMill), + topicResetTimeMill = dailyUserCardList.topicResetTimeMill + ) + } + } + }.onFailure { e -> + e.printStackTrace() } } /** * 페이징 - 마지막 Index Card 에서 페이징 요청 */ - private suspend fun fetchUserCard(lastUserIdx: Int? = null) { + private suspend fun fetchNextUserCard(lastUserIdx: Int? = null) { pagingLoading = lastUserIdx != null if (!pagingLoading) intent { reduce { it.copy(loading = ToHotLoading.UserList) } } fetchDailyUserCardUseCase( @@ -348,7 +427,7 @@ class ToHotViewModel @Inject constructor( loading = ToHotLoading.None ) } - fetchToHotState() + fetchToHotState(autoRunToHot = true) } else -> postSideEffect( ToHotSideEffect.ToastMessage( @@ -386,7 +465,7 @@ class ToHotViewModel @Inject constructor( passedCardCountBetweenTouch++ if (userIdx == currentUserListRange.last) { viewModelScope.launch { - fetchUserCard(lastUserIdx = passUser.idx) + fetchNextUserCard(lastUserIdx = passUser.idx) } } } @@ -722,18 +801,6 @@ class ToHotViewModel @Inject constructor( } } - private fun removeAllCard() { - intent { - reduce { - it.copy( - userList = ImmutableListWrapper(emptyList()), - timers = ImmutableListWrapper(emptyList()), - enableTimerIdx = 0 - ) - } - } - } - fun removeUserCard(userIdx: Int) = with(store.state.value) { if (userIdx !in userList.list.indices) return intent { @@ -796,5 +863,9 @@ class ToHotViewModel @Inject constructor( private const val CARD_COUNT_ALLOW_WITHOUT_TOUCH = 3 private const val CARD_SIZE = 5 + + private const val QUERY_USER_SUSPEND_TIME_MILL = 5000L + + private const val QUERY_USER_COUNT = 2 } } From 4d0375d01239f6ef36361eff2f36c7e58f078d0e Mon Sep 17 00:00:00 2001 From: wjchoi96 Date: Thu, 14 Sep 2023 16:01:10 +0900 Subject: [PATCH 04/12] =?UTF-8?q?design:TOP-77=20Topic=20placeholder=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=EC=BD=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/drawable/ic_topic_item_placeholder_48.xml | 8 +++++--- .../main/res/drawable/ic_topic_placeholder_38.xml | 12 +++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/feature/tohot/src/main/res/drawable/ic_topic_item_placeholder_48.xml b/feature/tohot/src/main/res/drawable/ic_topic_item_placeholder_48.xml index f7450271..3d193590 100644 --- a/feature/tohot/src/main/res/drawable/ic_topic_item_placeholder_48.xml +++ b/feature/tohot/src/main/res/drawable/ic_topic_item_placeholder_48.xml @@ -1,7 +1,9 @@ - + android:viewportWidth="38" + android:viewportHeight="38"> + diff --git a/feature/tohot/src/main/res/drawable/ic_topic_placeholder_38.xml b/feature/tohot/src/main/res/drawable/ic_topic_placeholder_38.xml index b0cf3d58..f61aec9b 100644 --- a/feature/tohot/src/main/res/drawable/ic_topic_placeholder_38.xml +++ b/feature/tohot/src/main/res/drawable/ic_topic_placeholder_38.xml @@ -1,7 +1,9 @@ + android:width="38dp" + android:height="38dp" + android:viewportWidth="38" + android:viewportHeight="38"> + From 900f74b0d536f57a66ce066a177a30fb38442f05 Mon Sep 17 00:00:00 2001 From: wjchoi96 Date: Thu, 14 Sep 2023 16:06:59 +0900 Subject: [PATCH 05/12] =?UTF-8?q?design:TOP-77=20Topic=20placeholder=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=EC=BD=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/drawable/ic_topic_item_placeholder_48.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/feature/tohot/src/main/res/drawable/ic_topic_item_placeholder_48.xml b/feature/tohot/src/main/res/drawable/ic_topic_item_placeholder_48.xml index 3d193590..62c1e3a6 100644 --- a/feature/tohot/src/main/res/drawable/ic_topic_item_placeholder_48.xml +++ b/feature/tohot/src/main/res/drawable/ic_topic_item_placeholder_48.xml @@ -1,9 +1,9 @@ + android:width="46dp" + android:height="46dp" + android:viewportWidth="46" + android:viewportHeight="46"> + android:pathData="M23,23m-23,0a23,23 0,1 1,46 0a23,23 0,1 1,-46 0" + android:fillColor="#383838"/> From 9763a4e546c4a79753f3ef714bfc0e9913a451d1 Mon Sep 17 00:00:00 2001 From: wjchoi96 Date: Sun, 17 Sep 2023 17:04:21 +0900 Subject: [PATCH 06/12] remove:TOP-77 remove debug log --- .../java/com/example/compose_ui/extensions/ModifierExtension.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/compose-ui/src/main/java/com/example/compose_ui/extensions/ModifierExtension.kt b/core/compose-ui/src/main/java/com/example/compose_ui/extensions/ModifierExtension.kt index 7522f004..70bda5f0 100644 --- a/core/compose-ui/src/main/java/com/example/compose_ui/extensions/ModifierExtension.kt +++ b/core/compose-ui/src/main/java/com/example/compose_ui/extensions/ModifierExtension.kt @@ -1,6 +1,5 @@ package com.example.compose_ui.extensions -import android.util.Log import android.view.MotionEvent import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -35,7 +34,6 @@ fun Modifier.onDoubleTab( pointerInteropFilter { when (it.action) { MotionEvent.ACTION_UP -> { - Log.d("TAG", "onDoubleTab ACTION_UP") System.currentTimeMillis().let { now -> doubleTabTouchTimeMill = if (doubleTabTouchTimeMill != 0L && now - doubleTabTouchTimeMill <= doubleIntervalMill) { onDoubleTab() From efc6d1fc2bee56a80a4558c6b11d49b09ef0e0c9 Mon Sep 17 00:00:00 2001 From: wjchoi96 <55623699+wjchoi96@users.noreply.github.com> Date: Sun, 17 Sep 2023 17:52:11 +0900 Subject: [PATCH 07/12] =?UTF-8?q?fix:TOP-79=20android=5Fcd=EC=97=90=20loca?= =?UTF-8?q?l.properties=20=EB=B3=80=EA=B2=BD=EC=A0=90=20=EB=AF=B8=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/android_cd.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/android_cd.yml b/.github/workflows/android_cd.yml index e45e4780..a804a010 100644 --- a/.github/workflows/android_cd.yml +++ b/.github/workflows/android_cd.yml @@ -2,7 +2,7 @@ name: Android CD on: push: - branches: [main, qa] + branches: [main, qa, fix/TOP-79_android_cd] jobs: @@ -42,11 +42,19 @@ jobs: echo -e KAKAO_NATIVE_APP_KEY=\"$KAKAO_NATIVE_APP_KEY\" >> ./local.properties echo -e NAVER_CLIENT_ID=\"$NAVER_CLIENT_ID\" >> ./local.properties echo -e NAVER_CLIENT_SECRET=\"$NAVER_CLIENT_SECRET\" >> ./local.properties + echo -e REGION_CODE_SERVICE_KEY=\"REGION_CODE_SERVICE_KEY\" >> ./local.properties + echo -e APP_EMAIL_ID=\"APP_EMAIL_ID\" >> ./local.properties + echo -e APP_EMAIL_PASSWORD=\"APP_EMAIL_PASSWORD\" >> ./local.properties + echo -e CEO_EMAIL=\"CEO_EMAIL\" >> ./local.properties cat ./local.properties env: KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }} NAVER_CLIENT_SECRET: ${{ secrets.NAVER_CLIENT_SECRET }} NAVER_CLIENT_ID: ${{ secrets.NAVER_CLIENT_ID }} + REGION_CODE_SERVICE_KEY: ${{ secrets.REGION_CODE_SERVICE_KEY }} + APP_EMAIL_ID: ${{ secrets.APP_EMAIL_ID }} + APP_EMAIL_PASSWORD: ${{ secrets.APP_EMAIL_PASSWORD }} + CEO_EMAIL: ${{ secrets.CEO_EMAIL }} - name: Build with Gradle Without Test run: ./gradlew build -x test @@ -77,11 +85,19 @@ jobs: echo -e KAKAO_NATIVE_APP_KEY=\"$KAKAO_NATIVE_APP_KEY\" >> ./local.properties echo -e NAVER_CLIENT_ID=\"$NAVER_CLIENT_ID\" >> ./local.properties echo -e NAVER_CLIENT_SECRET=\"$NAVER_CLIENT_SECRET\" >> ./local.properties + echo -e REGION_CODE_SERVICE_KEY=\"REGION_CODE_SERVICE_KEY\" >> ./local.properties + echo -e APP_EMAIL_ID=\"APP_EMAIL_ID\" >> ./local.properties + echo -e APP_EMAIL_PASSWORD=\"APP_EMAIL_PASSWORD\" >> ./local.properties + echo -e CEO_EMAIL=\"CEO_EMAIL\" >> ./local.properties cat ./local.properties env: KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }} NAVER_CLIENT_SECRET: ${{ secrets.NAVER_CLIENT_SECRET }} NAVER_CLIENT_ID: ${{ secrets.NAVER_CLIENT_ID }} + REGION_CODE_SERVICE_KEY: ${{ secrets.REGION_CODE_SERVICE_KEY }} + APP_EMAIL_ID: ${{ secrets.APP_EMAIL_ID }} + APP_EMAIL_PASSWORD: ${{ secrets.APP_EMAIL_PASSWORD }} + CEO_EMAIL: ${{ secrets.CEO_EMAIL }} - name: Run unit tests run: ./gradlew testDebugUnitTest @@ -119,11 +135,19 @@ jobs: echo -e KAKAO_NATIVE_APP_KEY=\"$KAKAO_NATIVE_APP_KEY\" >> ./local.properties echo -e NAVER_CLIENT_ID=\"$NAVER_CLIENT_ID\" >> ./local.properties echo -e NAVER_CLIENT_SECRET=\"$NAVER_CLIENT_SECRET\" >> ./local.properties + echo -e REGION_CODE_SERVICE_KEY=\"REGION_CODE_SERVICE_KEY\" >> ./local.properties + echo -e APP_EMAIL_ID=\"APP_EMAIL_ID\" >> ./local.properties + echo -e APP_EMAIL_PASSWORD=\"APP_EMAIL_PASSWORD\" >> ./local.properties + echo -e CEO_EMAIL=\"CEO_EMAIL\" >> ./local.properties cat ./local.properties env: KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }} NAVER_CLIENT_SECRET: ${{ secrets.NAVER_CLIENT_SECRET }} NAVER_CLIENT_ID: ${{ secrets.NAVER_CLIENT_ID }} + REGION_CODE_SERVICE_KEY: ${{ secrets.REGION_CODE_SERVICE_KEY }} + APP_EMAIL_ID: ${{ secrets.APP_EMAIL_ID }} + APP_EMAIL_PASSWORD: ${{ secrets.APP_EMAIL_PASSWORD }} + CEO_EMAIL: ${{ secrets.CEO_EMAIL }} - name: Access APP_GOOGLE_SERVICES_JSON run: echo '${{ secrets.APP_GOOGLE_SERVICES_JSON }}' > ./app/google-services.json From bac65f4190093617ceaa3e3515f05b085f7c425c Mon Sep 17 00:00:00 2001 From: wjchoi96 <55623699+wjchoi96@users.noreply.github.com> Date: Sun, 17 Sep 2023 18:04:45 +0900 Subject: [PATCH 08/12] =?UTF-8?q?fix:TOP-79=20android=5Fcd=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=ED=85=8C=EC=8A=A4=ED=84=B0=20=EA=B7=B8=EB=A3=B9?= =?UTF-8?q?=EC=97=90=20tht-team=20=EC=B6=94=EA=B0=80=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/android_cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android_cd.yml b/.github/workflows/android_cd.yml index a804a010..ec0da103 100644 --- a/.github/workflows/android_cd.yml +++ b/.github/workflows/android_cd.yml @@ -173,7 +173,7 @@ jobs: with: appId: ${{secrets.FIREBASE_APP_ID}} serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }} - groups: android-developer + groups: android-developer, tht-team file: app/build/outputs/apk/release/app-release-unsigned-signed.apk releaseNotesFile: app/release_note.md From fd73a3b666e9266c9e39b048ab841f6bcb85ce80 Mon Sep 17 00:00:00 2001 From: wjchoi96 <55623699+wjchoi96@users.noreply.github.com> Date: Sun, 17 Sep 2023 18:11:54 +0900 Subject: [PATCH 09/12] =?UTF-8?q?fix:TOP-79=20android=5Fcd=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=EC=9D=84=20main,=20qa=EB=B8=8C=EB=9E=9C=EC=B9=98?= =?UTF-8?q?=EC=97=90=20push=EB=90=98=EC=97=88=EC=9D=84=20=EB=95=8C=20?= =?UTF-8?q?=EB=8F=99=EC=9E=91=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/android_cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android_cd.yml b/.github/workflows/android_cd.yml index ec0da103..b9ed2d8c 100644 --- a/.github/workflows/android_cd.yml +++ b/.github/workflows/android_cd.yml @@ -2,7 +2,7 @@ name: Android CD on: push: - branches: [main, qa, fix/TOP-79_android_cd] + branches: [main, qa] jobs: From 42988b6ce54ecf8d60789a2d204ba86a9c81780e Mon Sep 17 00:00:00 2001 From: "cwj5@troder.com" Date: Mon, 18 Sep 2023 22:09:38 +0900 Subject: [PATCH 10/12] =?UTF-8?q?fix:TOP-69=20location=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EC=8B=A4=ED=8C=A8=20=EB=94=94=EB=B2=84=EA=B9=85?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=B4=20=EC=98=88=EC=99=B8=20=EC=83=81?= =?UTF-8?q?=ED=99=A9=EC=9D=84=20ui=EC=97=90=20=ED=91=9C=EC=8B=9C.=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=83=81=ED=99=A9=20=EC=84=B8=EB=B6=84?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/tht/feature/signin/StringProvider.kt | 3 ++- .../tht/feature/signin/StringProviderImpl.kt | 1 + .../signup/location/LocationViewModel.kt | 26 +++++++++++++++---- .../signin/src/main/res/values/strings.xml | 2 ++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/feature/signin/src/main/java/tht/feature/signin/StringProvider.kt b/feature/signin/src/main/java/tht/feature/signin/StringProvider.kt index 7ecb5dd6..13343a8d 100644 --- a/feature/signin/src/main/java/tht/feature/signin/StringProvider.kt +++ b/feature/signin/src/main/java/tht/feature/signin/StringProvider.kt @@ -41,6 +41,7 @@ interface StringProvider { RegionCodeFetchFail, SignupFail, InvalidDate, - EmailSendFail + EmailSendFail, + SignupUserInvalidate } } diff --git a/feature/signin/src/main/java/tht/feature/signin/StringProviderImpl.kt b/feature/signin/src/main/java/tht/feature/signin/StringProviderImpl.kt index 4348c98b..40b7925d 100644 --- a/feature/signin/src/main/java/tht/feature/signin/StringProviderImpl.kt +++ b/feature/signin/src/main/java/tht/feature/signin/StringProviderImpl.kt @@ -53,6 +53,7 @@ class StringProviderImpl @Inject constructor( StringProvider.ResId.SignupFail -> R.string.message_signup_fail StringProvider.ResId.InvalidDate -> R.string.message_invalidate_date StringProvider.ResId.EmailSendFail -> R.string.message_email_send_fail + StringProvider.ResId.SignupUserInvalidate -> R.string.signup_user_invalidate } } } diff --git a/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt b/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt index 3b56cac5..49be5a53 100644 --- a/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt +++ b/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt @@ -2,6 +2,7 @@ package tht.feature.signin.signup.location import androidx.lifecycle.viewModelScope import com.tht.tht.domain.signup.model.LocationModel +import com.tht.tht.domain.signup.model.SignupException import com.tht.tht.domain.signup.usecase.FetchCurrentLocationUseCase import com.tht.tht.domain.signup.usecase.FetchLocationByAddressUseCase import com.tht.tht.domain.signup.usecase.PatchLocationUseCase @@ -112,13 +113,28 @@ class LocationViewModel @Inject constructor( _sideEffectFlow.emit(LocationSideEffect.NavigateNextView) }.onFailure { _sideEffectFlow.emit( - LocationSideEffect.ShowToast( - stringProvider.getString(StringProvider.ResId.LocationPatchFail) - ) + when (it) { + is SignupException.InvalidateLocationInfo -> { + LocationSideEffect.ShowToast( + stringProvider.getString(StringProvider.ResId.InvalidateLocation) + ) + } + + is SignupException.SignupUserInvalidateException -> { + LocationSideEffect.ShowToast( + stringProvider.getString(StringProvider.ResId.SignupUserInvalidate) + " $it" + ) + } + + else -> { + LocationSideEffect.ShowToast( + stringProvider.getString(StringProvider.ResId.LocationPatchFail) + " $it" + ) + } + } ) - }.also { - _dataLoading.value = false } + _dataLoading.value = false } } diff --git a/feature/signin/src/main/res/values/strings.xml b/feature/signin/src/main/res/values/strings.xml index b52a00ce..4e945857 100644 --- a/feature/signin/src/main/res/values/strings.xml +++ b/feature/signin/src/main/res/values/strings.xml @@ -122,4 +122,6 @@ 돌아가기 InquiryCompleteDialog + 회원가입 정보가 존재하지 않습니다 + From 3d5bc950c5083ec746f06ee174f8f18bc794cb28 Mon Sep 17 00:00:00 2001 From: "cwj5@troder.com" Date: Mon, 18 Sep 2023 22:12:28 +0900 Subject: [PATCH 11/12] =?UTF-8?q?refactor:TOP-69=20location=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EC=B2=B4=ED=81=AC=EB=A5=BC=20PatchLocatio?= =?UTF-8?q?nUseCase=20=EB=82=B4=EB=B6=80=EC=97=90=EC=84=9C=20=EC=8B=A4?= =?UTF-8?q?=EC=8B=9C=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/signup/model/SignupException.kt | 4 +++ .../signup/usecase/PatchLocationUseCase.kt | 3 ++ .../usecase/PatchLocationUseCaseImpl.kt | 28 +++++++++++++------ .../signup/location/LocationViewModel.kt | 10 ------- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/domain/src/main/java/com/tht/tht/domain/signup/model/SignupException.kt b/domain/src/main/java/com/tht/tht/domain/signup/model/SignupException.kt index ec030320..2f88de9f 100644 --- a/domain/src/main/java/com/tht/tht/domain/signup/model/SignupException.kt +++ b/domain/src/main/java/com/tht/tht/domain/signup/model/SignupException.kt @@ -2,6 +2,10 @@ package com.tht.tht.domain.signup.model sealed interface SignupException { + data class InvalidateLocationInfo( + override val message: String? = "location data is invalidate" + ): SignupException, Exception() + data class SignupUserInvalidateException( override val message: String? = "signup user data is invalidate" ): SignupException, IllegalArgumentException() diff --git a/domain/src/main/java/com/tht/tht/domain/signup/usecase/PatchLocationUseCase.kt b/domain/src/main/java/com/tht/tht/domain/signup/usecase/PatchLocationUseCase.kt index 7dbc4b9f..a26d3924 100644 --- a/domain/src/main/java/com/tht/tht/domain/signup/usecase/PatchLocationUseCase.kt +++ b/domain/src/main/java/com/tht/tht/domain/signup/usecase/PatchLocationUseCase.kt @@ -18,6 +18,9 @@ class PatchLocationUseCase( address: String ): Result { return kotlin.runCatching { + if (lat < 0.0 || lng < 0.0 || address.isBlank()) { + throw SignupException.InvalidateLocationInfo() + } withContext(dispatcher) { val regionCode = fetchRegionCodeUseCase(address).getOrThrow().regionCode repository.patchSignupUser( diff --git a/domain/src/test/java/com/tht/tht/domain/signup/usecase/PatchLocationUseCaseImpl.kt b/domain/src/test/java/com/tht/tht/domain/signup/usecase/PatchLocationUseCaseImpl.kt index 5029b399..0bf9eefb 100644 --- a/domain/src/test/java/com/tht/tht/domain/signup/usecase/PatchLocationUseCaseImpl.kt +++ b/domain/src/test/java/com/tht/tht/domain/signup/usecase/PatchLocationUseCaseImpl.kt @@ -37,7 +37,7 @@ internal class PatchLocationUseCaseImpl { @Test fun `useCase는 FetchRegionCodeUseCase의 invoke()를 호출한다`() = runTest(testDispatcher) { - patchLocationUseCase("phone", 0.0, 0.0, "") + patchLocationUseCase("phone", 10.0, 127.0, "address") coVerify(exactly = 1) { fetchRegionCodeUseCase(any()) } } @@ -46,7 +46,7 @@ internal class PatchLocationUseCaseImpl { val unitTestException = Exception("unit test") coEvery { fetchRegionCodeUseCase(any()) } throws unitTestException - val actual = patchLocationUseCase("phone", 0.0, 0.0, "") + val actual = patchLocationUseCase("phone", 10.0, 127.0, "address") Assertions.assertThat(actual) .isInstanceOf(Result::class.java) @@ -56,9 +56,21 @@ internal class PatchLocationUseCaseImpl { .isEqualTo(unitTestException.message) } + @Test + fun `useCase는 lat, lng, address가 유효하지 않으면 InvalidateLocationInfo를 Result로 래핑해 리턴한다`() = runTest(testDispatcher) { + val actual = patchLocationUseCase("phone", 0.0, 0.0, "") + + Assertions.assertThat(actual) + .isInstanceOf(Result::class.java) + + Assertions.assertThat(actual.exceptionOrNull()) + .isNotNull + .isInstanceOf(SignupException.InvalidateLocationInfo::class.java) + } + @Test fun `useCase는 repository의 fetchSignupUser를 호출한다`() = runTest(testDispatcher) { - patchLocationUseCase("phone", 0.0, 0.0, "") + patchLocationUseCase("phone", 10.0, 127.0, "address") coEvery { fetchRegionCodeUseCase(any()) } returns kotlin.runCatching { RegionCodeModel("0") } coVerify(exactly = 1) { fetchRegionCodeUseCase(any()) } } @@ -69,7 +81,7 @@ internal class PatchLocationUseCaseImpl { coEvery { fetchRegionCodeUseCase(any()) } returns kotlin.runCatching { RegionCodeModel("0") } coEvery { repository.fetchSignupUser(any()) } throws unitTestException - val actual = patchLocationUseCase("phone", 0.0, 0.0, "") + val actual = patchLocationUseCase("phone", 10.0, 127.0, "address") Assertions.assertThat(actual) .isInstanceOf(Result::class.java) @@ -86,7 +98,7 @@ internal class PatchLocationUseCaseImpl { } coEvery { repository.fetchSignupUser(any()) } returns null - val actual = patchLocationUseCase("phone", 0.0, 0.0, "") + val actual = patchLocationUseCase("phone", 10.0, 127.0, "address") Assertions.assertThat(actual) .isInstanceOf(Result::class.java) @@ -100,7 +112,7 @@ internal class PatchLocationUseCaseImpl { fun `useCase는 fetchSignupUser리턴 값이 유효하면 patchSignupUser를 호출한다`() = runTest(testDispatcher) { coEvery { fetchRegionCodeUseCase(any()) } returns kotlin.runCatching { RegionCodeModel("0") } coEvery { repository.fetchSignupUser(any()) } returns SignupUserModel.getFromDefaultArgument() - patchLocationUseCase("phone", 0.0, 0.0, "") + patchLocationUseCase("phone", 10.0, 127.0, "address") coVerify { repository.patchSignupUser(any(), any()) } } @@ -110,7 +122,7 @@ internal class PatchLocationUseCaseImpl { coEvery { repository.patchSignupUser(any(), any()) } throws unitTestException coEvery { repository.fetchSignupUser(any()) } returns SignupUserModel.getFromDefaultArgument() coEvery { fetchRegionCodeUseCase(any()) } returns kotlin.runCatching { RegionCodeModel("0") } - val actual = patchLocationUseCase("phone", 0.0, 0.0, "") + val actual = patchLocationUseCase("phone", 10.0, 127.0, "address") Assertions.assertThat(actual) .isInstanceOf(Result::class.java) @@ -126,7 +138,7 @@ internal class PatchLocationUseCaseImpl { coEvery { repository.patchSignupUser(any(), any()) } returns expect coEvery { repository.fetchSignupUser(any()) } returns SignupUserModel.getFromDefaultArgument() coEvery { fetchRegionCodeUseCase(any()) } returns kotlin.runCatching { RegionCodeModel("0") } - val actual = patchLocationUseCase("phone", 0.0, 0.0, "") + val actual = patchLocationUseCase("phone", 10.0, 127.0, "address") Assertions.assertThat(actual) .isInstanceOf(Result::class.java) diff --git a/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt b/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt index 49be5a53..3f3089c2 100644 --- a/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt +++ b/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt @@ -93,16 +93,6 @@ class LocationViewModel @Inject constructor( fun nextEvent(phone: String) { viewModelScope.launch { - fullLocation.value.run { - if (lat < 0.0 || lng < 0.0 || address.isBlank()) { - _sideEffectFlow.emit( - LocationSideEffect.ShowToast( - stringProvider.getString(StringProvider.ResId.InvalidateLocation) - ) - ) - return@launch - } - } _dataLoading.value = true patchLocationUseCase( phone, From 192a39a9d3ac459560481dbd9809941de79a9190 Mon Sep 17 00:00:00 2001 From: "cwj5@troder.com" Date: Mon, 18 Sep 2023 22:24:43 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:TOP-83=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/location/LocationViewModel.kt | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt b/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt index 3f3089c2..28e74bd3 100644 --- a/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt +++ b/feature/signin/src/main/java/tht/feature/signin/signup/location/LocationViewModel.kt @@ -103,25 +103,21 @@ class LocationViewModel @Inject constructor( _sideEffectFlow.emit(LocationSideEffect.NavigateNextView) }.onFailure { _sideEffectFlow.emit( - when (it) { - is SignupException.InvalidateLocationInfo -> { - LocationSideEffect.ShowToast( + LocationSideEffect.ShowToast( + when (it) { + is SignupException.InvalidateLocationInfo -> { stringProvider.getString(StringProvider.ResId.InvalidateLocation) - ) - } + } - is SignupException.SignupUserInvalidateException -> { - LocationSideEffect.ShowToast( + is SignupException.SignupUserInvalidateException -> { stringProvider.getString(StringProvider.ResId.SignupUserInvalidate) + " $it" - ) - } + } - else -> { - LocationSideEffect.ShowToast( + else -> { stringProvider.getString(StringProvider.ResId.LocationPatchFail) + " $it" - ) + } } - } + ) ) } _dataLoading.value = false