From 2a750e7f941de725099b70ccaae55768c7c2a256 Mon Sep 17 00:00:00 2001 From: Namyunsuk <84739562+Namyunsuk@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:10:59 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EA=B3=B5=EB=AA=A8=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D,=20=EA=B3=B5=EB=AA=A8=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B8=EB=93=A4=EB=A7=81=20(#418)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 공모 목록에서 401에러를 제외하고는 에러코드 올 시 빈화면 보여주도록 에러핸들링 수정 * refactor: 필터및 업데이트된 공모 목록 가져오는 로직 에러핸들링 수정 - 400: 토스트 메시지 띄어줌 - 401: refresh - 그외에는 로그로 에러 코드를 보여줌 * refactor: strings네이밍 통일 * refactor: 공모 상세 에러 핸들링 수정 * refactor: strings정리 - offering_detail부분 정리 --- .../domain/paging/OfferingPagingSource.kt | 21 ++++++- .../presentation/util/BindingAdapters.kt | 22 +++---- .../presentation/view/home/HomeFragment.kt | 20 +++++++ .../view/home/OfferingViewModel.kt | 23 +++++++- .../offeringdetail/OfferingDetailFragment.kt | 20 +++++++ .../offeringdetail/OfferingDetailViewModel.kt | 20 ++++++- .../app/src/main/res/layout/fragment_home.xml | 2 +- .../res/layout/fragment_offering_detail.xml | 10 ++-- .../app/src/main/res/layout/item_offering.xml | 6 +- android/app/src/main/res/values/strings.xml | 57 ++++++++++--------- android/app/src/main/res/values/style.xml | 6 +- 11 files changed, 150 insertions(+), 57 deletions(-) diff --git a/android/app/src/main/java/com/zzang/chongdae/domain/paging/OfferingPagingSource.kt b/android/app/src/main/java/com/zzang/chongdae/domain/paging/OfferingPagingSource.kt index c63179bd..b07e7afd 100644 --- a/android/app/src/main/java/com/zzang/chongdae/domain/paging/OfferingPagingSource.kt +++ b/android/app/src/main/java/com/zzang/chongdae/domain/paging/OfferingPagingSource.kt @@ -5,6 +5,7 @@ import androidx.paging.PagingState import com.zzang.chongdae.domain.model.Offering import com.zzang.chongdae.domain.repository.AuthRepository import com.zzang.chongdae.domain.repository.OfferingRepository +import com.zzang.chongdae.domain.util.DataError import com.zzang.chongdae.domain.util.Result class OfferingPagingSource( @@ -27,9 +28,23 @@ class OfferingPagingSource( when (offerings) { is Result.Error -> { - authRepository.saveRefresh() - retry() - load(params) + when (offerings.error) { + DataError.Network.UNAUTHORIZED -> { + authRepository.saveRefresh() + retry() + load(params) + } + + else -> { + val prevKey: Long? = null + val nextKey: Long? = null + LoadResult.Page( + data = emptyList(), + prevKey = prevKey, + nextKey = nextKey, + ) + } + } } is Result.Success -> { diff --git a/android/app/src/main/java/com/zzang/chongdae/presentation/util/BindingAdapters.kt b/android/app/src/main/java/com/zzang/chongdae/presentation/util/BindingAdapters.kt index e254238d..35fcd013 100644 --- a/android/app/src/main/java/com/zzang/chongdae/presentation/util/BindingAdapters.kt +++ b/android/app/src/main/java/com/zzang/chongdae/presentation/util/BindingAdapters.kt @@ -131,10 +131,10 @@ private fun OfferingCondition.toOfferingComment( context: Context, remaining: Int, ) = when (this) { - OfferingCondition.FULL -> context.getString(R.string.main_offering_condition_full_comment) + OfferingCondition.FULL -> context.getString(R.string.home_offering_condition_full_comment) OfferingCondition.IMMINENT -> Html.fromHtml( - context.getString(R.string.main_offering_condition_continue_comment) + context.getString(R.string.home_offering_condition_continue_comment) .format(remaining), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE, ) @@ -171,10 +171,10 @@ private fun TextView.setColor(colorId: Int) { private fun OfferingCondition.toOfferingConditionText(context: Context) = when (this) { - OfferingCondition.FULL -> context.getString(R.string.main_offering_full) // 인원 만석 - OfferingCondition.IMMINENT -> context.getString(R.string.main_offering_imminent) // 마감임박 - OfferingCondition.CONFIRMED -> context.getString(R.string.main_offering_closed) // 공구마감 - OfferingCondition.AVAILABLE -> context.getString(R.string.main_offering_continue) // 모집중 + OfferingCondition.FULL -> context.getString(R.string.home_offering_full) // 인원 만석 + OfferingCondition.IMMINENT -> context.getString(R.string.home_offering_imminent) // 마감임박 + OfferingCondition.CONFIRMED -> context.getString(R.string.home_offering_closed) // 공구마감 + OfferingCondition.AVAILABLE -> context.getString(R.string.home_offering_continue) // 모집중 } private fun OfferingCondition.toStyle() = @@ -193,7 +193,7 @@ fun View.setIsVisible(isVisible: Boolean) { @BindingAdapter("formattedDate") fun TextView.bindFormattedDate(datetime: LocalDateTime?) { this.text = - datetime?.format(DateTimeFormatter.ofPattern(context.getString(R.string.due_datetime))) + datetime?.format(DateTimeFormatter.ofPattern(context.getString(R.string.all_due_datetime))) } @BindingAdapter("currentCount", "totalCount", "condition") @@ -210,18 +210,18 @@ private fun OfferingCondition.toOfferingConditionText( currentCount: Int, totalCount: Int, ) = when (this) { - OfferingCondition.FULL -> context.getString(R.string.participant_full) + OfferingCondition.FULL -> context.getString(R.string.offering_detail_participant_full) OfferingCondition.IMMINENT -> context.getString( - R.string.participant_count, + R.string.offering_detail_participant_count, currentCount, totalCount, ) - OfferingCondition.CONFIRMED -> context.getString(R.string.participant_end) + OfferingCondition.CONFIRMED -> context.getString(R.string.offering_detail_participant_end) OfferingCondition.AVAILABLE -> context.getString( - R.string.participant_count, + R.string.offering_detail_participant_count, currentCount, totalCount, ) diff --git a/android/app/src/main/java/com/zzang/chongdae/presentation/view/home/HomeFragment.kt b/android/app/src/main/java/com/zzang/chongdae/presentation/view/home/HomeFragment.kt index 88477c45..46287fb1 100644 --- a/android/app/src/main/java/com/zzang/chongdae/presentation/view/home/HomeFragment.kt +++ b/android/app/src/main/java/com/zzang/chongdae/presentation/view/home/HomeFragment.kt @@ -7,6 +7,8 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo import android.widget.CheckBox +import android.widget.Toast +import androidx.annotation.StringRes import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.setFragmentResultListener @@ -34,6 +36,7 @@ import kotlinx.coroutines.launch class HomeFragment : Fragment(), OnOfferingClickListener { private var _binding: FragmentHomeBinding? = null private val binding get() = _binding!! + private var toast: Toast? = null private lateinit var offeringAdapter: OfferingAdapter private val viewModel: OfferingViewModel by viewModels { @@ -88,6 +91,10 @@ class HomeFragment : Fragment(), OnOfferingClickListener { viewModel.selectedFilter.observe(viewLifecycleOwner) { selectedFilter -> updateCheckBoxStates(selectedFilter) } + + viewModel.error.observe(viewLifecycleOwner) { errMsgId -> + showToast(errMsgId) + } } private fun handleCheckBoxSelection( @@ -219,6 +226,19 @@ class HomeFragment : Fragment(), OnOfferingClickListener { } } + private fun showToast( + @StringRes messageId: Int, + ) { + toast?.cancel() + toast = + Toast.makeText( + requireActivity(), + getString(messageId), + Toast.LENGTH_SHORT, + ) + toast?.show() + } + companion object { const val OFFERING_ID = "offering_id" } diff --git a/android/app/src/main/java/com/zzang/chongdae/presentation/view/home/OfferingViewModel.kt b/android/app/src/main/java/com/zzang/chongdae/presentation/view/home/OfferingViewModel.kt index f202656c..28f0c652 100644 --- a/android/app/src/main/java/com/zzang/chongdae/presentation/view/home/OfferingViewModel.kt +++ b/android/app/src/main/java/com/zzang/chongdae/presentation/view/home/OfferingViewModel.kt @@ -1,5 +1,6 @@ package com.zzang.chongdae.presentation.view.home +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -12,6 +13,7 @@ import androidx.paging.PagingConfig import androidx.paging.PagingData import androidx.paging.cachedIn import androidx.paging.map +import com.zzang.chongdae.R import com.zzang.chongdae.domain.model.Filter import com.zzang.chongdae.domain.model.FilterName import com.zzang.chongdae.domain.model.Offering @@ -68,6 +70,9 @@ class OfferingViewModel( private val _offeringsRefreshEvent: MutableSingleLiveData = MutableSingleLiveData() val offeringsRefreshEvent: SingleLiveData get() = _offeringsRefreshEvent + private val _error: MutableSingleLiveData = MutableSingleLiveData() + val error: SingleLiveData get() = _error + init { fetchOfferings() fetchFilters() @@ -127,7 +132,14 @@ class OfferingViewModel( authRepository.saveRefresh() fetchFilters() } - else -> DataError.Network.UNKNOWN + + DataError.Network.BAD_REQUEST -> { + _error.setValue(R.string.home_filter_error_message) + } + + else -> { + Log.e("error", "fetchFilters Error: ${result.error.name}") + } } } @@ -166,7 +178,14 @@ class OfferingViewModel( authRepository.saveRefresh() fetchUpdatedOffering(offeringId) } - else -> DataError.Network.UNKNOWN + + DataError.Network.BAD_REQUEST -> { + _error.setValue(R.string.home_updated_offering_error_mesasge) + } + + else -> { + Log.e("error", "fetchUpdatedOffering Error: ${result.error.name}") + } } } diff --git a/android/app/src/main/java/com/zzang/chongdae/presentation/view/offeringdetail/OfferingDetailFragment.kt b/android/app/src/main/java/com/zzang/chongdae/presentation/view/offeringdetail/OfferingDetailFragment.kt index 96c67ec9..3ae8d1c0 100644 --- a/android/app/src/main/java/com/zzang/chongdae/presentation/view/offeringdetail/OfferingDetailFragment.kt +++ b/android/app/src/main/java/com/zzang/chongdae/presentation/view/offeringdetail/OfferingDetailFragment.kt @@ -6,6 +6,8 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast +import androidx.annotation.StringRes import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.fragment.app.setFragmentResult @@ -21,6 +23,7 @@ import com.zzang.chongdae.presentation.view.home.HomeFragment class OfferingDetailFragment : Fragment() { private var _binding: FragmentOfferingDetailBinding? = null private val binding get() = _binding!! + private var toast: Toast? = null private val offeringId by lazy { arguments?.getLong(HomeFragment.OFFERING_ID) ?: throw IllegalArgumentException() @@ -69,6 +72,10 @@ class OfferingDetailFragment : Fragment() { openUrlInBrowser(getString(reportUrlId)) } + viewModel.error.observe(viewLifecycleOwner) { errMsgId -> + showToast(errMsgId) + } + viewModel.productLinkRedirectEvent.observe(viewLifecycleOwner) { productURL -> openUrlInBrowser(productURL) } @@ -108,6 +115,19 @@ class OfferingDetailFragment : Fragment() { } } + private fun showToast( + @StringRes messageId: Int, + ) { + toast?.cancel() + toast = + Toast.makeText( + requireActivity(), + getString(messageId), + Toast.LENGTH_SHORT, + ) + toast?.show() + } + companion object { const val OFFERING_DETAIL_BUNDLE_KEY = "offering_detail_bundle_key" const val UPDATED_OFFERING_ID_KEY = "updated_offering_id" diff --git a/android/app/src/main/java/com/zzang/chongdae/presentation/view/offeringdetail/OfferingDetailViewModel.kt b/android/app/src/main/java/com/zzang/chongdae/presentation/view/offeringdetail/OfferingDetailViewModel.kt index 655e16af..cf65a7a1 100644 --- a/android/app/src/main/java/com/zzang/chongdae/presentation/view/offeringdetail/OfferingDetailViewModel.kt +++ b/android/app/src/main/java/com/zzang/chongdae/presentation/view/offeringdetail/OfferingDetailViewModel.kt @@ -1,5 +1,6 @@ package com.zzang.chongdae.presentation.view.offeringdetail +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -57,6 +58,9 @@ class OfferingDetailViewModel( private val _productLinkRedirectEvent: MutableSingleLiveData = MutableSingleLiveData() val productLinkRedirectEvent: SingleLiveData get() = _productLinkRedirectEvent + private val _error: MutableSingleLiveData = MutableSingleLiveData() + val error: SingleLiveData get() = _error + init { loadOffering() } @@ -71,7 +75,13 @@ class OfferingDetailViewModel( loadOffering() } - else -> DataError.Network.UNKNOWN + DataError.Network.BAD_REQUEST -> { + _error.setValue(R.string.offering_detail_load_error_mesage) + } + + else -> { + Log.e("error", "loadOffering Error: ${result.error.name}") + } } is Result.Success -> { @@ -97,7 +107,13 @@ class OfferingDetailViewModel( onClickParticipation() } - else -> DataError.Network.UNKNOWN + DataError.Network.BAD_REQUEST -> { + _error.setValue(R.string.offering_detail_participation_error) + } + + else -> { + Log.e("error", "onClickParticipation Error: ${result.error.name}") + } } is Result.Success -> { diff --git a/android/app/src/main/res/layout/fragment_home.xml b/android/app/src/main/res/layout/fragment_home.xml index 8652b349..3dce35e2 100644 --- a/android/app/src/main/res/layout/fragment_home.xml +++ b/android/app/src/main/res/layout/fragment_home.xml @@ -24,7 +24,7 @@ android:layout_marginTop="28dp" android:backgroundTint="@color/main_color" android:fontFamily="@font/suit_medium" - android:hint="@string/main_search_hint_text" + android:hint="@string/home_search_hint_text" android:inputType="text" android:paddingStart="15dp" android:paddingEnd="30dp" diff --git a/android/app/src/main/res/layout/fragment_offering_detail.xml b/android/app/src/main/res/layout/fragment_offering_detail.xml index d260b38f..28b2df20 100644 --- a/android/app/src/main/res/layout/fragment_offering_detail.xml +++ b/android/app/src/main/res/layout/fragment_offering_detail.xml @@ -153,7 +153,7 @@ android:id="@+id/tv_product_link_comment" style="@style/Theme.AppCompat.TextView.Bold.Gray900.Size16" android:layout_marginTop="18dp" - android:text="@string/detail_product_url_title" + android:text="@string/offering_detail_product_url_title" app:isVisible="@{vm.offeringDetail.productUrl != null}" app:layout_constraintBottom_toTopOf="@id/horizon_line" app:layout_constraintStart_toStartOf="@id/tv_title" @@ -163,8 +163,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/suit_bold" + android:text="@string/offering_detail_product_url_text" android:onClick="@{() -> vm.onClickProductRedirectText(vm.offeringDetail.productUrl)}" - android:text="@string/detail_product_url_text" android:textColor="@color/main_color" android:textSize="16sp" app:isVisible="@{vm.offeringDetail.productUrl != null}" @@ -197,7 +197,7 @@ style="@style/Theme.AppCompat.TextView.Bold.Gray900.Size16" android:layout_marginStart="8dp" android:layout_marginTop="15dp" - android:text="@string/detail_divided_money_title" + android:text="@string/offering_detail_divided_money_title" app:layout_constraintBottom_toBottomOf="@id/iv_money" app:layout_constraintStart_toEndOf="@id/iv_money" app:layout_constraintTop_toBottomOf="@id/horizon_line" /> @@ -222,7 +222,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="8dp" android:fontFamily="@font/suit_medium" - android:text="@{@string/total_price(vm.offeringDetail.totalPrice)}" + android:text="@{@string/offering_detail_total_price(vm.offeringDetail.totalPrice)}" android:textColor="@color/gray_500" android:textSize="11sp" app:layout_constraintBottom_toBottomOf="@id/tv_divided_price" @@ -374,7 +374,7 @@ android:background="@drawable/btn_participation_opened" android:fontFamily="@font/suit_medium" android:onClick="@{() -> vm.onClickMoveCommentDetail()}" - android:text="@string/detail_move_comment_detail" + android:text="@string/offering_detail_move_comment_detail" android:textColor="@color/white" app:isVisible="@{vm.isParticipated}" app:layout_constraintBottom_toBottomOf="parent" diff --git a/android/app/src/main/res/layout/item_offering.xml b/android/app/src/main/res/layout/item_offering.xml index b08cc70f..6ac785cb 100644 --- a/android/app/src/main/res/layout/item_offering.xml +++ b/android/app/src/main/res/layout/item_offering.xml @@ -58,7 +58,7 @@ app:layout_constraintStart_toStartOf="@id/iv_product" app:layout_constraintTop_toTopOf="@id/iv_product" app:offeringCondition="@{offering.status}" - tools:text="@string/main_offering_closed" /> + tools:text="@string/home_offering_closed" /> @@ -119,7 +119,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="5dp" - android:text='@{offering.originPrice != null ? @string/main_discount_rate_text(offering.calculateDiscountRate()) : ""}' + android:text='@{offering.originPrice != null ? @string/home_discount_rate_text(offering.calculateDiscountRate()) : ""}' android:textColor="@color/main_color" android:textSize="@dimen/size_13" android:textStyle="bold" diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 7e3785bf..64aea96c 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -24,6 +24,8 @@ 취소하기 확정하기 https://docs.google.com/forms/d/e/1FAIpQLSdyHhWqwY0-iJsa6MrbD2f3rdES4dhXekkRbQ2T3HmnIgV1TA/viewform + yyyy년 M월 d일 + 카카오톡으로 \n간편하게 공동구매 시작하기 @@ -34,40 +36,42 @@ 채팅방 마이페이지 - - 검색할 내용을 입력해주세요. - 모집중 - 모집마감 - 마감임박 - 인원만석 - 마감이 얼마 안남았어요! - 공구가 마감되었어요. - 인원이 빠질 수도 있어요 - 마감까지 <font color="#F15642">%d명 </font> 남았어요 - %.1f%%↓ - %,d원 + + 검색할 내용을 입력해주세요. + 모집중 + 모집마감 + 마감임박 + 인원만석 + 마감이 얼마 안남았어요! + 공구가 마감되었어요. + 인원이 빠질 수도 있어요 + 마감까지 <font color="#F15642">%d명 </font> 남았어요 + %.1f%%↓ + 필터 정보를 불러올 수 없습니다. + 업데이트된 공모 목록을 가져올 수 없습니다. 안녕하세요 - - - 물품 링크:  - 바로가기 - 엔빵 가격 - - 마이페이지 - 내가 올린 공구 - (총 가격 %,d원) - yyyy년 M월 d일 이용약관 개인정보처리 방침 로그아웃 회원 탈퇴 - 참여하기(%d/%d) - 인원이 다 찼어요! - 이미 참여중이에요! - 마감되었어요! + 마이페이지 + 내가 올린 공구 + + + 물품 링크:  + 바로가기 + 해당 공모가 존재하지 않습니다. + 엔빵 가격 + 참여중인 채팅방 + (총 가격 %,d원) + 참여하기(%d/%d) + 인원이 다 찼어요! + 참여할 수 없는 공모입니다. + 이미 참여중이에요! + 마감되었어요! 채팅 @@ -134,5 +138,4 @@ 공모 게시에 실패했어요🥲 공동구매 진행 상황변경하시겠습니까? 현재 엔빵 가격: %,d원 - 참여중인 채팅방 diff --git a/android/app/src/main/res/values/style.xml b/android/app/src/main/res/values/style.xml index 43f74524..d6a77ac5 100644 --- a/android/app/src/main/res/values/style.xml +++ b/android/app/src/main/res/values/style.xml @@ -38,7 +38,7 @@ wrap_content wrap_content @dimen/size_12 - @string/main_offering_continue + @string/home_offering_continue @font/suit_bold @color/white @@ -46,7 +46,7 @@