From e837634747305127d1930fc8e63d038bc55c69d1 Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 03:06:05 +0900 Subject: [PATCH 01/12] =?UTF-8?q?refactor:=20feed=20=EB=A1=9C=EB=94=A9=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/teamwss/websoso/ui/main/feed/FeedViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/ui/main/feed/FeedViewModel.kt b/app/src/main/java/com/teamwss/websoso/ui/main/feed/FeedViewModel.kt index 9bac23b7f..fff335666 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/main/feed/FeedViewModel.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/main/feed/FeedViewModel.kt @@ -47,7 +47,6 @@ class FeedViewModel @Inject constructor( fun updateFeeds() { feedUiState.value?.let { feedUiState -> if (!feedUiState.isLoadable) return - else _feedUiState.value = feedUiState.copy(loading = true) viewModelScope.launch { val selectedCategory: Category = @@ -118,7 +117,6 @@ class FeedViewModel @Inject constructor( fun updateRefreshedFeeds() { feedUiState.value?.let { feedUiState -> - _feedUiState.value = feedUiState.copy(loading = true) viewModelScope.launch { val selectedCategory: Category = From 170c23a22d7db58b2d659b6a324b122b91dd4d17 Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 03:42:27 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20=EB=8C=93=EA=B8=80=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websoso/data/remote/api/FeedApi.kt | 12 ++++++-- .../data/remote/request/CommentRequestDto.kt | 9 ++++++ .../websoso/data/repository/FeedRepository.kt | 16 ++++++----- .../ui/feedDetail/FeedDetailActivity.kt | 13 +++++++-- .../ui/feedDetail/FeedDetailViewModel.kt | 28 +++++++++++++++++++ .../feedDetail/adapter/FeedDetailAdapter.kt | 10 ++++--- .../adapter/FeedDetailCommentViewHolder.kt | 4 +-- 7 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/com/teamwss/websoso/data/remote/request/CommentRequestDto.kt diff --git a/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt b/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt index 0bc1e6ee7..20d885e25 100644 --- a/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt +++ b/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt @@ -1,10 +1,12 @@ package com.teamwss.websoso.data.remote.api +import com.teamwss.websoso.data.remote.request.CommentRequestDto import com.teamwss.websoso.data.remote.response.CommentsResponseDto import com.teamwss.websoso.data.remote.response.FeedDetailResponseDto import com.teamwss.websoso.data.remote.response.FeedsResponseDto import com.teamwss.websoso.data.remote.response.PopularFeedsResponseDto import com.teamwss.websoso.data.remote.response.UserInterestFeedsResponseDto +import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.GET import retrofit2.http.POST @@ -25,14 +27,20 @@ interface FeedApi { @Path("feedId") feedId: Long, ): FeedDetailResponseDto + @DELETE("feeds/{feedId}") + suspend fun deleteFeed( + @Path("feedId") feedId: Long, + ) + @GET("feeds/{feedId}/comments") suspend fun getComments( @Path("feedId") feedId: Long, ): CommentsResponseDto - @DELETE("feeds/{feedId}") - suspend fun deleteFeed( + @POST("feeds/{feedId}/comments") + suspend fun postComment( @Path("feedId") feedId: Long, + @Body commentRequestDto: CommentRequestDto, ) @POST("feeds/{feedId}/likes") diff --git a/app/src/main/java/com/teamwss/websoso/data/remote/request/CommentRequestDto.kt b/app/src/main/java/com/teamwss/websoso/data/remote/request/CommentRequestDto.kt new file mode 100644 index 000000000..293c01922 --- /dev/null +++ b/app/src/main/java/com/teamwss/websoso/data/remote/request/CommentRequestDto.kt @@ -0,0 +1,9 @@ +package com.teamwss.websoso.data.remote.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class CommentRequestDto( + @SerialName("commentContent") val commentContent: String, +) diff --git a/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt b/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt index 694bea92a..489fdb8ae 100644 --- a/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt +++ b/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt @@ -7,6 +7,7 @@ import com.teamwss.websoso.data.model.FeedsEntity import com.teamwss.websoso.data.model.PopularFeedsEntity import com.teamwss.websoso.data.model.UserInterestFeedsEntity import com.teamwss.websoso.data.remote.api.FeedApi +import com.teamwss.websoso.data.remote.request.CommentRequestDto import javax.inject.Inject class FeedRepository @Inject constructor( @@ -28,27 +29,28 @@ class FeedRepository @Inject constructor( suspend fun fetchComments(feedId: Long): CommentsEntity = feedApi.getComments(feedId).toData() + suspend fun saveComment(feedId: Long, comment: String) { + feedApi.postComment(feedId, CommentRequestDto(comment)) + } + suspend fun saveLike(isLikedOfLikedFeed: Boolean, selectedFeedId: Long) { - return when (isLikedOfLikedFeed) { + when (isLikedOfLikedFeed) { true -> feedApi.deleteLikes(selectedFeedId) false -> feedApi.postLikes(selectedFeedId) } } suspend fun saveRemovedFeed(feedId: Long) { - return feedApi.deleteFeed(feedId) - .also { _cachedFeeds.removeIf { it.id == feedId } } + feedApi.deleteFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } } suspend fun saveSpoilerFeed(feedId: Long) { - return feedApi.postSpoilerFeed(feedId) - .also { _cachedFeeds.removeIf { it.id == feedId } } + feedApi.postSpoilerFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } } suspend fun saveImpertinenceFeed(feedId: Long) { - return feedApi.postImpertinenceFeed(feedId) - .also { _cachedFeeds.removeIf { it.id == feedId } } + feedApi.postImpertinenceFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } } fun clearCachedFeeds() { diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index 97f1c9b52..8b3b26848 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -16,8 +16,7 @@ import com.teamwss.websoso.ui.feedDetail.model.FeedDetailUiState.Success import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class FeedDetailActivity : - BaseActivity(R.layout.activity_feed_detail) { +class FeedDetailActivity : BaseActivity(R.layout.activity_feed_detail) { private val feedDetailViewModel: FeedDetailViewModel by viewModels() private val feedId: Long by lazy { intent.getLongExtra(FEED_ID, DEFAULT_FEED_ID) } private val feedDetailAdapter: FeedDetailAdapter by lazy { FeedDetailAdapter() } @@ -27,6 +26,7 @@ class FeedDetailActivity : setupView() setupObserver() + onCommentRegisterClick() } private fun setupView() { @@ -51,6 +51,15 @@ class FeedDetailActivity : feedDetailAdapter.submitList(listOf(header) + comments) } + private fun onCommentRegisterClick() { + binding.ivFeedDetailCommentRegister.setOnClickListener { + binding.etFeedDetailInput.text.run { + feedDetailViewModel.dispatchComment(feedId, toString()) + clear() + } + } + } + companion object { private const val FEED_ID: String = "FEED_ID" private const val DEFAULT_FEED_ID: Long = -1 diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt index 12d9f9182..8e56a1354 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt @@ -40,4 +40,32 @@ class FeedDetailViewModel @Inject constructor( } } } + + fun dispatchComment(feedId: Long, comment: String) { + viewModelScope.launch { + runCatching { + feedRepository.saveComment(feedId, comment) + }.onSuccess { + updateComments(feedId) + }.onFailure { + _feedDetailUiState.value = Error + } + } + } + + private fun updateComments(feedId: Long) { + viewModelScope.launch { + runCatching { + feedRepository.fetchComments(feedId) + }.onSuccess { comments -> + _feedDetailUiState.value = Success( + feedDetail = (feedDetailUiState.value as Success).feedDetail.copy( + comments = comments.comments.map { it.toUi() } + ) + ) + }.onFailure { + _feedDetailUiState.value = Error + } + } + } } diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt index b7f8a9d60..3dfc0f254 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt @@ -7,6 +7,8 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.Comment import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.Header import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.ItemType +import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.ItemType.COMMENT +import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.ItemType.HEADER class FeedDetailAdapter : ListAdapter(diffCallBack) { @@ -15,8 +17,8 @@ class FeedDetailAdapter : ListAdapter(diffCallBack) } override fun getItemViewType(position: Int): Int = when (getItem(position)) { - is Header -> ItemType.HEADER.ordinal - is Comment -> ItemType.COMMENT.ordinal + is Header -> HEADER.ordinal + is Comment -> COMMENT.ordinal } override fun getItemId(position: Int): Long = when (getItem(position)) { @@ -26,8 +28,8 @@ class FeedDetailAdapter : ListAdapter(diffCallBack) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = when (ItemType.valueOf(viewType)) { - ItemType.HEADER -> FeedDetailContentViewHolder.from(parent) - ItemType.COMMENT -> FeedDetailCommentViewHolder.from(parent) + HEADER -> FeedDetailContentViewHolder.from(parent) + COMMENT -> FeedDetailCommentViewHolder.from(parent) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailCommentViewHolder.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailCommentViewHolder.kt index e98a288a6..b3dd28741 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailCommentViewHolder.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailCommentViewHolder.kt @@ -11,7 +11,7 @@ class FeedDetailCommentViewHolder( ) : RecyclerView.ViewHolder(binding.root) { fun bind(comment: CommentModel) { - + binding.comment = comment } companion object { @@ -25,4 +25,4 @@ class FeedDetailCommentViewHolder( ) ) } -} \ No newline at end of file +} From 5c0dcfb36f435e879ab6eb475c56adc16949dc40 Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 03:58:38 +0900 Subject: [PATCH 03/12] =?UTF-8?q?refactor:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EA=B0=9C=EC=88=98=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt | 2 +- .../websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt | 6 +----- .../ui/feedDetail/adapter/FeedDetailContentViewHolder.kt | 3 +-- app/src/main/res/layout/item_feed_detail_header.xml | 6 +----- 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index 8b3b26848..447405667 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -45,8 +45,8 @@ class FeedDetailActivity : BaseActivity(R.layout.acti } private fun updateView(feedDetailUiState: Success) { - val header = Header(feedDetailUiState.feedDetail.feed) val comments = feedDetailUiState.feedDetail.comments.map { Comment(it) } + val header = Header(feedDetailUiState.feedDetail.feed.copy(commentCount = comments.size)) feedDetailAdapter.submitList(listOf(header) + comments) } diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt index 3dfc0f254..9f8761e36 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt @@ -34,11 +34,7 @@ class FeedDetailAdapter : ListAdapter(diffCallBack) override fun onBindViewHolder(holder: ViewHolder, position: Int) { when (holder) { - is FeedDetailContentViewHolder -> holder.bind( - (getItem(position) as Header).feed, - itemCount - 1, - ) - + is FeedDetailContentViewHolder -> holder.bind((getItem(position) as Header).feed) is FeedDetailCommentViewHolder -> holder.bind((getItem(position) as Comment).comment) } } diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailContentViewHolder.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailContentViewHolder.kt index 54190e071..7a8c1ecb7 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailContentViewHolder.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailContentViewHolder.kt @@ -10,9 +10,8 @@ class FeedDetailContentViewHolder( private val binding: ItemFeedDetailHeaderBinding, ) : RecyclerView.ViewHolder(binding.root) { - fun bind(feed: FeedModel, commentsCount: Int) { + fun bind(feed: FeedModel) { binding.feed = feed - binding.commentsCount = commentsCount } companion object { diff --git a/app/src/main/res/layout/item_feed_detail_header.xml b/app/src/main/res/layout/item_feed_detail_header.xml index f32b0f9a8..6b27b5c32 100644 --- a/app/src/main/res/layout/item_feed_detail_header.xml +++ b/app/src/main/res/layout/item_feed_detail_header.xml @@ -7,10 +7,6 @@ - - Date: Wed, 28 Aug 2024 14:37:14 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20=EB=8C=93=EA=B8=80=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=20=EB=A6=AC=EC=8A=A4=EB=84=88=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/feedDetail/CommentClickListener.kt | 10 ++++++++ .../ui/feedDetail/FeedDetailActivity.kt | 17 ++++++++++++- .../feedDetail/adapter/FeedDetailAdapter.kt | 8 ++++-- .../adapter/FeedDetailCommentViewHolder.kt | 25 +++++++++++++------ .../main/res/layout/activity_feed_detail.xml | 8 +++--- .../res/layout/item_feed_detail_comment.xml | 11 ++++++-- 6 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/com/teamwss/websoso/ui/feedDetail/CommentClickListener.kt diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/CommentClickListener.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/CommentClickListener.kt new file mode 100644 index 000000000..3be2b6ef5 --- /dev/null +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/CommentClickListener.kt @@ -0,0 +1,10 @@ +package com.teamwss.websoso.ui.feedDetail + +import android.view.View + +interface CommentClickListener { + + fun onProfileClick(userId: Long, isMyComment: Boolean) + + fun onMoreButtonClick(view: View, commentId: Long, isMyComment: Boolean) +} diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index 447405667..fe15c37e4 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -3,10 +3,12 @@ package com.teamwss.websoso.ui.feedDetail import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.activity.viewModels import com.teamwss.websoso.R import com.teamwss.websoso.common.ui.base.BaseActivity import com.teamwss.websoso.databinding.ActivityFeedDetailBinding +import com.teamwss.websoso.databinding.MenuFeedPopupBinding import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailAdapter import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.Comment import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.Header @@ -17,9 +19,22 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class FeedDetailActivity : BaseActivity(R.layout.activity_feed_detail) { + private var _popupBinding: MenuFeedPopupBinding? = null + private val popupBinding: MenuFeedPopupBinding + get() = _popupBinding ?: error("error: binding is null") private val feedDetailViewModel: FeedDetailViewModel by viewModels() private val feedId: Long by lazy { intent.getLongExtra(FEED_ID, DEFAULT_FEED_ID) } - private val feedDetailAdapter: FeedDetailAdapter by lazy { FeedDetailAdapter() } + private val feedDetailAdapter: FeedDetailAdapter by lazy { FeedDetailAdapter(onCommentClick()) } + + private fun onCommentClick(): CommentClickListener = object : CommentClickListener { + override fun onProfileClick(userId: Long, isMyComment: Boolean) { + // if (isMyComment) 마이페이지 else 프로필 뷰 + } + + override fun onMoreButtonClick(view: View, commentId: Long, isMyComment: Boolean) { + // 더보기 기능 구현 + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt index 9f8761e36..6678f49e8 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailAdapter.kt @@ -4,13 +4,17 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView.ViewHolder +import com.teamwss.websoso.ui.feedDetail.CommentClickListener import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.Comment import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.Header import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.ItemType import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.ItemType.COMMENT import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.ItemType.HEADER -class FeedDetailAdapter : ListAdapter(diffCallBack) { +class FeedDetailAdapter( + + private val commentClickListener: CommentClickListener, +) : ListAdapter(diffCallBack) { init { setHasStableIds(true) @@ -29,7 +33,7 @@ class FeedDetailAdapter : ListAdapter(diffCallBack) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = when (ItemType.valueOf(viewType)) { HEADER -> FeedDetailContentViewHolder.from(parent) - COMMENT -> FeedDetailCommentViewHolder.from(parent) + COMMENT -> FeedDetailCommentViewHolder.from(parent, commentClickListener) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailCommentViewHolder.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailCommentViewHolder.kt index b3dd28741..93c17bc5c 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailCommentViewHolder.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/adapter/FeedDetailCommentViewHolder.kt @@ -4,25 +4,34 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.teamwss.websoso.databinding.ItemFeedDetailCommentBinding +import com.teamwss.websoso.ui.feedDetail.CommentClickListener import com.teamwss.websoso.ui.feedDetail.model.CommentModel class FeedDetailCommentViewHolder( + commentClickListener: CommentClickListener, private val binding: ItemFeedDetailCommentBinding, ) : RecyclerView.ViewHolder(binding.root) { + init { + binding.onClick = commentClickListener + } + fun bind(comment: CommentModel) { binding.comment = comment } companion object { - fun from(parent: ViewGroup): FeedDetailCommentViewHolder = - FeedDetailCommentViewHolder( - ItemFeedDetailCommentBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false, - ) - ) + fun from( + parent: ViewGroup, + commentClickListener: CommentClickListener, + ): FeedDetailCommentViewHolder = FeedDetailCommentViewHolder( + commentClickListener, + ItemFeedDetailCommentBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false, + ), + ) } } diff --git a/app/src/main/res/layout/activity_feed_detail.xml b/app/src/main/res/layout/activity_feed_detail.xml index 2796dc9aa..34cce20b7 100644 --- a/app/src/main/res/layout/activity_feed_detail.xml +++ b/app/src/main/res/layout/activity_feed_detail.xml @@ -87,9 +87,9 @@ android:id="@+id/et_feed_detail_input" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" + android:layout_marginStart="10dp" android:layout_marginTop="16dp" - android:layout_marginEnd="4dp" + android:layout_marginEnd="10dp" android:layout_marginBottom="16dp" android:background="@drawable/bg_feed_detail_gray_50_radius_14dp" android:gravity="top" @@ -111,7 +111,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="6dp" - android:layout_marginEnd="20dp" + android:layout_marginEnd="16dp" android:src="@drawable/btn_comment_register" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/et_feed_detail_input" /> @@ -119,4 +119,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/item_feed_detail_comment.xml b/app/src/main/res/layout/item_feed_detail_comment.xml index d52c4a99b..8337c9393 100644 --- a/app/src/main/res/layout/item_feed_detail_comment.xml +++ b/app/src/main/res/layout/item_feed_detail_comment.xml @@ -8,6 +8,10 @@ + + @@ -34,6 +39,7 @@ android:layout_marginStart="14dp" android:maxLength="10" android:maxLines="1" + android:onClick="@{() -> onClick.onProfileClick(comment.user.id,comment.isMyComment)}" android:text="@{comment.user.nickname}" android:textAppearance="@style/title2" android:textColor="@color/black" @@ -68,10 +74,10 @@ - \ No newline at end of file + From 0a4a63e9003bcd2726a5801dfb6b025f1192be87 Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 15:36:37 +0900 Subject: [PATCH 05/12] =?UTF-8?q?feat:=20=EB=8D=94=EB=B3=B4=EA=B8=B0=20?= =?UTF-8?q?=EB=A7=A4=EB=89=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/feedDetail/FeedDetailActivity.kt | 102 +++++++++++++++++- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index fe15c37e4..2ed2955cf 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -3,11 +3,17 @@ package com.teamwss.websoso.ui.feedDetail import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.WindowManager +import android.widget.PopupWindow import androidx.activity.viewModels +import androidx.databinding.ViewDataBinding import com.teamwss.websoso.R import com.teamwss.websoso.common.ui.base.BaseActivity import com.teamwss.websoso.databinding.ActivityFeedDetailBinding +import com.teamwss.websoso.databinding.DialogRemovePopupMenuBinding +import com.teamwss.websoso.databinding.DialogReportPopupMenuBinding import com.teamwss.websoso.databinding.MenuFeedPopupBinding import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailAdapter import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.Comment @@ -15,16 +21,19 @@ import com.teamwss.websoso.ui.feedDetail.adapter.FeedDetailType.Header import com.teamwss.websoso.ui.feedDetail.model.FeedDetailUiState.Error import com.teamwss.websoso.ui.feedDetail.model.FeedDetailUiState.Loading import com.teamwss.websoso.ui.feedDetail.model.FeedDetailUiState.Success +import com.teamwss.websoso.ui.main.feed.dialog.FeedRemoveDialogFragment +import com.teamwss.websoso.ui.main.feed.dialog.FeedReportDialogFragment import dagger.hilt.android.AndroidEntryPoint +import java.io.Serializable @AndroidEntryPoint class FeedDetailActivity : BaseActivity(R.layout.activity_feed_detail) { - private var _popupBinding: MenuFeedPopupBinding? = null - private val popupBinding: MenuFeedPopupBinding - get() = _popupBinding ?: error("error: binding is null") private val feedDetailViewModel: FeedDetailViewModel by viewModels() private val feedId: Long by lazy { intent.getLongExtra(FEED_ID, DEFAULT_FEED_ID) } private val feedDetailAdapter: FeedDetailAdapter by lazy { FeedDetailAdapter(onCommentClick()) } + private val popupBinding: MenuFeedPopupBinding by lazy { + MenuFeedPopupBinding.inflate(LayoutInflater.from(this)) + } private fun onCommentClick(): CommentClickListener = object : CommentClickListener { override fun onProfileClick(userId: Long, isMyComment: Boolean) { @@ -32,8 +41,93 @@ class FeedDetailActivity : BaseActivity(R.layout.acti } override fun onMoreButtonClick(view: View, commentId: Long, isMyComment: Boolean) { - // 더보기 기능 구현 + showMenu(view, commentId, isMyComment) + } + } + + private fun showMenu(view: View, commentId: Long, isMyComment: Boolean) { + val popupWindow: PopupWindow = PopupWindow( + popupBinding.root, + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + true + ).apply { + elevation = 2f + showAsDropDown(view) + } + + bindMenuByIsMyComment(popupWindow, isMyComment, commentId) + } + + private fun bindMenuByIsMyComment(popup: PopupWindow, isMyComment: Boolean, commentId: Long) { + with(popupBinding) { + when (isMyComment) { + true -> setupMyComment(commentId, popup) + false -> setupNotMyComment(commentId, popup) + } + } + } + + private fun MenuFeedPopupBinding.setupMyComment(commentId: Long, popup: PopupWindow) { + onFirstItemClick = { + // 댓글 수정 + popup.dismiss() } + onSecondItemClick = { + showDialog( + event = { + // 댓글 삭제 + }, + ) + popup.dismiss() + } + menuContentTitle = getString(R.string.feed_popup_menu_content_isMyFeed).split(",") + tvFeedPopupFirstItem.isSelected = true + tvFeedPopupSecondItem.isSelected = true + } + + private fun MenuFeedPopupBinding.setupNotMyComment(commentId: Long, popup: PopupWindow) { + onFirstItemClick = { + showDialog( + title = getString(R.string.report_popup_menu_spoiling_feed), + event = { + // 스포일러 신고 + }, + ) + popup.dismiss() + } + onSecondItemClick = { + showDialog( + title = getString(R.string.report_popup_menu_impertinence_feed), + event = { + // 부적절한 표현 신고 + }, + ) + popup.dismiss() + } + menuContentTitle = getString(R.string.feed_popup_menu_content_report_isNotMyFeed).split(",") + tvFeedPopupFirstItem.isSelected = false + tvFeedPopupSecondItem.isSelected = false + } + + private inline fun showDialog( + title: String? = null, + noinline event: () -> Unit, + ) { + when (Dialog::class) { + DialogRemovePopupMenuBinding::class -> FeedRemoveDialogFragment.newInstance( + event = { event() }, + ).show(supportFragmentManager, FeedRemoveDialogFragment.TAG) + + DialogReportPopupMenuBinding::class -> FeedReportDialogFragment.newInstance( + title = title ?: throw IllegalArgumentException(), + event = { event() }, + ).show(supportFragmentManager, FeedReportDialogFragment.TAG) + } + } + + fun interface FeedDialogClickListener : Serializable { + operator fun invoke() } override fun onCreate(savedInstanceState: Bundle?) { From 20782d5f0013ab718d6a4ed364ca5e723afae592 Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 16:56:12 +0900 Subject: [PATCH 06/12] =?UTF-8?q?refactor:=20=EB=8D=94=EB=B3=B4=EA=B8=B0?= =?UTF-8?q?=20=EB=A7=A4=EB=89=B4=20=EB=B6=84=EA=B8=B0=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/feedDetail/FeedDetailActivity.kt | 13 ++- .../websoso/ui/main/feed/FeedFragment.kt | 46 +++++----- .../feed/dialog/FeedRemoveDialogFragment.kt | 41 +++++++-- .../feed/dialog/FeedReportDialogFragment.kt | 89 +++++++++++++++---- .../dialog/FeedReportDoneDialogFragment.kt | 34 ++++++- .../res/layout/dialog_remove_popup_menu.xml | 15 ---- .../layout/dialog_report_done_popup_menu.xml | 12 +-- .../res/layout/dialog_report_popup_menu.xml | 20 +---- app/src/main/res/layout/item_feed.xml | 2 +- app/src/main/res/values/strings.xml | 7 +- 10 files changed, 183 insertions(+), 96 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index 2ed2955cf..8eae9fb98 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -23,6 +23,9 @@ import com.teamwss.websoso.ui.feedDetail.model.FeedDetailUiState.Loading import com.teamwss.websoso.ui.feedDetail.model.FeedDetailUiState.Success import com.teamwss.websoso.ui.main.feed.dialog.FeedRemoveDialogFragment import com.teamwss.websoso.ui.main.feed.dialog.FeedReportDialogFragment +import com.teamwss.websoso.ui.main.feed.dialog.RemoveMenuType.REMOVE_COMMENT +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_COMMENT +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.SPOILER_COMMENT import dagger.hilt.android.AndroidEntryPoint import java.io.Serializable @@ -75,6 +78,7 @@ class FeedDetailActivity : BaseActivity(R.layout.acti } onSecondItemClick = { showDialog( + menuType = REMOVE_COMMENT.name, event = { // 댓글 삭제 }, @@ -89,7 +93,7 @@ class FeedDetailActivity : BaseActivity(R.layout.acti private fun MenuFeedPopupBinding.setupNotMyComment(commentId: Long, popup: PopupWindow) { onFirstItemClick = { showDialog( - title = getString(R.string.report_popup_menu_spoiling_feed), + menuType = SPOILER_COMMENT.name, event = { // 스포일러 신고 }, @@ -98,7 +102,7 @@ class FeedDetailActivity : BaseActivity(R.layout.acti } onSecondItemClick = { showDialog( - title = getString(R.string.report_popup_menu_impertinence_feed), + menuType = IMPERTINENCE_COMMENT.name, event = { // 부적절한 표현 신고 }, @@ -111,16 +115,17 @@ class FeedDetailActivity : BaseActivity(R.layout.acti } private inline fun showDialog( - title: String? = null, + menuType: String? = null, noinline event: () -> Unit, ) { when (Dialog::class) { DialogRemovePopupMenuBinding::class -> FeedRemoveDialogFragment.newInstance( + menuType = menuType ?: throw IllegalArgumentException(), event = { event() }, ).show(supportFragmentManager, FeedRemoveDialogFragment.TAG) DialogReportPopupMenuBinding::class -> FeedReportDialogFragment.newInstance( - title = title ?: throw IllegalArgumentException(), + menuType = menuType ?: throw IllegalArgumentException(), event = { event() }, ).show(supportFragmentManager, FeedReportDialogFragment.TAG) } diff --git a/app/src/main/java/com/teamwss/websoso/ui/main/feed/FeedFragment.kt b/app/src/main/java/com/teamwss/websoso/ui/main/feed/FeedFragment.kt index 43a508281..5bedda5ec 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/main/feed/FeedFragment.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/main/feed/FeedFragment.kt @@ -27,6 +27,8 @@ import com.teamwss.websoso.ui.main.feed.adapter.FeedType.Feed import com.teamwss.websoso.ui.main.feed.adapter.FeedType.Loading import com.teamwss.websoso.ui.main.feed.dialog.FeedRemoveDialogFragment import com.teamwss.websoso.ui.main.feed.dialog.FeedReportDialogFragment +import com.teamwss.websoso.ui.main.feed.dialog.RemoveMenuType.REMOVE_FEED +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType import com.teamwss.websoso.ui.main.feed.model.CategoryModel import com.teamwss.websoso.ui.main.feed.model.FeedUiState import dagger.hilt.android.AndroidEntryPoint @@ -113,62 +115,62 @@ class FeedFragment : BaseFragment(R.layout.fragment_feed) { } } - private fun MenuFeedPopupBinding.setupNotMyFeed( + private fun MenuFeedPopupBinding.setupMyFeed( feedId: Long, popup: PopupWindow, ) { onFirstItemClick = { - showDialog( - title = getString(R.string.report_popup_menu_spoiling_feed), - event = { feedViewModel.updateReportedSpoilerFeed(feedId) }, - ) + navigateToFeedEdit(feedId) popup.dismiss() } onSecondItemClick = { - showDialog( - title = getString(R.string.report_popup_menu_impertinence_feed), - event = { feedViewModel.updateReportedImpertinenceFeed(feedId) }, + showDialog( + menuType = REMOVE_FEED.name, + event = { feedViewModel.updateRemovedFeed(feedId) }, ) popup.dismiss() } menuContentTitle = - getString(R.string.feed_popup_menu_content_report_isNotMyFeed).split(",") - tvFeedPopupFirstItem.isSelected = false - tvFeedPopupSecondItem.isSelected = false + getString(R.string.feed_popup_menu_content_isMyFeed).split(",") + tvFeedPopupFirstItem.isSelected = true + tvFeedPopupSecondItem.isSelected = true } - private fun MenuFeedPopupBinding.setupMyFeed( + private fun MenuFeedPopupBinding.setupNotMyFeed( feedId: Long, popup: PopupWindow, ) { onFirstItemClick = { - navigateToFeedEdit(feedId) + showDialog( + menuType = ReportMenuType.SPOILER_FEED.name, + event = { feedViewModel.updateReportedSpoilerFeed(feedId) }, + ) popup.dismiss() } onSecondItemClick = { - showDialog( - event = { feedViewModel.updateRemovedFeed(feedId) }, + showDialog( + menuType = ReportMenuType.IMPERTINENCE_FEED.name, + event = { feedViewModel.updateReportedImpertinenceFeed(feedId) }, ) popup.dismiss() } menuContentTitle = - getString(R.string.feed_popup_menu_content_isMyFeed).split(",") - tvFeedPopupFirstItem.isSelected = true - tvFeedPopupSecondItem.isSelected = true + getString(R.string.feed_popup_menu_content_report_isNotMyFeed).split(",") + tvFeedPopupFirstItem.isSelected = false + tvFeedPopupSecondItem.isSelected = false } private inline fun showDialog( - title: String? = null, + menuType: String, noinline event: () -> Unit, ) { when (Dialog::class) { DialogRemovePopupMenuBinding::class -> FeedRemoveDialogFragment.newInstance( - event = { event() }, + menuType = menuType, event = { event() }, ).show(childFragmentManager, FeedRemoveDialogFragment.TAG) DialogReportPopupMenuBinding::class -> FeedReportDialogFragment.newInstance( - title = title ?: throw IllegalArgumentException(), - event = { event() }, + menuType = menuType, event = { event() }, ).show(childFragmentManager, FeedReportDialogFragment.TAG) } } diff --git a/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedRemoveDialogFragment.kt b/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedRemoveDialogFragment.kt index 51fc2e523..c928b1b1c 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedRemoveDialogFragment.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedRemoveDialogFragment.kt @@ -2,13 +2,20 @@ package com.teamwss.websoso.ui.main.feed.dialog import android.os.Bundle import android.view.View -import com.teamwss.websoso.R +import com.teamwss.websoso.R.layout +import com.teamwss.websoso.R.string.remove_popup_menu_description +import com.teamwss.websoso.R.string.remove_popup_menu_description_comment +import com.teamwss.websoso.R.string.remove_popup_menu_title +import com.teamwss.websoso.R.string.remove_popup_menu_title_comment import com.teamwss.websoso.common.ui.base.BaseDialogFragment import com.teamwss.websoso.databinding.DialogRemovePopupMenuBinding import com.teamwss.websoso.ui.main.feed.FeedFragment.FeedDialogClickListener +import com.teamwss.websoso.ui.main.feed.dialog.RemoveMenuType.REMOVE_COMMENT +import com.teamwss.websoso.ui.main.feed.dialog.RemoveMenuType.REMOVE_FEED class FeedRemoveDialogFragment : - BaseDialogFragment(R.layout.dialog_remove_popup_menu) { + BaseDialogFragment(layout.dialog_remove_popup_menu) { + private val menuType: String? by lazy { arguments?.getString(MENU_TYPE) } private val onRemoveClick: FeedDialogClickListener by lazy { arguments?.getSerializable(EVENT) as FeedDialogClickListener } @@ -16,23 +23,47 @@ class FeedRemoveDialogFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.onCancelClick = { dismiss() } - binding.onRemoveClick = { + when (menuType) { + REMOVE_FEED.name -> setupRemoveFeedView() + REMOVE_COMMENT.name -> setupRemoveCommentView() + } + + binding.tvRemovePopupMenuCancel.setOnClickListener { dismiss() } + binding.tvRemovePopupMenuRemove.setOnClickListener { onRemoveClick() dismiss() } dialog?.setCanceledOnTouchOutside(false) } + private fun setupRemoveCommentView() { + binding.tvRemovePopupMenuTitle.text = getString(remove_popup_menu_title_comment) + binding.tvRemovePopupMenuDescription.text = getString(remove_popup_menu_description_comment) + } + + private fun setupRemoveFeedView() { + binding.tvRemovePopupMenuTitle.text = getString(remove_popup_menu_title) + binding.tvRemovePopupMenuDescription.text = getString(remove_popup_menu_description) + } + companion object { private const val EVENT = "EVENT" + private const val MENU_TYPE = "MENU_TYPE" const val TAG = "FeedRemoveDialogFragment" - fun newInstance(event: FeedDialogClickListener): FeedRemoveDialogFragment = + fun newInstance( + menuType: String, + event: FeedDialogClickListener, + ): FeedRemoveDialogFragment = FeedRemoveDialogFragment().also { it.arguments = Bundle().apply { + putString(MENU_TYPE, menuType) putSerializable(EVENT, event) } } } } + +enum class RemoveMenuType { + REMOVE_FEED, REMOVE_COMMENT, +} diff --git a/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt b/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt index b50c4eb57..397d24700 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt @@ -2,14 +2,22 @@ package com.teamwss.websoso.ui.main.feed.dialog import android.os.Bundle import android.view.View -import com.teamwss.websoso.R +import com.teamwss.websoso.R.layout +import com.teamwss.websoso.R.string.report_popup_menu_impertinence_comment +import com.teamwss.websoso.R.string.report_popup_menu_impertinence_feed +import com.teamwss.websoso.R.string.report_popup_menu_spoiling_comment +import com.teamwss.websoso.R.string.report_popup_menu_spoiling_feed import com.teamwss.websoso.common.ui.base.BaseDialogFragment import com.teamwss.websoso.databinding.DialogReportPopupMenuBinding import com.teamwss.websoso.ui.main.feed.FeedFragment.FeedDialogClickListener +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_COMMENT +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_FEED +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.SPOILER_COMMENT +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.SPOILER_FEED class FeedReportDialogFragment : - BaseDialogFragment(R.layout.dialog_report_popup_menu) { - private val reportTitle: String? by lazy { arguments?.getString(TITLE) } + BaseDialogFragment(layout.dialog_report_popup_menu) { + private val menuType: String? by lazy { arguments?.getString(MENU_TYPE) } private val onReportClick: FeedDialogClickListener by lazy { arguments?.getSerializable(EVENT) as FeedDialogClickListener } @@ -17,29 +25,80 @@ class FeedReportDialogFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.title = reportTitle - binding.onCancelClick = { dismiss() } - binding.onReportClick = { + when (menuType) { + SPOILER_COMMENT.name -> setupSpoilerCommentView() + IMPERTINENCE_COMMENT.name -> setupImpertinenceCommentView() + SPOILER_FEED.name -> setupSpoilerFeedView() + IMPERTINENCE_FEED.name -> setupImpertinenceFeedView() + } + + binding.tvReportPopupMenuCancel.setOnClickListener { dismiss() } + dialog?.setCanceledOnTouchOutside(false) + } + + private fun setupImpertinenceFeedView() { + binding.tvReportPopupMenuTitle.text = getString(report_popup_menu_impertinence_feed) + binding.tvReportPopupMenuReport.setOnClickListener { onReportClick() - FeedReportDoneDialogFragment.newInstance { dismiss() } + FeedReportDoneDialogFragment + .newInstance(IMPERTINENCE_FEED.name) { dismiss() } + .show(childFragmentManager, FeedReportDoneDialogFragment.TAG) + } + } + + private fun setupSpoilerFeedView() { + binding.tvReportPopupMenuTitle.text = getString(report_popup_menu_spoiling_feed) + binding.tvReportPopupMenuReport.setOnClickListener { + onReportClick() + FeedReportDoneDialogFragment + .newInstance(SPOILER_FEED.name) { dismiss() } + .show(childFragmentManager, FeedReportDoneDialogFragment.TAG) + } + } + + private fun setupImpertinenceCommentView() { + binding.tvReportPopupMenuTitle.text = getString( + report_popup_menu_impertinence_comment + ) + binding.tvReportPopupMenuReport.setOnClickListener { + onReportClick() + FeedReportDoneDialogFragment + .newInstance(IMPERTINENCE_COMMENT.name) { dismiss() } + .show(childFragmentManager, FeedReportDoneDialogFragment.TAG) + } + } + + private fun setupSpoilerCommentView() { + binding.tvReportPopupMenuTitle.text = getString(report_popup_menu_spoiling_comment) + binding.tvReportPopupMenuReport.setOnClickListener { + onReportClick() + FeedReportDoneDialogFragment + .newInstance(IMPERTINENCE_COMMENT.name) { dismiss() } .show(childFragmentManager, FeedReportDoneDialogFragment.TAG) } - dialog?.setCanceledOnTouchOutside(false) } companion object { private const val EVENT = "EVENT" - private const val TITLE = "TITLE" + private const val MENU_TYPE = "MENU_TYPE" const val TAG = "FeedReportDialogFragment" fun newInstance( - title: String, + menuType: String, event: FeedDialogClickListener, - ): FeedReportDialogFragment = FeedReportDialogFragment().also { - it.arguments = Bundle().apply { - putString(TITLE, title) - putSerializable(EVENT, event) + ): FeedReportDialogFragment = + FeedReportDialogFragment().also { + it.arguments = Bundle().apply { + putString(MENU_TYPE, menuType) + putSerializable(EVENT, event) + } } - } } } + +enum class ReportMenuType { + SPOILER_COMMENT, + IMPERTINENCE_COMMENT, + SPOILER_FEED, + IMPERTINENCE_FEED, +} diff --git a/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedReportDoneDialogFragment.kt b/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedReportDoneDialogFragment.kt index 196950954..d80d97f84 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedReportDoneDialogFragment.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/main/feed/dialog/FeedReportDoneDialogFragment.kt @@ -2,13 +2,18 @@ package com.teamwss.websoso.ui.main.feed.dialog import android.os.Bundle import android.view.View -import com.teamwss.websoso.R +import com.teamwss.websoso.R.layout +import com.teamwss.websoso.R.string.report_popup_menu_description +import com.teamwss.websoso.R.string.report_popup_menu_description_comment import com.teamwss.websoso.common.ui.base.BaseDialogFragment import com.teamwss.websoso.databinding.DialogReportDonePopupMenuBinding import com.teamwss.websoso.ui.main.feed.FeedFragment.FeedDialogClickListener +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_COMMENT +import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_FEED class FeedReportDoneDialogFragment : - BaseDialogFragment(R.layout.dialog_report_done_popup_menu) { + BaseDialogFragment(layout.dialog_report_done_popup_menu) { + private val menuType: String? by lazy { arguments?.getString(MENU_TYPE) } private val onCheckClick: FeedDialogClickListener by lazy { arguments?.getSerializable(EVENT) as FeedDialogClickListener } @@ -16,20 +21,41 @@ class FeedReportDoneDialogFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.onCheckClick = { + when (menuType) { + IMPERTINENCE_COMMENT.name -> setupImpertinenceCommentView() + IMPERTINENCE_FEED.name -> setupImpertinenceFeedView() + } + + binding.tvReportPopupMenuCheck.setOnClickListener { onCheckClick() dismiss() } dialog?.setCanceledOnTouchOutside(false) } + private fun setupImpertinenceFeedView() { + binding.tvReportPopupMenuDescription.visibility = View.VISIBLE + binding.tvReportPopupMenuDescription.text = getString(report_popup_menu_description) + } + + private fun setupImpertinenceCommentView() { + binding.tvReportPopupMenuDescription.visibility = View.VISIBLE + binding.tvReportPopupMenuDescription.text = + getString(report_popup_menu_description_comment) + } + companion object { private const val EVENT = "EVENT" + private const val MENU_TYPE = "MENU_TYPE" const val TAG = "FeedReportDoneDialogFragment" - fun newInstance(event: FeedDialogClickListener): FeedReportDoneDialogFragment = + fun newInstance( + menuType: String, + event: FeedDialogClickListener, + ): FeedReportDoneDialogFragment = FeedReportDoneDialogFragment().also { it.arguments = Bundle().apply { + putString(MENU_TYPE, menuType) putSerializable(EVENT, event) } } diff --git a/app/src/main/res/layout/dialog_remove_popup_menu.xml b/app/src/main/res/layout/dialog_remove_popup_menu.xml index 5f5077656..5a82da5fc 100644 --- a/app/src/main/res/layout/dialog_remove_popup_menu.xml +++ b/app/src/main/res/layout/dialog_remove_popup_menu.xml @@ -2,17 +2,6 @@ - - - - - - - - - - - - @@ -66,7 +59,6 @@ android:layout_marginBottom="24dp" android:background="@drawable/bg_novel_info_primary_100_radius_8dp" android:gravity="center" - android:onClick="@{()-> onCheckClick.invoke()}" android:paddingHorizontal="48dp" android:paddingVertical="12dp" android:text="@string/report_popup_menu_check" @@ -79,4 +71,4 @@ app:layout_constraintTop_toBottomOf="@+id/tv_report_popup_menu_description" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/dialog_report_popup_menu.xml b/app/src/main/res/layout/dialog_report_popup_menu.xml index 341a685f3..3bdeb1422 100644 --- a/app/src/main/res/layout/dialog_report_popup_menu.xml +++ b/app/src/main/res/layout/dialog_report_popup_menu.xml @@ -2,21 +2,6 @@ - - - - - - - - - - \ No newline at end of file + diff --git a/app/src/main/res/layout/item_feed.xml b/app/src/main/res/layout/item_feed.xml index da36b79a0..3ea174e69 100644 --- a/app/src/main/res/layout/item_feed.xml +++ b/app/src/main/res/layout/item_feed.xml @@ -262,7 +262,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" - android:onClick="@{() -> onClick.onCommentButtonClick(feed.novel.id)}" + android:onClick="@{() -> onClick.onCommentButtonClick(feed.id)}" app:layout_constraintBottom_toBottomOf="@+id/cl_feed_like" app:layout_constraintStart_toEndOf="@+id/cl_feed_like" app:layout_constraintTop_toTopOf="@+id/cl_feed_like"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e0955c2a3..303ebc866 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -100,6 +100,11 @@ 댓글 · 댓글을 남겨보세요 + 내 댓글을 삭제할까요? + 삭제한 댓글은 되돌릴 수 없어요 + 해당 댓글에 부적절한 표현이 사용되었나요? + 해당 댓글이 스포일러를 포함하고 있나요? + 해당 댓글이 커뮤니티 가이드\n위반했는지 검토할게요. 취소 @@ -287,4 +292,4 @@ 소개글을 적어보세요! 선호장르 선택한 장르에 맞춰 작품을 추천해 드려요 - \ No newline at end of file + From d08fc7d5c911f4fbe42d026e387676ac3a1880bd Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 17:47:23 +0900 Subject: [PATCH 07/12] =?UTF-8?q?feat:=20=EB=8C=93=EA=B8=80=20=EC=8B=A0?= =?UTF-8?q?=EA=B3=A0=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websoso/data/remote/api/FeedApi.kt | 12 +++++++ .../websoso/data/repository/FeedRepository.kt | 8 +++++ .../ui/feedDetail/FeedDetailActivity.kt | 13 ++----- .../ui/feedDetail/FeedDetailViewModel.kt | 36 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt b/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt index 20d885e25..8a94732e5 100644 --- a/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt +++ b/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt @@ -63,6 +63,18 @@ interface FeedApi { @Path("feedId") feedId: Long, ) + @POST("feeds/{feedId}/comments/{commentId}/spoiler") + suspend fun postSpoilerComment( + @Path("feedId") feedId: Long, + @Path("commentId") commentId: Long, + ) + + @POST("feeds/{feedId}/comments/{commentId}/impertinence") + suspend fun postImpertinenceComment( + @Path("feedId") feedId: Long, + @Path("commentId") commentId: Long, + ) + @GET("feeds/popular") suspend fun getPopularFeeds(): PopularFeedsResponseDto diff --git a/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt b/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt index 489fdb8ae..f3da54c78 100644 --- a/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt +++ b/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt @@ -33,6 +33,14 @@ class FeedRepository @Inject constructor( feedApi.postComment(feedId, CommentRequestDto(comment)) } + suspend fun saveSpoilerComment(feedId: Long, commentId: Long) { + feedApi.postSpoilerComment(feedId, commentId) + } + + suspend fun saveImpertinenceComment(feedId: Long, commentId: Long) { + feedApi.postImpertinenceComment(feedId, commentId) + } + suspend fun saveLike(isLikedOfLikedFeed: Boolean, selectedFeedId: Long) { when (isLikedOfLikedFeed) { diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index 8eae9fb98..a83195036 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -27,7 +27,6 @@ import com.teamwss.websoso.ui.main.feed.dialog.RemoveMenuType.REMOVE_COMMENT import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_COMMENT import com.teamwss.websoso.ui.main.feed.dialog.ReportMenuType.SPOILER_COMMENT import dagger.hilt.android.AndroidEntryPoint -import java.io.Serializable @AndroidEntryPoint class FeedDetailActivity : BaseActivity(R.layout.activity_feed_detail) { @@ -94,18 +93,14 @@ class FeedDetailActivity : BaseActivity(R.layout.acti onFirstItemClick = { showDialog( menuType = SPOILER_COMMENT.name, - event = { - // 스포일러 신고 - }, + event = { feedDetailViewModel.updateReportedSpoilerComment(commentId) }, ) popup.dismiss() } onSecondItemClick = { showDialog( menuType = IMPERTINENCE_COMMENT.name, - event = { - // 부적절한 표현 신고 - }, + event = { feedDetailViewModel.updateReportedImpertinenceComment(commentId) }, ) popup.dismiss() } @@ -131,10 +126,6 @@ class FeedDetailActivity : BaseActivity(R.layout.acti } } - fun interface FeedDialogClickListener : Serializable { - operator fun invoke() - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt index 8e56a1354..b2e98f875 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt @@ -68,4 +68,40 @@ class FeedDetailViewModel @Inject constructor( } } } + + fun updateReportedSpoilerComment(commentId: Long) { + feedDetailUiState.value?.let { feedUiState -> + viewModelScope.launch { + _feedDetailUiState.value = Loading + runCatching { + feedRepository.saveSpoilerComment( + (feedUiState as Success).feedDetail.feed.id, + commentId, + ) + }.onSuccess { + _feedDetailUiState.value = feedUiState as Success + }.onFailure { + _feedDetailUiState.value = Error + } + } + } + } + + fun updateReportedImpertinenceComment(commentId: Long) { + feedDetailUiState.value?.let { feedUiState -> + viewModelScope.launch { + _feedDetailUiState.value = Loading + runCatching { + feedRepository.saveImpertinenceComment( + (feedUiState as Success).feedDetail.feed.id, + commentId, + ) + }.onSuccess { + _feedDetailUiState.value = feedUiState as Success + }.onFailure { + _feedDetailUiState.value = Error + } + } + } + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6fbf37fef..169142852 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -209,6 +209,7 @@ 관심작품 등록하기 관심 등록한 작품의 최근 수다예요 로맨스, 로판, 판타지, 현판 등\n선호장르를 기반으로 웹소설을 추천해 드려요! + 선호장르를 기반으로 추천해 드려요 선호장르 설정하기 이 웹소설은 어때요? %s 님의 한마디 @@ -217,6 +218,7 @@ %1$s 님의 리뷰 %1$.1f (%2$d) %1$s 님의 관심글 + %1$.1f (%2$d) 설정 From b7f4cfab852a39142cfbb109ab9c4d5008f784cb Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 18:10:07 +0900 Subject: [PATCH 08/12] =?UTF-8?q?feat:=20=EB=8C=93=EA=B8=80=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websoso/data/remote/api/FeedApi.kt | 38 ++++++++------ .../websoso/data/repository/FeedRepository.kt | 49 ++++++++++--------- .../ui/feedDetail/FeedDetailActivity.kt | 4 +- .../ui/feedDetail/FeedDetailViewModel.kt | 24 +++++++++ .../teamwss/websoso/ui/mapper/FeedMapper.kt | 2 +- 5 files changed, 75 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt b/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt index 8a94732e5..90d321c28 100644 --- a/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt +++ b/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt @@ -27,20 +27,25 @@ interface FeedApi { @Path("feedId") feedId: Long, ): FeedDetailResponseDto + @GET("feeds/popular") + suspend fun getPopularFeeds(): PopularFeedsResponseDto + + @GET("feeds/interest") + suspend fun getUserInterestFeeds(): UserInterestFeedsResponseDto + @DELETE("feeds/{feedId}") suspend fun deleteFeed( @Path("feedId") feedId: Long, ) - @GET("feeds/{feedId}/comments") - suspend fun getComments( + @POST("feeds/{feedId}/spoiler") + suspend fun postSpoilerFeed( @Path("feedId") feedId: Long, - ): CommentsResponseDto + ) - @POST("feeds/{feedId}/comments") - suspend fun postComment( + @POST("feeds/{feedId}/impertinence") + suspend fun postImpertinenceFeed( @Path("feedId") feedId: Long, - @Body commentRequestDto: CommentRequestDto, ) @POST("feeds/{feedId}/likes") @@ -53,14 +58,21 @@ interface FeedApi { @Path("feedId") feedId: Long, ) - @POST("feeds/{feedId}/spoiler") - suspend fun postSpoilerFeed( + @GET("feeds/{feedId}/comments") + suspend fun getComments( @Path("feedId") feedId: Long, + ): CommentsResponseDto + + @POST("feeds/{feedId}/comments") + suspend fun postComment( + @Path("feedId") feedId: Long, + @Body commentRequestDto: CommentRequestDto, ) - @POST("feeds/{feedId}/impertinence") - suspend fun postImpertinenceFeed( + @DELETE("feeds/{feedId}/comments/{commentId}") + suspend fun deleteComment( @Path("feedId") feedId: Long, + @Path("commentId") commentId: Long, ) @POST("feeds/{feedId}/comments/{commentId}/spoiler") @@ -74,10 +86,4 @@ interface FeedApi { @Path("feedId") feedId: Long, @Path("commentId") commentId: Long, ) - - @GET("feeds/popular") - suspend fun getPopularFeeds(): PopularFeedsResponseDto - - @GET("feeds/interest") - suspend fun getUserInterestFeeds(): UserInterestFeedsResponseDto } diff --git a/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt b/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt index f3da54c78..70fc025b5 100644 --- a/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt +++ b/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt @@ -1,5 +1,6 @@ package com.teamwss.websoso.data.repository +import android.util.Log import com.teamwss.websoso.data.mapper.toData import com.teamwss.websoso.data.model.CommentsEntity import com.teamwss.websoso.data.model.FeedEntity @@ -16,6 +17,10 @@ class FeedRepository @Inject constructor( private val _cachedFeeds: MutableList = mutableListOf() val cachedFeeds: List get() = _cachedFeeds.toList() + fun clearCachedFeeds() { + if (cachedFeeds.isNotEmpty()) _cachedFeeds.clear() + } + suspend fun fetchFeeds(category: String, lastFeedId: Long, size: Int): FeedsEntity = feedApi.getFeeds( category = if (category == "all") null else category, @@ -27,18 +32,24 @@ class FeedRepository @Inject constructor( suspend fun fetchFeed(feedId: Long): FeedEntity = feedApi.getFeed(feedId).toData() - suspend fun fetchComments(feedId: Long): CommentsEntity = feedApi.getComments(feedId).toData() + suspend fun fetchPopularFeeds(): PopularFeedsEntity { + return feedApi.getPopularFeeds().toData() + } - suspend fun saveComment(feedId: Long, comment: String) { - feedApi.postComment(feedId, CommentRequestDto(comment)) + suspend fun fetchUserInterestFeeds(): UserInterestFeedsEntity { + return feedApi.getUserInterestFeeds().toData() } - suspend fun saveSpoilerComment(feedId: Long, commentId: Long) { - feedApi.postSpoilerComment(feedId, commentId) + suspend fun saveRemovedFeed(feedId: Long) { + feedApi.deleteFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } } - suspend fun saveImpertinenceComment(feedId: Long, commentId: Long) { - feedApi.postImpertinenceComment(feedId, commentId) + suspend fun saveSpoilerFeed(feedId: Long) { + feedApi.postSpoilerFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } + } + + suspend fun saveImpertinenceFeed(feedId: Long) { + feedApi.postImpertinenceFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } } suspend fun saveLike(isLikedOfLikedFeed: Boolean, selectedFeedId: Long) { @@ -49,27 +60,21 @@ class FeedRepository @Inject constructor( } } - suspend fun saveRemovedFeed(feedId: Long) { - feedApi.deleteFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } - } - - suspend fun saveSpoilerFeed(feedId: Long) { - feedApi.postSpoilerFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } - } + suspend fun fetchComments(feedId: Long): CommentsEntity = feedApi.getComments(feedId).toData() - suspend fun saveImpertinenceFeed(feedId: Long) { - feedApi.postImpertinenceFeed(feedId).also { _cachedFeeds.removeIf { it.id == feedId } } + suspend fun saveComment(feedId: Long, comment: String) { + feedApi.postComment(feedId, CommentRequestDto(comment)) } - fun clearCachedFeeds() { - if (cachedFeeds.isNotEmpty()) _cachedFeeds.clear() + suspend fun deleteComment(feedId: Long, commentId: Long) { + feedApi.deleteComment(feedId, commentId) } - suspend fun fetchPopularFeeds(): PopularFeedsEntity { - return feedApi.getPopularFeeds().toData() + suspend fun saveSpoilerComment(feedId: Long, commentId: Long) { + feedApi.postSpoilerComment(feedId, commentId) } - suspend fun fetchUserInterestFeeds(): UserInterestFeedsEntity { - return feedApi.getUserInterestFeeds().toData() + suspend fun saveImpertinenceComment(feedId: Long, commentId: Long) { + feedApi.postImpertinenceComment(feedId, commentId) } } diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index a83195036..7a02e5e51 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -78,9 +78,7 @@ class FeedDetailActivity : BaseActivity(R.layout.acti onSecondItemClick = { showDialog( menuType = REMOVE_COMMENT.name, - event = { - // 댓글 삭제 - }, + event = { feedDetailViewModel.updateRemovedComment(commentId) }, ) popup.dismiss() } diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt index b2e98f875..62a9418f4 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt @@ -104,4 +104,28 @@ class FeedDetailViewModel @Inject constructor( } } } + + fun updateRemovedComment(commentId: Long) { + feedDetailUiState.value?.let { feedUiState -> + viewModelScope.launch { + _feedDetailUiState.value = Loading + runCatching { + feedRepository.deleteComment( + (feedUiState as Success).feedDetail.feed.id, + commentId, + ) + }.onSuccess { + _feedDetailUiState.value = Success( + feedDetail = (feedUiState as Success).feedDetail.copy( + comments = feedUiState.feedDetail.comments.filter { + it.commentId.toLong() != commentId + } + ) + ) + }.onFailure { + _feedDetailUiState.value = Error + } + } + } + } } diff --git a/app/src/main/java/com/teamwss/websoso/ui/mapper/FeedMapper.kt b/app/src/main/java/com/teamwss/websoso/ui/mapper/FeedMapper.kt index fe40393c2..96c7a6b22 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/mapper/FeedMapper.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/mapper/FeedMapper.kt @@ -3,10 +3,10 @@ package com.teamwss.websoso.ui.mapper import com.teamwss.websoso.data.model.CommentEntity import com.teamwss.websoso.data.model.FeedEntity import com.teamwss.websoso.domain.model.Feed +import com.teamwss.websoso.ui.feedDetail.model.CommentModel import com.teamwss.websoso.ui.main.feed.model.FeedModel import com.teamwss.websoso.ui.main.feed.model.FeedModel.NovelModel import com.teamwss.websoso.ui.main.feed.model.FeedModel.UserModel -import com.teamwss.websoso.ui.feedDetail.model.CommentModel fun Feed.toUi(): FeedModel = FeedModel( user = UserModel( From 10dc703eb0972d54b510cd7219eff31ab4eb82eb Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 18:15:35 +0900 Subject: [PATCH 09/12] =?UTF-8?q?refactor:=20id=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/teamwss/websoso/data/mapper/FeedMapper.kt | 2 +- .../com/teamwss/websoso/data/model/CommentEntity.kt | 2 +- .../websoso/data/remote/response/CommentResponseDto.kt | 4 ++-- .../websoso/ui/feedDetail/FeedDetailViewModel.kt | 10 +++++----- .../websoso/ui/feedDetail/model/CommentModel.kt | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/data/mapper/FeedMapper.kt b/app/src/main/java/com/teamwss/websoso/data/mapper/FeedMapper.kt index 9e31b43c1..4e6db3144 100644 --- a/app/src/main/java/com/teamwss/websoso/data/mapper/FeedMapper.kt +++ b/app/src/main/java/com/teamwss/websoso/data/mapper/FeedMapper.kt @@ -53,7 +53,7 @@ fun CommentsResponseDto.toData(): CommentsEntity = CommentsEntity( fun CommentResponseDto.toData(): CommentEntity = CommentEntity( user = UserEntity( - id = userId.toLong(), + id = userId, nickname = nickname, avatarImage = avatarImage, ), diff --git a/app/src/main/java/com/teamwss/websoso/data/model/CommentEntity.kt b/app/src/main/java/com/teamwss/websoso/data/model/CommentEntity.kt index 3ee1f8064..3767fe38d 100644 --- a/app/src/main/java/com/teamwss/websoso/data/model/CommentEntity.kt +++ b/app/src/main/java/com/teamwss/websoso/data/model/CommentEntity.kt @@ -5,7 +5,7 @@ import com.teamwss.websoso.data.model.FeedEntity.UserEntity data class CommentEntity( val user: UserEntity, val commentContent: String, - val commentId: Int, + val commentId: Long, val createdDate: String, val isModified: Boolean, val isMyComment: Boolean, diff --git a/app/src/main/java/com/teamwss/websoso/data/remote/response/CommentResponseDto.kt b/app/src/main/java/com/teamwss/websoso/data/remote/response/CommentResponseDto.kt index 3e6d139fe..7d9737bb7 100644 --- a/app/src/main/java/com/teamwss/websoso/data/remote/response/CommentResponseDto.kt +++ b/app/src/main/java/com/teamwss/websoso/data/remote/response/CommentResponseDto.kt @@ -10,7 +10,7 @@ data class CommentResponseDto( @SerialName("commentContent") val commentContent: String, @SerialName("commentId") - val commentId: Int, + val commentId: Long, @SerialName("createdDate") val createdDate: String, @SerialName("isModified") @@ -20,5 +20,5 @@ data class CommentResponseDto( @SerialName("nickname") val nickname: String, @SerialName("userId") - val userId: Int, + val userId: Long, ) diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt index 62a9418f4..b10121935 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt @@ -60,8 +60,8 @@ class FeedDetailViewModel @Inject constructor( }.onSuccess { comments -> _feedDetailUiState.value = Success( feedDetail = (feedDetailUiState.value as Success).feedDetail.copy( - comments = comments.comments.map { it.toUi() } - ) + comments = comments.comments.map { it.toUi() }, + ), ) }.onFailure { _feedDetailUiState.value = Error @@ -118,9 +118,9 @@ class FeedDetailViewModel @Inject constructor( _feedDetailUiState.value = Success( feedDetail = (feedUiState as Success).feedDetail.copy( comments = feedUiState.feedDetail.comments.filter { - it.commentId.toLong() != commentId - } - ) + it.commentId != commentId + }, + ), ) }.onFailure { _feedDetailUiState.value = Error diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/model/CommentModel.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/model/CommentModel.kt index 7d5b38753..909c9127e 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/model/CommentModel.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/model/CommentModel.kt @@ -5,7 +5,7 @@ import com.teamwss.websoso.ui.main.feed.model.FeedModel.UserModel data class CommentModel( val user: UserModel, val commentContent: String, - val commentId: Int, + val commentId: Long, val createdDate: String, val isModified: Boolean, val isMyComment: Boolean, From db649652d7a7ef061777f2cedb0030f99ea24b98 Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 18:39:23 +0900 Subject: [PATCH 10/12] =?UTF-8?q?feat:=20=EB=8C=93=EA=B8=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websoso/data/remote/api/FeedApi.kt | 8 ++++++ .../websoso/data/repository/FeedRepository.kt | 4 +++ .../ui/feedDetail/FeedDetailActivity.kt | 25 +++++++++++++++---- .../ui/feedDetail/FeedDetailViewModel.kt | 19 ++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt b/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt index 90d321c28..661c5beb1 100644 --- a/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt +++ b/app/src/main/java/com/teamwss/websoso/data/remote/api/FeedApi.kt @@ -10,6 +10,7 @@ import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.GET import retrofit2.http.POST +import retrofit2.http.PUT import retrofit2.http.Path import retrofit2.http.Query @@ -69,6 +70,13 @@ interface FeedApi { @Body commentRequestDto: CommentRequestDto, ) + @PUT("feeds/{feedId}/comments/{commentId}") + suspend fun putComment( + @Path("feedId") feedId: Long, + @Path("commentId") commentId: Long, + @Body commentRequestDto: CommentRequestDto, + ) + @DELETE("feeds/{feedId}/comments/{commentId}") suspend fun deleteComment( @Path("feedId") feedId: Long, diff --git a/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt b/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt index 70fc025b5..8818ed862 100644 --- a/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt +++ b/app/src/main/java/com/teamwss/websoso/data/repository/FeedRepository.kt @@ -66,6 +66,10 @@ class FeedRepository @Inject constructor( feedApi.postComment(feedId, CommentRequestDto(comment)) } + suspend fun saveModifiedComment(feedId: Long, commentId: Long, comment: String) { + feedApi.putComment(feedId, commentId, CommentRequestDto(comment)) + } + suspend fun deleteComment(feedId: Long, commentId: Long) { feedApi.deleteComment(feedId, commentId) } diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index 7a02e5e51..1ce56026d 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -72,7 +72,15 @@ class FeedDetailActivity : BaseActivity(R.layout.acti private fun MenuFeedPopupBinding.setupMyComment(commentId: Long, popup: PopupWindow) { onFirstItemClick = { - // 댓글 수정 + val writtenComment = (feedDetailViewModel.feedDetailUiState.value as Success) + .feedDetail + .comments + .find { it.commentId == commentId } + ?.commentContent ?: "" + + feedDetailViewModel.updateCommentId(commentId) + binding.etFeedDetailInput.setText(writtenComment) + binding.etFeedDetailInput.requestFocus() popup.dismiss() } onSecondItemClick = { @@ -134,7 +142,10 @@ class FeedDetailActivity : BaseActivity(R.layout.acti private fun setupView() { feedDetailViewModel.updateFeedDetail(feedId) - binding.rvFeedDetail.adapter = feedDetailAdapter + binding.rvFeedDetail.apply { + adapter = feedDetailAdapter + itemAnimator = null + } } private fun setupObserver() { @@ -156,9 +167,13 @@ class FeedDetailActivity : BaseActivity(R.layout.acti private fun onCommentRegisterClick() { binding.ivFeedDetailCommentRegister.setOnClickListener { - binding.etFeedDetailInput.text.run { - feedDetailViewModel.dispatchComment(feedId, toString()) - clear() + binding.etFeedDetailInput.run { + when (feedDetailViewModel.commentId == DEFAULT_FEED_ID) { + true -> feedDetailViewModel.dispatchComment(feedId, text.toString()) + false -> feedDetailViewModel.modifyComment(feedId, text.toString()) + } + text.clear() + clearFocus() } } } diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt index b10121935..90b4b4653 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt @@ -1,5 +1,6 @@ package com.teamwss.websoso.ui.feedDetail +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -22,6 +23,12 @@ class FeedDetailViewModel @Inject constructor( ) : ViewModel() { private val _feedDetailUiState: MutableLiveData = MutableLiveData(Loading) val feedDetailUiState: LiveData get() = _feedDetailUiState + var commentId: Long = -1 + private set + + fun updateCommentId(commentId: Long) { + this.commentId = commentId + } fun updateFeedDetail(feedId: Long) { viewModelScope.launch { @@ -53,6 +60,18 @@ class FeedDetailViewModel @Inject constructor( } } + fun modifyComment(feedId: Long, comment: String) { + viewModelScope.launch { + runCatching { + feedRepository.saveModifiedComment(feedId, commentId, comment) + }.onSuccess { + updateComments(feedId) + }.onFailure { + _feedDetailUiState.value = Error + } + } + } + private fun updateComments(feedId: Long) { viewModelScope.launch { runCatching { From 338fb77d4e9e00c6c8a00134d0264b12e56a5326 Mon Sep 17 00:00:00 2001 From: s9hn Date: Wed, 28 Aug 2024 19:14:34 +0900 Subject: [PATCH 11/12] =?UTF-8?q?feat:=20=EB=8C=93=EA=B8=80=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=EC=8B=9C=20=EC=9E=90=EB=8F=99=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websoso/ui/feedDetail/FeedDetailActivity.kt | 10 +++++++++- app/src/main/res/layout/activity_feed_detail.xml | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index 6ecc40f80..4be37d423 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -161,8 +161,16 @@ class FeedDetailActivity : BaseActivity(R.layout.acti private fun updateView(feedDetailUiState: Success) { val header = Header(feedDetailUiState.feedDetail.feed) val comments = feedDetailUiState.feedDetail.comments.map { Comment(it) } + val feedDetail = listOf(header) + comments - feedDetailAdapter.submitList(listOf(header) + comments) + + when (feedDetailAdapter.itemCount == 0) { + true -> feedDetailAdapter.submitList(feedDetail) + false -> { + feedDetailAdapter.submitList(feedDetail) + binding.rvFeedDetail.smoothScrollToPosition(feedDetailAdapter.itemCount) + } + } } private fun onCommentRegisterClick() { diff --git a/app/src/main/res/layout/activity_feed_detail.xml b/app/src/main/res/layout/activity_feed_detail.xml index 34cce20b7..d56c8f871 100644 --- a/app/src/main/res/layout/activity_feed_detail.xml +++ b/app/src/main/res/layout/activity_feed_detail.xml @@ -63,6 +63,7 @@ android:layout_width="match_parent" android:layout_height="0dp" android:orientation="vertical" + android:overScrollMode="never" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_constraintBottom_toTopOf="@+id/cl_feed_detail_input" app:layout_constraintTop_toBottomOf="@+id/cl_feed_detail_toolbar" /> From 4e70a4234c5330e11660adb69da2d2742e218a8b Mon Sep 17 00:00:00 2001 From: s9hn Date: Thu, 29 Aug 2024 02:22:24 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt | 3 +-- .../com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt index 4be37d423..647ef05d2 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -52,7 +52,7 @@ class FeedDetailActivity : BaseActivity(R.layout.acti popupBinding.root, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, - true + true, ).apply { elevation = 2f showAsDropDown(view) @@ -163,7 +163,6 @@ class FeedDetailActivity : BaseActivity(R.layout.acti val comments = feedDetailUiState.feedDetail.comments.map { Comment(it) } val feedDetail = listOf(header) + comments - when (feedDetailAdapter.itemCount == 0) { true -> feedDetailAdapter.submitList(feedDetail) false -> { diff --git a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt index 90b4b4653..eff439065 100644 --- a/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt +++ b/app/src/main/java/com/teamwss/websoso/ui/feedDetail/FeedDetailViewModel.kt @@ -1,6 +1,5 @@ package com.teamwss.websoso.ui.feedDetail -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel