Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] 버그 수정 #270

Merged
merged 9 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class CommunityRepository @Inject constructor(
}
}

private suspend fun checkPostLike(
suspend fun checkPostLike(
postId: String,
userId: String,
): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.boostcamp.dreamteam.dreamdiary.core.domain.usecase.community

import com.boostcamp.dreamteam.dreamdiary.core.data.repository.AuthRepository
import com.boostcamp.dreamteam.dreamdiary.core.data.repository.CommunityRepository
import javax.inject.Inject

class GetPostIsLikeUseCase @Inject constructor(
private val communityRepository: CommunityRepository,
private val authRepository: AuthRepository,
) {
suspend operator fun invoke(postId: String): Boolean {
val userId = authRepository.getUserUID() ?: throw IllegalStateException("User is not signed in")
return communityRepository.checkPostLike(
postId = postId,
userId = userId,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.BottomAppBarDefaults
Expand All @@ -27,6 +28,10 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
Expand Down Expand Up @@ -218,6 +223,14 @@ private fun CommunityListScreenContent(
val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val bottomAppBarScrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()

val listState = rememberLazyListState()
var previousRefreshState by remember { mutableStateOf(posts.loadState.refresh) }
LaunchedEffect(posts.loadState.refresh) {
if (previousRefreshState is LoadState.Loading && posts.loadState.refresh is LoadState.NotLoading) {
listState.animateScrollToItem(0)
}
previousRefreshState = posts.loadState.refresh
}
Scaffold(
modifier = modifier
.fillMaxSize()
Expand Down Expand Up @@ -246,12 +259,15 @@ private fun CommunityListScreenContent(
) { innerPadding ->
PullToRefreshBox(
isRefreshing = posts.loadState.refresh is LoadState.Loading,
onRefresh = { posts.refresh() },
onRefresh = {
posts.refresh()
},
modifier = Modifier
.fillMaxSize()
.padding(innerPadding),
) {
LazyColumn(
state = listState,
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.boostcamp.dreamteam.dreamdiary.community.model.PostUi
import com.boostcamp.dreamteam.dreamdiary.community.model.toPostUi
import com.boostcamp.dreamteam.dreamdiary.core.data.repository.AuthRepository
import com.boostcamp.dreamteam.dreamdiary.core.domain.usecase.community.GetCommunityPostsUseCase
import com.boostcamp.dreamteam.dreamdiary.core.domain.usecase.community.GetPostIsLikeUseCase
import com.boostcamp.dreamteam.dreamdiary.core.domain.usecase.community.TogglePostLikeUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.channels.Channel
Expand All @@ -26,38 +27,40 @@ import javax.inject.Inject
class CommunityListViewModel @Inject constructor(
private val getCommunityPostsUseCase: GetCommunityPostsUseCase,
private val togglePostLikeUseCase: TogglePostLikeUseCase,
private val getPostIsLikeUseCase: GetPostIsLikeUseCase,
private val authRepository: AuthRepository,
) : ViewModel() {
private val _event = Channel<CommunityListEvent>(64)
val event = _event.receiveAsFlow()

private val toggledLikes = MutableStateFlow<Set<String>>(emptySet())
private val toggledLikes = MutableStateFlow<Map<String, Boolean>>(emptyMap())

private val toggleLike = Channel<String>()
private val toggleLikeFlow = toggleLike.consumeAsFlow()
.onEach {
togglePostLikeInternal(it)
}

val posts = getCommunityPostsUseCase()
.map { pagingData ->
pagingData.map { it.toPostUi() }
}
.map { pagingData -> pagingData.map { it.toPostUi() } }
.cachedIn(viewModelScope)
.combine(toggledLikes) { pagingData, toggledLikesSet ->
.combine(toggledLikes) { pagingData, toggledLikesMap ->
pagingData.map { postUi ->
val newIsLiked = !postUi.isLiked
val newLikeCount = if (newIsLiked) postUi.likeCount + 1 else postUi.likeCount - 1
if (toggledLikesSet.contains(postUi.id)) {
postUi.copy(
isLiked = newIsLiked,
likeCount = newLikeCount,
)
} else {
postUi
}
postUi.applyToggleLike(toggledLikesMap[postUi.id])
}
}

private fun PostUi.applyToggleLike(toggleIsLike: Boolean?): PostUi {
return toggleIsLike?.let { toggled ->
if (toggled != isLiked) {
val adjustLikeCount = likeCount + if (toggled) 1 else -1
copy(isLiked = toggled, likeCount = adjustLikeCount)
} else {
this
}
} ?: this
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if가 아니게 되었을 뿐이지 똑같잖아요 ㅋㅋㅋㅋㅋ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어쩔수 없습니다ㅠ

init {
toggleLikeFlow.launchIn(viewModelScope)
}
Expand All @@ -72,21 +75,24 @@ class CommunityListViewModel @Inject constructor(

// 내부 함수: 실제로 좋아요 토글 처리
private suspend fun togglePostLikeInternal(postId: String) {
val copiedToggledLikes = toggledLikes.value.toSet()
val previousToggledLikes = toggledLikes.value.toMap()
try {
toggledLikes.update { currentSet ->
if (currentSet.contains(postId)) {
currentSet - postId
} else {
currentSet + postId
}
// 현재 상태 가져오기
val currentIsLiked = toggledLikes.value[postId] ?: getCurrentIsLiked(postId)
val newIsLiked = !currentIsLiked
toggledLikes.update { currentMap ->
currentMap + (postId to newIsLiked)
}
togglePostLikeUseCase(postId)
} catch (e: Exception) {
// 실패하면 복원하기
toggledLikes.value = copiedToggledLikes
// 실패 시 이전 상태로 복원
toggledLikes.value = previousToggledLikes
_event.trySend(CommunityListEvent.LikePost.Failure)
Timber.e(e, "Failed to toggle like for post $postId")
}
}

private suspend fun getCurrentIsLiked(postId: String): Boolean {
return getPostIsLikeUseCase(postId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ internal fun SettingOption(
) {
Row(
modifier = modifier
.padding(8.dp)
.clickable(onClick = onClick),
.clickable(onClick = onClick)
.padding(8.dp),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

내부가 아닌 외부에서 하는 게 더 좋을 것 같긴 하지만 괜찮습니다.

verticalAlignment = Alignment.CenterVertically,
) {
Icon(
Expand Down
2 changes: 1 addition & 1 deletion feature/setting/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<string name="setting_picture">꿈 사진으로 보기</string>
<string name="setting_darkmode">테마 설정</string>
<string name="setting_information">정보</string>
<string name="setting_lock_setting">잠금설정</string>
<string name="setting_lock_setting">잠금 설정</string>
<string name="setting_check_account">로그인된 SNS 계정 확인</string>
<string name="setting_logout">로그아웃</string>
<string name="setting_withdraw">탈퇴</string>
Expand Down