Skip to content

Commit

Permalink
feat(ChildCommentsActivity): 댓글 하이라이팅 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
ki960213 committed Dec 14, 2023
1 parent 6219159 commit b91f79a
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import android.os.Bundle
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.emmsale.R
import com.emmsale.data.model.Comment
import com.emmsale.databinding.ActivityChildCommentsBinding
import com.emmsale.presentation.base.NetworkActivity
import com.emmsale.presentation.common.extension.hideKeyboard
import com.emmsale.presentation.common.extension.showKeyboard
import com.emmsale.presentation.common.extension.showSnackBar
import com.emmsale.presentation.common.layoutManager.CenterSmoothScroller
import com.emmsale.presentation.common.layoutManager.EndSmoothScroller
import com.emmsale.presentation.common.recyclerView.DividerItemDecoration
import com.emmsale.presentation.common.views.InfoDialog
import com.emmsale.presentation.common.views.WarningDialog
Expand All @@ -24,18 +27,26 @@ import com.emmsale.presentation.ui.childCommentList.ChildCommentsViewModel.Compa
import com.emmsale.presentation.ui.childCommentList.recyclerView.CommentsAdapter
import com.emmsale.presentation.ui.childCommentList.uiState.ChildCommentsUiEvent
import com.emmsale.presentation.ui.feedDetail.FeedDetailActivity
import com.emmsale.presentation.ui.feedDetail.uiState.CommentsUiState
import com.emmsale.presentation.ui.profile.ProfileActivity
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
class ChildCommentsActivity :
NetworkActivity<ActivityChildCommentsBinding>(R.layout.activity_child_comments) {

override val viewModel: ChildCommentsViewModel by viewModels()

@Inject
lateinit var centerSmoothScroller: CenterSmoothScroller

@Inject
lateinit var endSmoothScroller: EndSmoothScroller

private val commentsAdapter: CommentsAdapter = CommentsAdapter(
onCommentClick = { comment -> viewModel.unhighlight(comment.id) },
onCommentClick = { },
onAuthorImageClick = { authorId -> ProfileActivity.startActivity(this, authorId) },
onCommentMenuClick = ::showCommentMenuDialog,
)
Expand Down Expand Up @@ -63,9 +74,21 @@ class ChildCommentsActivity :

private fun BottomMenuDialog.addCommentUpdateButton(commentId: Long) {
addMenuItemBelow(context.getString(R.string.all_update_button_label)) {
viewModel.setEditMode(true, commentId)
viewModel.startEditComment(commentId)
binding.stiwCommentUpdate.requestFocusOnEditText()
showKeyboard()
startToEditComment(commentId)
}
}

private fun startToEditComment(commentId: Long) {
val position = getCommentPosition(commentId)

lifecycleScope.launch {
delay(KEYBOARD_SHOW_WAITING_TIME)
binding.rvChildcommentsChildcomments
.layoutManager
?.startSmoothScroll(endSmoothScroller.apply { targetPosition = position })
}
}

Expand Down Expand Up @@ -130,7 +153,7 @@ class ChildCommentsActivity :
hideKeyboard()
}
binding.onCommentUpdateCancelButtonClick = {
viewModel.setEditMode(false)
viewModel.cancelEditComment()
hideKeyboard()
}
binding.onUpdatedCommentSubmitButtonClick = {
Expand Down Expand Up @@ -172,25 +195,38 @@ class ChildCommentsActivity :

private fun observeComments() {
viewModel.comments.observe(this) {
commentsAdapter.submitList(it.commentUiStates) { scrollToIfFirstFetch(it) }
commentsAdapter.submitList(it.commentUiStates) { handleHighlightComment() }
}
}

private fun scrollToIfFirstFetch(commentUiState: CommentsUiState) {
fun cantScroll(): Boolean =
viewModel.isAlreadyFirstFetched || commentUiState.commentUiStates.isEmpty()

if (highlightCommentId == INVALID_COMMENT_ID || cantScroll()) return
val position = viewModel.comments.value.commentUiStates
.indexOfFirst {
it.comment.id == highlightCommentId
}
binding.rvChildcommentsChildcomments.scrollToPosition(position)
private fun handleHighlightComment() {
if (highlightCommentId == INVALID_COMMENT_ID || isNotRealFirstEnter()) return

viewModel.highlight(highlightCommentId)
viewModel.isAlreadyFirstFetched = true
viewModel.highlightCommentOnFirstEnter(highlightCommentId)
highlightCommentOnFirstEnter()
}

private fun isNotRealFirstEnter(): Boolean =
viewModel.isAlreadyFirstFetched || viewModel.comments.value.commentUiStates.isEmpty()

private fun highlightCommentOnFirstEnter() {
val position = getCommentPosition(highlightCommentId)

binding.rvChildcommentsChildcomments.scrollToPosition(position)
lifecycleScope.launch {
delay(100L) // 버그 때문에
binding.rvChildcommentsChildcomments
.layoutManager
?.startSmoothScroll(centerSmoothScroller.apply { targetPosition = position })
}
}

private fun getCommentPosition(commentId: Long): Int = viewModel.comments.value.commentUiStates
.indexOfFirst { commentUiState ->
commentUiState.comment.id == commentId
}

private fun observeUiEvent() {
viewModel.uiEvent.observe(this, ::handleUiEvent)
}
Expand Down Expand Up @@ -242,6 +278,7 @@ class ChildCommentsActivity :
private const val KEY_HIGHLIGHT_COMMENT_ID = "KEY_HIGHLIGHT_COMMENT_ID"
private const val KEY_FROM_POST_DETAIL = "KEY_FROM_POST_DETAIL"
private const val INVALID_COMMENT_ID: Long = -1
private const val KEYBOARD_SHOW_WAITING_TIME = 300L

fun startActivity(
context: Context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.map
import androidx.lifecycle.viewModelScope
import com.emmsale.data.repository.interfaces.CommentRepository
import com.emmsale.data.repository.interfaces.TokenRepository
import com.emmsale.presentation.base.RefreshableViewModel
Expand All @@ -14,6 +15,8 @@ import com.emmsale.presentation.ui.childCommentList.uiState.ChildCommentsUiEvent
import com.emmsale.presentation.ui.feedDetail.uiState.CommentsUiState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.properties.Delegates.vetoable

Expand Down Expand Up @@ -46,6 +49,8 @@ class ChildCommentsViewModel @Inject constructor(
private val _canSubmitComment = NotNullMutableLiveData(true)
val canSubmitComment: NotNullLiveData<Boolean> = _canSubmitComment

private var unhighlightJob: Job? = null

private val _uiEvent = SingleLiveEvent<ChildCommentsUiEvent>()
val uiEvent: LiveData<ChildCommentsUiEvent> = _uiEvent

Expand Down Expand Up @@ -80,8 +85,23 @@ class ChildCommentsViewModel @Inject constructor(
onFailure = { _, _ -> _uiEvent.value = ChildCommentsUiEvent.CommentDeleteFail },
)

fun setEditMode(isEditMode: Boolean, commentId: Long = INVALID_COMMENT_ID) {
_editingCommentId.value = if (isEditMode) commentId else null
fun startEditComment(commentId: Long) {
_editingCommentId.value = commentId
unhighlightJob?.cancel()
_comments.value = _comments.value.highlight(commentId)
}

fun cancelEditComment() {
_editingCommentId.value = null
_comments.value = _comments.value.unhighlight()
}

fun highlightCommentOnFirstEnter(commentId: Long) {
_comments.value = _comments.value.highlight(commentId)
unhighlightJob = viewModelScope.launch {
delay(COMMENT_HIGHLIGHTING_DURATION_ON_FIRST_ENTER)
_comments.value = _comments.value.unhighlight()
}
}

fun reportComment(commentId: Long): Job = command(
Expand All @@ -106,24 +126,12 @@ class ChildCommentsViewModel @Inject constructor(
onSuccess = { _comments.value = CommentsUiState(uid, it) },
)

fun highlight(commentId: Long) {
val comment = _comments.value.commentUiStates.find { it.comment.id == commentId } ?: return
if (comment.isHighlight) return
_comments.value = _comments.value.highlight(commentId)
}

fun unhighlight(commentId: Long) {
val comment = _comments.value.commentUiStates.find { it.comment.id == commentId } ?: return
if (!comment.isHighlight) return
_comments.value = _comments.value.unhighlight()
}

companion object {
const val KEY_FEED_ID = "KEY_FEED_ID"
const val KEY_PARENT_COMMENT_ID = "KEY_PARENT_COMMENT_ID"

private const val INVALID_COMMENT_ID: Long = -1

private const val REPORT_DUPLICATE_ERROR_CODE = 400

private const val COMMENT_HIGHLIGHTING_DURATION_ON_FIRST_ENTER = 2000L
}
}

0 comments on commit b91f79a

Please sign in to comment.