From 84390a31fb9d34f4f6e499738ca6a39193170bff Mon Sep 17 00:00:00 2001 From: Yu Jin Date: Mon, 2 Dec 2024 13:54:33 +0900 Subject: [PATCH 1/5] add: bottomSheetDialogFragment --- .../myreview/MyReviewBottomSheetFragment.kt | 104 ++++++++++++++++++ .../review/delete/MyReviewDialogActivity.kt | 84 -------------- app/src/main/res/drawable/ic_pencil.xml | 13 +++ app/src/main/res/drawable/ic_remove.xml | 13 +++ .../res/layout/activity_my_review_dialog.xml | 25 ----- .../layout/fragment_bottomsheet_my_review.xml | 88 +++++++++++++++ 6 files changed, 218 insertions(+), 109 deletions(-) create mode 100644 app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewBottomSheetFragment.kt delete mode 100644 app/src/main/java/com/eatssu/android/presentation/review/delete/MyReviewDialogActivity.kt create mode 100644 app/src/main/res/drawable/ic_pencil.xml create mode 100644 app/src/main/res/drawable/ic_remove.xml delete mode 100644 app/src/main/res/layout/activity_my_review_dialog.xml create mode 100644 app/src/main/res/layout/fragment_bottomsheet_my_review.xml diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewBottomSheetFragment.kt new file mode 100644 index 00000000..e0bb72eb --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewBottomSheetFragment.kt @@ -0,0 +1,104 @@ +package com.eatssu.android.presentation.mypage.myreview + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.lifecycleScope +import com.eatssu.android.App +import com.eatssu.android.R +import com.eatssu.android.databinding.FragmentBottomsheetMyReviewBinding +import com.eatssu.android.presentation.review.modify.ModifyReviewActivity +import com.eatssu.android.presentation.util.showToast +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import timber.log.Timber + +@AndroidEntryPoint +class MyReviewBottomSheetFragment : BottomSheetDialogFragment() { + private var _binding: FragmentBottomsheetMyReviewBinding? = null + private val binding get() = _binding!! + + private val viewModel: MyReviewViewModel by activityViewModels() + + var reviewId = -1L + var menu = "" + var content = "" + var mainGrade = -1 + var amountGrade = -1 + var tasteGrade = -1 + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentBottomsheetMyReviewBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val intent = Intent(requireContext(), ModifyReviewActivity::class.java) + +// reviewId = intent.getLongExtra("reviewId", -1L) +// menu = intent.getStringExtra("menu").toString() +// content = intent.getStringExtra("content").toString() +// mainGrade = intent.getIntExtra("mainGrade", -1) +// amountGrade = intent.getIntExtra("amountGrade", -1) +// tasteGrade = intent.getIntExtra("tasteGrade", -1) + + reviewId = arguments?.getLong("reviewId")!! + menu = arguments?.getString("menu").toString() + content = arguments?.getString("content").toString() + + mainGrade = arguments?.getInt("mainGrade")!! + amountGrade = arguments?.getInt("amountGrade")!! + tasteGrade = arguments?.getInt("tasteGrade")!! + + + + Timber.d("전:" + reviewId.toString()) + Timber.d("전:" + menu) + Timber.d("전:" + content) + Timber.d(reviewId.toString()) + + binding.llModify.setOnClickListener { + intent.putExtra("reviewId", reviewId) + intent.putExtra("menu", menu) + intent.putExtra("content", content) + intent.putExtra("mainGrade", mainGrade) + intent.putExtra("amountGrade", amountGrade) + intent.putExtra("tasteGrade", tasteGrade) + + startActivity(intent) + } + + binding.llDelete.setOnClickListener { + AlertDialog.Builder(requireContext()).apply { + setTitle(R.string.delete) + setMessage(R.string.delete_description) + setNegativeButton("취소") { _, _ -> + activity?.showToast(App.appContext.getString(R.string.delete_undo)) + } + setPositiveButton("삭제") { _, _ -> + viewModel.deleteReview(reviewId) + lifecycleScope.launch { + viewModel.uiState.collectLatest { + if (it.isDeleted) { +// finish() + } + } + } + } + }.create().show() + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/review/delete/MyReviewDialogActivity.kt b/app/src/main/java/com/eatssu/android/presentation/review/delete/MyReviewDialogActivity.kt deleted file mode 100644 index 57313a79..00000000 --- a/app/src/main/java/com/eatssu/android/presentation/review/delete/MyReviewDialogActivity.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.eatssu.android.presentation.review.delete - -import android.content.Intent -import android.os.Bundle -import androidx.activity.viewModels -import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.lifecycleScope -import com.eatssu.android.App -import com.eatssu.android.R -import com.eatssu.android.databinding.ActivityMyReviewDialogBinding -import com.eatssu.android.presentation.review.modify.ModifyReviewActivity -import com.eatssu.android.presentation.util.showToast -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import timber.log.Timber - -@AndroidEntryPoint -class MyReviewDialogActivity : AppCompatActivity() { - private lateinit var binding: ActivityMyReviewDialogBinding - - private val deleteViewModel: DeleteViewModel by viewModels() - - var reviewId = -1L - var menu = "" - var content = "" - var mainGrade = -1 - var amountGrade = -1 - var tasteGrade = -1 - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - binding = ActivityMyReviewDialogBinding.inflate(layoutInflater) - setContentView(binding.root) - - reviewId = intent.getLongExtra("reviewId", -1L) - menu = intent.getStringExtra("menu").toString() - content = intent.getStringExtra("content").toString() - mainGrade = intent.getIntExtra("mainGrade", -1) - amountGrade = intent.getIntExtra("amountGrade", -1) - tasteGrade = intent.getIntExtra("tasteGrade", -1) - - Timber.d("전:" + reviewId.toString()) - Timber.d("전:" + menu.toString()) - Timber.d("전:" + content.toString()) - Timber.d(reviewId.toString()) - - binding.btnReviewFix.setOnClickListener { - val intent = Intent(this, ModifyReviewActivity::class.java) - intent.putExtra("reviewId", reviewId) - intent.putExtra("menu", menu) - intent.putExtra("content", content) - intent.putExtra("mainGrade", mainGrade) - intent.putExtra("amountGrade", amountGrade) - intent.putExtra("tasteGrade", tasteGrade) - - startActivity(intent) - finish() - } - - binding.btnReviewDelete.setOnClickListener { - AlertDialog.Builder(this).apply { - setTitle(R.string.delete) - setMessage(R.string.delete_description) - setNegativeButton("취소") { _, _ -> - showToast(App.appContext.getString(R.string.delete_undo)) - } - setPositiveButton("삭제") { _, _ -> - deleteViewModel.deleteReview(reviewId) - lifecycleScope.launch { - deleteViewModel.uiState.collectLatest { - if (it.isDeleted) { - finish() - } - } - } - } - }.create().show() - - } - } -} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_pencil.xml b/app/src/main/res/drawable/ic_pencil.xml new file mode 100644 index 00000000..c04bdf61 --- /dev/null +++ b/app/src/main/res/drawable/ic_pencil.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/ic_remove.xml b/app/src/main/res/drawable/ic_remove.xml new file mode 100644 index 00000000..3fe37ca3 --- /dev/null +++ b/app/src/main/res/drawable/ic_remove.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/layout/activity_my_review_dialog.xml b/app/src/main/res/layout/activity_my_review_dialog.xml deleted file mode 100644 index 1f8a10c4..00000000 --- a/app/src/main/res/layout/activity_my_review_dialog.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_bottomsheet_my_review.xml b/app/src/main/res/layout/fragment_bottomsheet_my_review.xml new file mode 100644 index 00000000..29984fa0 --- /dev/null +++ b/app/src/main/res/layout/fragment_bottomsheet_my_review.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 628b1d5bb9c7b2ba3982bdb535fdda96acbe2356 Mon Sep 17 00:00:00 2001 From: Yu Jin Date: Mon, 2 Dec 2024 15:46:01 +0900 Subject: [PATCH 2/5] =?UTF-8?q?refactor:=20ListAdapter=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/myreview/MyReviewAdapter.kt | 21 ++++--- .../presentation/review/list/ReviewAdapter.kt | 62 ++++--------------- 2 files changed, 27 insertions(+), 56 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewAdapter.kt index 5649cf96..029ea961 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewAdapter.kt @@ -1,17 +1,15 @@ package com.eatssu.android.presentation.mypage.myreview -import android.content.Intent import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView -import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter import com.bumptech.glide.Glide import com.eatssu.android.data.MySharedPreferences import com.eatssu.android.databinding.ItemReviewBinding import com.eatssu.android.domain.model.Review -import com.eatssu.android.presentation.review.delete.MyReviewDialogActivity import timber.log.Timber @@ -75,8 +73,17 @@ class MyReviewAdapter(private val dataList: List) : } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bind(position) + val item = getItem(position) + holder.bind(item) } +} - override fun getItemCount(): Int = dataList.size -} \ No newline at end of file +class ReviewDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Review, newItem: Review): Boolean { + return oldItem.reviewId == newItem.reviewId + } + + override fun areContentsTheSame(oldItem: Review, newItem: Review): Boolean { + return oldItem == newItem + } +} diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt index 112b122b..5213f760 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt @@ -1,22 +1,14 @@ package com.eatssu.android.presentation.review.list -import android.content.Context -import android.content.Intent -import android.util.Log import android.view.LayoutInflater -import android.view.MenuItem import android.view.View import android.view.ViewGroup -import androidx.annotation.MenuRes -import androidx.appcompat.widget.PopupMenu -import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide -import com.eatssu.android.R import com.eatssu.android.databinding.ItemReviewBinding import com.eatssu.android.domain.model.Review -import com.eatssu.android.presentation.review.modify.ModifyReviewActivity -import com.eatssu.android.presentation.review.report.ReportActivity class ReviewAdapter( @@ -74,10 +66,9 @@ class ReviewAdapter( } - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - when (holder) { - is ViewHolder -> holder.bind(position) - } + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val review = getItem(position) // `ListAdapter`에서 제공 + holder.bind(review) } @@ -98,41 +89,14 @@ class ReviewAdapter( true } - R.id.fix -> { - val intent = - Intent(holdercontext, ModifyReviewActivity::class.java) - intent.putExtra("reviewId", data.reviewId) - intent.putExtra("menu", data.menu) - intent.putExtra("content", data.content) - intent.putExtra("mainGrade", data.mainGrade) - intent.putExtra("amountGrade", data.amountGrade) - intent.putExtra("tasteGrade", data.tasteGrade) - - Log.d("ReviewFixedActivity", "전전:" + data.reviewId) - Log.d("ReviewFixedActivity", "전전:" + data.menu) - Log.d("ReviewFixedActivity", "전전:" + data.content) -//// Timber.d("내용: "+data.content) - ContextCompat.startActivity(holdercontext, intent, null) - true - } - - R.id.delete -> { - callBackReviewId(data.reviewId) - true - } - - else -> { - true - } - } - } - popup.setOnDismissListener { - // Respond to popup being dismissed. - } -// Show the popup menu. - popup.show() +class ReviewDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Review, newItem: Review): Boolean { + // 고유 식별자를 비교 (예: id) + return oldItem.reviewId == newItem.reviewId } - override fun getItemCount(): Int = dataList.size - + override fun areContentsTheSame(oldItem: Review, newItem: Review): Boolean { + // 객체의 내용 전체를 비교 + return oldItem == newItem + } } From 87a92a1cad9060b44c6cb9d22e3e5798f6a6fdad Mon Sep 17 00:00:00 2001 From: Yu Jin Date: Mon, 2 Dec 2024 15:46:54 +0900 Subject: [PATCH 3/5] change: bottomSheet clickListener --- app/src/main/AndroidManifest.xml | 2 +- .../MyReviewBottomSheetFragment.kt | 62 ++++++------ .../common/OthersBottomSheetFragment.kt | 50 ++++++++++ .../mypage/myreview/MyReviewAdapter.kt | 58 +++++------ .../mypage/myreview/MyReviewListActivity.kt | 46 ++++++++- .../mypage/myreview/MyReviewViewModel.kt | 34 +++++++ .../review/delete/DeleteViewModel.kt | 68 ------------- .../review/list/ReviewActivity.kt | 97 +++++++++++++++---- .../presentation/review/list/ReviewAdapter.kt | 64 +++++------- .../review/list/ReviewViewModel.kt | 29 ++++++ .../report/OthersReviewDialogActivity.kt | 39 -------- app/src/main/res/layout/activity_fix_menu.xml | 10 ++ .../layout/fragment_bottomsheet_others.xml | 60 ++++++++++++ 13 files changed, 388 insertions(+), 231 deletions(-) rename app/src/main/java/com/eatssu/android/presentation/{mypage/myreview => common}/MyReviewBottomSheetFragment.kt (64%) create mode 100644 app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt delete mode 100644 app/src/main/java/com/eatssu/android/presentation/review/delete/DeleteViewModel.kt delete mode 100644 app/src/main/java/com/eatssu/android/presentation/review/report/OthersReviewDialogActivity.kt create mode 100644 app/src/main/res/layout/fragment_bottomsheet_others.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0d799397..a86b06f7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -170,7 +170,7 @@ android:value="" /> (ReviewDiffCallback()) { -class MyReviewAdapter(private val dataList: List) : - RecyclerView.Adapter() { + interface OnItemClickListener { + fun onMyReviewClicked(view: View, reviewData: Review) + } - inner class ViewHolder(private val binding: ItemReviewBinding) : - RecyclerView.ViewHolder(binding.root) { + // 객체 저장 변수 + private lateinit var mOnItemClickListener: OnItemClickListener - fun bind(position: Int) { - binding.tvReviewItemComment.text = dataList[position].content - binding.tvReviewItemDate.text = dataList[position].writeDate - binding.tvMenuName.text = dataList[position].menu + // 객체 전달 메서드 + fun setOnItemClickListener(onItemClickListener: OnItemClickListener) { + mOnItemClickListener = onItemClickListener + } + + inner class ViewHolder(private val binding: ItemReviewBinding) : + androidx.recyclerview.widget.RecyclerView.ViewHolder(binding.root) { - binding.rbRate.rating = dataList[position].mainGrade.toFloat() + fun bind(data: Review) { binding.tvWriterNickname.text = MySharedPreferences.getUserName(binding.root.context) + binding.tvReviewItemComment.text = data.content + binding.tvReviewItemDate.text = data.writeDate + binding.tvMenuName.text = data.menu + binding.rbRate.rating = data.mainGrade.toFloat() val imageView: ImageView = binding.ivReviewPhoto - - if (dataList[position].imgUrl?.isEmpty() == true) { + if (data.imgUrl?.isEmpty() == true || data.imgUrl?.get(0).isNullOrEmpty()) { imageView.visibility = View.GONE } else { - Timber.d("사진 있다") Glide.with(itemView) - .load(dataList[position].imgUrl?.get(0)) + .load(data.imgUrl?.get(0)) .into(imageView) imageView.visibility = View.VISIBLE - - if (dataList[position].imgUrl?.get(0) == "" || dataList[position].imgUrl?.get(0) == null) { - binding.ivReviewPhoto.visibility = View.GONE - } } - binding.btnDetail.setOnClickListener { - val intent = Intent(binding.btnDetail.context, MyReviewDialogActivity::class.java) - intent.putExtra("reviewId", dataList[position].reviewId) - intent.putExtra("menu", dataList[position].menu) - - intent.putExtra("content", dataList[position].content) - - intent.putExtra("mainGrade", dataList[position].mainGrade) - intent.putExtra("amountGrade", dataList[position].amountGrade) - intent.putExtra("tasteGrade", dataList[position].tasteGrade) + binding.btnDetail.setOnClickListener { v: View -> + mOnItemClickListener.onMyReviewClicked(v, data) Timber.d( "리뷰 상세 정보 - ID: %d, 메뉴: %s, 내용: %s", - dataList[position].reviewId, - dataList[position].menu, - dataList[position].content + data.reviewId, + data.menu, + data.content ) - - ContextCompat.startActivity(binding.btnDetail.context, intent, null) } } } diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt index 2beee9a1..39fa59f6 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt @@ -3,18 +3,22 @@ package com.eatssu.android.presentation.mypage.myreview import android.os.Bundle import android.view.View import androidx.activity.viewModels +import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager +import com.eatssu.android.R import com.eatssu.android.databinding.ActivityMyReviewListBinding import com.eatssu.android.domain.model.Review import com.eatssu.android.presentation.base.BaseActivity +import com.eatssu.android.presentation.common.MyReviewBottomSheetFragment import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch @AndroidEntryPoint class MyReviewListActivity : - BaseActivity(ActivityMyReviewListBinding::inflate) { + BaseActivity(ActivityMyReviewListBinding::inflate), + MyReviewBottomSheetFragment.OnReviewDeletedListener { private val myReviewViewModel: MyReviewViewModel by viewModels() @@ -28,10 +32,21 @@ class MyReviewListActivity : } private fun setAdapter(reviewList: List) { - val listAdapter = MyReviewAdapter(reviewList) + + val adapter = MyReviewAdapter() + adapter.submitList(reviewList) + val linearLayoutManager = LinearLayoutManager(this) - binding.rvReview.adapter = listAdapter + adapter.setOnItemClickListener(object : + MyReviewAdapter.OnItemClickListener { + + override fun onMyReviewClicked(view: View, reviewData: Review) { + onMyReviewClicked(review = reviewData) + } + }) + + binding.rvReview.adapter = adapter binding.rvReview.layoutManager = linearLayoutManager binding.rvReview.setHasFixedSize(true) } @@ -62,4 +77,29 @@ class MyReviewListActivity : super.onResume() lodeReview() } + + fun onMyReviewClicked(review: Review) { + + val modalBottomSheet = MyReviewBottomSheetFragment().apply { + arguments = Bundle().apply { + putLong("reviewId", review.reviewId) + putString("menu", review.menu) + putString("content", review.content) + putInt("mainGrade", review.mainGrade) + putInt("amountGrade", review.amountGrade) + putInt("tasteGrade", review.tasteGrade) + } + onReviewDeletedListener = this@MyReviewListActivity + } + modalBottomSheet.setStyle( + DialogFragment.STYLE_NORMAL, + R.style.RoundCornerBottomSheetDialogTheme + ) + modalBottomSheet.show(supportFragmentManager, "Open Bottom Sheet") + } + + override fun onReviewDeleted() { + lodeReview() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewViewModel.kt index b65be4bf..29fe8b12 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewViewModel.kt @@ -1,11 +1,15 @@ package com.eatssu.android.presentation.mypage.myreview +import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.eatssu.android.R import com.eatssu.android.data.dto.response.toReviewList import com.eatssu.android.domain.model.Review import com.eatssu.android.domain.usecase.auth.GetMyReviewsUseCase +import com.eatssu.android.domain.usecase.review.DeleteReviewUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -21,6 +25,8 @@ import javax.inject.Inject @HiltViewModel class MyReviewViewModel @Inject constructor( private val getMyReviewsUseCase: GetMyReviewsUseCase, + private val deleteReviewUseCase: DeleteReviewUseCase, + @ApplicationContext private val context: Context ) : ViewModel() { private val _uiState: MutableStateFlow = MutableStateFlow(MyReviewState()) @@ -55,6 +61,33 @@ class MyReviewViewModel @Inject constructor( } } } + + fun deleteReview(reviewId: Long) { + viewModelScope.launch { + deleteReviewUseCase(reviewId).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + error = true, + toastMessage = context.getString(R.string.delete_not) + ) + } + Timber.e(e.toString()) + }.collectLatest { result -> + Timber.d(result.toString()) + + _uiState.update { + it.copy( + isDeleted = true, + toastMessage = context.getString(R.string.delete_done) + ) + } + } + } + } } @@ -67,5 +100,6 @@ data class MyReviewState( var isEmpty: Boolean = false, var myReviews: List? = null, + var isDeleted: Boolean = false, ) \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/review/delete/DeleteViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/review/delete/DeleteViewModel.kt deleted file mode 100644 index ef9fb66d..00000000 --- a/app/src/main/java/com/eatssu/android/presentation/review/delete/DeleteViewModel.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.eatssu.android.presentation.review.delete - -import android.content.Context -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.eatssu.android.R -import com.eatssu.android.domain.usecase.review.DeleteReviewUseCase -import dagger.hilt.android.lifecycle.HiltViewModel -import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.onCompletion -import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import timber.log.Timber -import javax.inject.Inject - -@HiltViewModel -class DeleteViewModel @Inject constructor( - private val deleteReviewUseCase: DeleteReviewUseCase, - @ApplicationContext private val context: Context -) : ViewModel() { - - private val _uiState: MutableStateFlow = MutableStateFlow(DeleteState()) - val uiState: StateFlow = _uiState.asStateFlow() - - - fun deleteReview(reviewId: Long) { - viewModelScope.launch { - deleteReviewUseCase(reviewId).onStart { - _uiState.update { it.copy(loading = true) } - }.onCompletion { - _uiState.update { it.copy(loading = false, error = true) } - }.catch { e -> - _uiState.update { - it.copy( - error = true, - toastMessage = context.getString(R.string.delete_not) - ) - } - Timber.e(e.toString()) - }.collectLatest { result -> - Timber.d(result.toString()) - - _uiState.update { - it.copy( - isDeleted = true, - toastMessage = context.getString(R.string.delete_done) - ) - } - } - } - } -} - -data class DeleteState( - var loading: Boolean = true, - var error: Boolean = false, - - var toastMessage: String = "", - - var isDeleted: Boolean = false, - - ) \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt index feb396e7..ad8e9545 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt @@ -4,12 +4,16 @@ import android.content.Intent import android.os.Bundle import android.view.View import androidx.activity.viewModels +import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager +import com.eatssu.android.R import com.eatssu.android.data.enums.MenuType import com.eatssu.android.databinding.ActivityReviewBinding +import com.eatssu.android.domain.model.Review import com.eatssu.android.presentation.base.BaseActivity -import com.eatssu.android.presentation.review.delete.DeleteViewModel +import com.eatssu.android.presentation.common.MyReviewBottomSheetFragment +import com.eatssu.android.presentation.common.OthersBottomSheetFragment import com.eatssu.android.presentation.review.write.ReviewWriteRateActivity import com.eatssu.android.presentation.review.write.menu.ReviewWriteMenuActivity import dagger.hilt.android.AndroidEntryPoint @@ -20,9 +24,9 @@ import kotlin.properties.Delegates @AndroidEntryPoint class ReviewActivity : - BaseActivity(ActivityReviewBinding::inflate) { + BaseActivity(ActivityReviewBinding::inflate), + MyReviewBottomSheetFragment.OnReviewDeletedListener { - private val deleteViewModel: DeleteViewModel by viewModels() private val reviewViewModel: ReviewViewModel by viewModels() private lateinit var menuType: String @@ -68,7 +72,6 @@ class ReviewActivity : } - private fun bindData() { lifecycleScope.launch { reviewViewModel.uiState.collectLatest { @@ -88,19 +91,7 @@ class ReviewActivity : binding.llNonReview.visibility = View.INVISIBLE binding.rvReview.visibility = View.VISIBLE - reviewAdapter = it.reviewList?.let { review -> - ReviewAdapter(review) { reviewId -> - deleteViewModel.deleteReview( - reviewId - ) - } - } - - binding.rvReview.apply { - adapter = reviewAdapter - layoutManager = LinearLayoutManager(applicationContext) - setHasFixedSize(true) - } + it.reviewList?.let { reviewList -> setAdapter(reviewList = reviewList) } it.reviewInfo?.apply { @@ -129,6 +120,32 @@ class ReviewActivity : } } + + private fun setAdapter(reviewList: List) { + + val adapter = ReviewAdapter() + adapter.submitList(reviewList) + + val linearLayoutManager = LinearLayoutManager(this) + + adapter.setOnItemClickListener(object : + ReviewAdapter.OnItemClickListener { + + override fun onMyReviewClicked(view: View, reviewData: Review) { + onMyReviewClicked(reviewData = reviewData) + } + + override fun onOthersReviewClicked(view: View, reviewData: Review) { + onOthersReviewClicked(reviewData = reviewData) + } + }) + + binding.rvReview.adapter = adapter + binding.rvReview.layoutManager = linearLayoutManager + binding.rvReview.setHasFixedSize(true) + } + + private fun setClickListener() { when (menuType) { MenuType.FIXED.name -> { @@ -155,4 +172,50 @@ class ReviewActivity : } } } + + + fun onMyReviewClicked(reviewData: Review) { + val modalBottomSheet = MyReviewBottomSheetFragment() + modalBottomSheet.setStyle( + DialogFragment.STYLE_NORMAL, + R.style.RoundCornerBottomSheetDialogTheme + ) + + val bundle = Bundle() + bundle.let { + it.putLong("reviewId", reviewData.reviewId) + it.putString("menu", reviewData.menu) + it.putString("content", reviewData.content) + it.putInt("mainGrade", reviewData.mainGrade) + it.putInt("amountGrade", reviewData.amountGrade) + it.putInt("tasteGrade", reviewData.tasteGrade) + } + + modalBottomSheet.arguments = bundle + modalBottomSheet.show(supportFragmentManager, "Open Bottom Sheet") + } + + fun onOthersReviewClicked(reviewData: Review) { + val modalBottomSheet = OthersBottomSheetFragment() + modalBottomSheet.setStyle( + DialogFragment.STYLE_NORMAL, + R.style.RoundCornerBottomSheetDialogTheme + ) + + val bundle = Bundle() + bundle.let { + it.putLong("reviewId", reviewData.reviewId) + it.putString("menu", reviewData.menu) + } + + modalBottomSheet.arguments = bundle + modalBottomSheet.show(supportFragmentManager, "Open Bottom Sheet") + } + + + override fun onReviewDeleted() { + lodeData() + bindData() + } + } diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt index 5213f760..f6948f8a 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt @@ -11,35 +11,38 @@ import com.eatssu.android.databinding.ItemReviewBinding import com.eatssu.android.domain.model.Review -class ReviewAdapter( - private val dataList: List, - private val callBackReviewId: (Long) -> Unit -) : - RecyclerView.Adapter() { +class ReviewAdapter : + ListAdapter(ReviewDiffCallback()) { + + interface OnItemClickListener { + fun onMyReviewClicked(view: View, reviewData: Review) + fun onOthersReviewClicked(view: View, reviewData: Review) + } + + private lateinit var mOnItemClickListener: OnItemClickListener + + fun setOnItemClickListener(onItemClickListener: OnItemClickListener) { + mOnItemClickListener = onItemClickListener + } inner class ViewHolder(private val binding: ItemReviewBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(position: Int) { - val data = dataList[position].apply { - binding.tvWriterNickname.text = writerNickname - binding.tvReviewItemComment.text = content - binding.tvReviewItemDate.text = writeDate - binding.tvMenuName.text = menu //TODO 리사이클러뷰로 변경 - binding.rbRate.rating = mainGrade.toFloat() - } + fun bind(data: Review) { + binding.tvWriterNickname.text = data.writerNickname + binding.tvReviewItemComment.text = data.content + binding.tvReviewItemDate.text = data.writeDate + binding.tvMenuName.text = data.menu + binding.rbRate.rating = data.mainGrade.toFloat() if (!data.imgUrl.isNullOrEmpty()) { - Log.d("ReviewAdapter", data.content + data.imgUrl?.size.toString()) - data.imgUrl?.toString()?.let { Log.d("ReviewAdapter", it) } - Glide.with(itemView) .load(data.imgUrl[0]) .into(binding.ivReviewPhoto) binding.ivReviewPhoto.visibility = View.VISIBLE binding.cvPhotoReview.visibility = View.VISIBLE - if (data.imgUrl[0] == "") { + if (data.imgUrl[0].isEmpty()) { binding.ivReviewPhoto.visibility = View.GONE binding.cvPhotoReview.visibility = View.GONE } @@ -50,44 +53,25 @@ class ReviewAdapter( binding.btnDetail.setOnClickListener { v: View -> if (data.isWriter) { - showMenu(binding.root.context, v, R.menu.menu_my_review, data) + mOnItemClickListener.onMyReviewClicked(v, data) } else { - showMenu(binding.root.context, v, R.menu.menu_other_review, data) + mOnItemClickListener.onOthersReviewClicked(v, data) } } } } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = ItemReviewBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return ViewHolder(binding) - } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val review = getItem(position) // `ListAdapter`에서 제공 holder.bind(review) } - - - private fun showMenu(holdercontext: Context, v: View, @MenuRes menuRes: Int, data: Review) { - val popup = PopupMenu(holdercontext, v) - popup.menuInflater.inflate(menuRes, popup.menu) - - popup.setOnMenuItemClickListener { menuItem: MenuItem -> - // Respond to menu item click. - when (menuItem.itemId) { - R.id.report -> { - val intent = - Intent(holdercontext, ReportActivity::class.java) - intent.putExtra("reviewId", data.reviewId) - intent.putExtra("menu", data.menu) - ContextCompat.startActivity(holdercontext, intent, null) - - true - } +} class ReviewDiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Review, newItem: Review): Boolean { diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewViewModel.kt index b49b83bf..86e42362 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewViewModel.kt @@ -7,6 +7,7 @@ import com.eatssu.android.data.dto.response.toReviewList import com.eatssu.android.data.enums.MenuType import com.eatssu.android.domain.model.Review import com.eatssu.android.domain.model.ReviewInfo +import com.eatssu.android.domain.usecase.review.DeleteReviewUseCase import com.eatssu.android.domain.usecase.review.GetMealReviewInfoUseCase import com.eatssu.android.domain.usecase.review.GetMealReviewListUseCase import com.eatssu.android.domain.usecase.review.GetMenuReviewInfoUseCase @@ -31,6 +32,7 @@ class ReviewViewModel @Inject constructor( private val getMenuReviewListUseCase: GetMenuReviewListUseCase, private val getMealReviewInfoUseCase: GetMealReviewInfoUseCase, private val getMealReviewListUseCase: GetMealReviewListUseCase, + private val deleteReviewUseCase: DeleteReviewUseCase, ) : ViewModel() { private val _uiState: MutableStateFlow = MutableStateFlow(ReviewState()) @@ -224,6 +226,33 @@ class ReviewViewModel @Inject constructor( } } } + + fun deleteReview(reviewId: Long) { + viewModelScope.launch { + deleteReviewUseCase(reviewId).onStart { + _uiState.update { it.copy(loading = true) } + }.onCompletion { + _uiState.update { it.copy(loading = false, error = true) } + }.catch { e -> + _uiState.update { + it.copy( + error = true, +// toastMessage = context.getString(R.string.delete_not) + ) + } + Timber.e(e.toString()) + }.collectLatest { result -> + Timber.d(result.toString()) + + _uiState.update { + it.copy( +// isDeleted = true, +// toastMessage = context.getString(R.string.delete_done) + ) + } + } + } + } } data class ReviewState( diff --git a/app/src/main/java/com/eatssu/android/presentation/review/report/OthersReviewDialogActivity.kt b/app/src/main/java/com/eatssu/android/presentation/review/report/OthersReviewDialogActivity.kt deleted file mode 100644 index 88b4609f..00000000 --- a/app/src/main/java/com/eatssu/android/presentation/review/report/OthersReviewDialogActivity.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.eatssu.android.presentation.review.report - -import android.content.Intent -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import com.eatssu.android.databinding.ActivityOthersReviewDialogBinding -import timber.log.Timber - -class OthersReviewDialogActivity : AppCompatActivity() { - - private lateinit var binding: ActivityOthersReviewDialogBinding - var reviewId = -1L - var menuId = -1L - var menu = "" - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - binding = ActivityOthersReviewDialogBinding.inflate(layoutInflater) - - setContentView(binding.root) - - reviewId = intent.getLongExtra("reviewId", -1L) - menu = intent.getStringExtra("menu").toString() - - - binding.btnReviewReport.setOnClickListener { - val intent = Intent(this, ReportActivity::class.java) - intent.putExtra( - "reviewId", reviewId - ) - Timber.d("reviewId $reviewId") - startActivity(intent) - finish() - } - - - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_fix_menu.xml b/app/src/main/res/layout/activity_fix_menu.xml index efe9e40a..32397c14 100644 --- a/app/src/main/res/layout/activity_fix_menu.xml +++ b/app/src/main/res/layout/activity_fix_menu.xml @@ -47,7 +47,10 @@ android:layout_height="wrap_content" android:isIndicator="false" android:numStars="5" + android:progressBackgroundTint="@color/gray300" + android:progressTint="@color/star" android:rating="0" + android:secondaryProgressTint="@color/star" android:stepSize="1" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" @@ -102,7 +105,10 @@ android:layout_gravity="center" android:isIndicator="false" android:numStars="5" + android:progressBackgroundTint="@color/gray300" + android:progressTint="@color/star" android:rating="0" + android:secondaryProgressTint="@color/star" android:stepSize="1" /> @@ -131,9 +137,13 @@ style="@style/Widget.AppCompat.RatingBar.Indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_gravity="center" android:isIndicator="false" android:numStars="5" + android:progressBackgroundTint="@color/gray300" + android:progressTint="@color/star" android:rating="0" + android:secondaryProgressTint="@color/star" android:stepSize="1" /> diff --git a/app/src/main/res/layout/fragment_bottomsheet_others.xml b/app/src/main/res/layout/fragment_bottomsheet_others.xml new file mode 100644 index 00000000..245979d8 --- /dev/null +++ b/app/src/main/res/layout/fragment_bottomsheet_others.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 7de6d1a453e1a5740338337d9d0c984ae0794948 Mon Sep 17 00:00:00 2001 From: Yu Jin Date: Mon, 2 Dec 2024 15:48:53 +0900 Subject: [PATCH 4/5] =?UTF-8?q?chore:=20=EC=A0=84=EC=B2=B4=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=EC=97=90=EC=84=9C=20=EC=82=AD=EC=A0=9C=ED=95=98?= =?UTF-8?q?=EB=A9=B4=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=9E=AC=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=95=88=EB=90=98=EB=8A=94=EA=B1=B0=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 --- .../review/list/ReviewActivity.kt | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt index ad8e9545..590a5644 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt @@ -132,7 +132,7 @@ class ReviewActivity : ReviewAdapter.OnItemClickListener { override fun onMyReviewClicked(view: View, reviewData: Review) { - onMyReviewClicked(reviewData = reviewData) + onMyReviewClicked(review = reviewData) } override fun onOthersReviewClicked(view: View, reviewData: Review) { @@ -174,24 +174,22 @@ class ReviewActivity : } - fun onMyReviewClicked(reviewData: Review) { - val modalBottomSheet = MyReviewBottomSheetFragment() + fun onMyReviewClicked(review: Review) { + val modalBottomSheet = MyReviewBottomSheetFragment().apply { + arguments = Bundle().apply { + putLong("reviewId", review.reviewId) + putString("menu", review.menu) + putString("content", review.content) + putInt("mainGrade", review.mainGrade) + putInt("amountGrade", review.amountGrade) + putInt("tasteGrade", review.tasteGrade) + } + onReviewDeletedListener = this@ReviewActivity + } modalBottomSheet.setStyle( DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme ) - - val bundle = Bundle() - bundle.let { - it.putLong("reviewId", reviewData.reviewId) - it.putString("menu", reviewData.menu) - it.putString("content", reviewData.content) - it.putInt("mainGrade", reviewData.mainGrade) - it.putInt("amountGrade", reviewData.amountGrade) - it.putInt("tasteGrade", reviewData.tasteGrade) - } - - modalBottomSheet.arguments = bundle modalBottomSheet.show(supportFragmentManager, "Open Bottom Sheet") } @@ -217,5 +215,4 @@ class ReviewActivity : lodeData() bindData() } - } From 687a1c7ffb8974b9b94b3b61d16c8740bef62c42 Mon Sep 17 00:00:00 2001 From: Yu Jin Date: Mon, 2 Dec 2024 15:59:56 +0900 Subject: [PATCH 5/5] =?UTF-8?q?chore:=20=EC=A0=84=EC=B2=B4=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=EC=97=90=EC=84=9C=20=EC=82=AD=EC=A0=9C=ED=95=98?= =?UTF-8?q?=EB=A9=B4=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=9E=AC=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=95=88=EB=90=98=EB=8A=94=EA=B1=B0=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 --- .../eatssu/android/presentation/review/list/ReviewActivity.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt index 590a5644..670664e8 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt @@ -33,8 +33,6 @@ class ReviewActivity : private var itemId by Delegates.notNull() private lateinit var itemName: String - private var reviewAdapter: ReviewAdapter? = null - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)