Conversation
- `CachedFeedLikeState.kt`: 피드의 좋아요 여부(`isLiked`)와 좋아요 수(`likeCount`)를 관리하는 `CachedFeedLikeState` internal 데이터 클래스 추가
- `feedDetailStates` (ConcurrentHashMap)를 추가하여 피드 상세 정보의 좋아요 상태(`isLiked`, `likeCount`)를 별도로 관리하도록 개선 - `saveLikeState` 시 메인 피드 리스트(Flow)에 해당 데이터가 없는 경우에도 상세 캐시 상태를 업데이트하도록 로직 수정 - `fetchFeed` 수행 시 서버에서 조회한 최신 좋아요 상태를 `feedDetailStates` 캐시에 반영하는 로직 추가 - 캐시된 피드 존재 여부를 확인하기 위한 `findCachedFeed` 메서드 및 상세 상태 업데이트를 위한 `updateFeedDetailState` 메서드 구현
- 미동기화된 상태를 의미하는 `dirty` 관련 명칭을 사용자 의도가 반영된 대기 상태를 의미하는 `pendingLike`로 변경 - `dirtyFeedStates`, `originalFeedStates`를 각각 `pendingLikeStates`, `originalLikeStates`로 변경 - `applyDirtyState`, `trackDirtyState` 등의 메서드를 `applyPendingLikeState`, `trackPendingLikeState`로 변경하여 가독성 개선
- `UpdatedFeedRepository.kt`: 메서드명을 `syncDirtyFeeds`에서 `syncPendingLikes`로 변경하고, 좋아요 상태를 동기화한다는 점을 명확히 하도록 주석 수정 - `UpdatedFeedDetailViewModel.kt`, `FeedViewModel.kt`: ViewModel이 해제되는 시점(`onCleared`)에 호출되는 메서드명을 변경된 명칭(`syncPendingLikes`)에 맞춰 수정
- 피드별 좋아요 상태(`isLiked`)를 관리하기 위한 `pendingLikes` Flow 및 CRUD 메서드 정의 - 서버 반영 전 로컬의 임시 상태를 관리하고, 상태 일치 시 삭제하는 기능을 포함하는 `PendingFeedLikeStore` 인터페이스 구현
- `DataStoreQualifier.kt`: 좋아요 요청 보류 상태를 관리하는 DataStore를 구분하기 위한 `@PendingFeedLikeDataStore` 한정자(Qualifier) 추가
- `DataStoreQualifier.kt`: 좋아요 요청 보류 상태를 관리하는 DataStore를 구분하기 위한 `@PendingFeedLikeDataStore` 한정자(Qualifier) 추가
- `PendingFeedLikesPreferences.kt`: 피드 ID(`feedId`)와 좋아요 여부(`isLiked`)를 저장하는 `PendingFeedLikesPreferences` 및 `PendingFeedLikePreferences` 데이터 클래스 정의
- `DefaultPendingFeedLikeStore`: DataStore를 사용하여 피드 ID별 좋아요 보류 상태(`isLiked`)를 관리하는 로직 구현 - `PendingFeedLikesPreferences` 모델을 JSON 문자열로 인코딩/디코딩하여 저장하는 직렬화 로직 추가 - 보류 중인 좋아요 업데이트(`updatePendingLike`) 및 상태 일치 시 삭제(`deletePendingLikeIfMatched`) 기능 구현 - `PendingFeedLikeStoreModule`: Hilt를 이용한 `PendingFeedLikeStore` 의존성 주입 설정 추가
- `DefaultPendingFeedLikeStore`: DataStore를 사용하여 피드 ID별 좋아요 보류 상태(`isLiked`)를 관리하는 로직 구현 - `PendingFeedLikesPreferences` 모델을 JSON 문자열로 인코딩/디코딩하여 저장하는 직렬화 로직 추가 - 보류 중인 좋아요 업데이트(`updatePendingLike`) 및 상태 일치 시 삭제(`deletePendingLikeIfMatched`) 기능 구현 - `PendingFeedLikeStoreModule`: Hilt를 이용한 `PendingFeedLikeStore` 의존성 주입 설정 추가
- `PendingFeedLikeStore`: 특정 피드 ID의 보류된 좋아요 상태를 삭제하는 `deletePendingLike` 인터페이스 메서드 추가 - `DefaultPendingFeedLikeStore`: `deletePendingLike` 구현을 통해 DataStore에서 특정 피드 ID의 데이터를 삭제하고, 전체 데이터가 비어있을 경우 키 자체를 제거하도록 로직 반영
- `UpdatedFeedRepository`에 `PendingFeedLikeStore`를 주입하여 앱 종료 후에도 좋아요 상태를 유지할 수 있도록 개선 - 좋아요 상태가 변경될 때 호출되는 `updatePendingLike` 및 `deletePendingLike` 메서드 구현 - 변경된 좋아요 상태가 원본 상태와 다를 경우 로컬에 저장하고, 원본과 일치할 경우 로컬 데이터를 삭제하도록 로직 수정
- `UpdatedFeedRepository`: 서버와 좋아요 상태 동기화 성공 시, `pendingFeedLikeStore`에 저장된 임시 데이터를 삭제하는 `deleteSyncedPendingLike` 로직 구현 및 적용
- `observePendingLikes` 메서드를 통해 `pendingFeedLikeStore`의 변경 사항을 구독하고, `pendingLikeStates`를 실시간으로 업데이트하도록 수정 - 펜딩된 좋아요 상태를 모든 피드 리스트(`_sosoAllFeeds`, `_sosoRecommendedFeeds`, `_myFeeds`)에 즉각 반영하는 `applyPendingLikeStatesToCachedFeeds` 로직 구현
- `syncPendingLikes`: 동기화 시 메모리(`pendingLikeStates`)뿐만 아니라 로컬 저장소(`pendingFeedLikeStore`)의 데이터도 함께 처리하도록 수정 - `deleteSyncedPendingLike`: 동기화 완료 후 데이터를 삭제하는 로직을 메모리(`FromMemory`)와 로컬 저장소(`FromStore`)용으로 분리하여 관리 최적화 - 동기화 시작 전 빈 맵 확인 로직을 코루틴 내부로 이동하여 데이터 유실 방지 및 안정성 향상
- `UpdatedFeedRepository`: `pendingFeedLikeStore`에 대한 쓰기 작업의 순서 보장을 위해 `enqueuePendingLikeStoreWrite` 메서드 구현 및 `Job.join()`을 이용한 직렬화 로직 적용 - 초기화 시 `Flow.collect`를 통한 관찰 방식 대신 `getPendingLikes`를 호출하여 일회성으로 데이터를 복구하도록 `restorePendingLikes` 로직 수정 - `savePendingLike` 및 `deletePendingLike` 호출 시 새로운 쓰기 큐 로직을 적용하여 데이터 정합성 강화
- `pendingLikeStoreWriteLock` (Any) 및 `Job`을 이용한 순차 처리 로직을 `Mutex`와 `withLock`을 사용하는 방식으로 변경하여 코루틴 환경에서의 안정성 및 가독성 향상 - `enqueuePendingLikeStoreWrite` 메서드를 `writePendingLikeStore`로 네이밍 변경 및 로직 최적화
Walkthrough피드 좋아요 미동기화 상태 관리를 ChangesPending Likes 전환
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (1 warning, 2 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
data/feed/src/main/java/com/into/websoso/data/feed/store/PendingFeedLikeStore.kt (1)
17-20: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
deletePendingLikeIfMatched의 Boolean 반환값에 대한 문서화를 고려해보세요.메서드의 Boolean 반환값이 무엇을 의미하는지(매칭 성공 여부인지, 삭제 성공 여부인지) KDoc으로 명시하면 구현체와 호출자 모두에게 도움이 될 것입니다.
📝 KDoc 추가 예시
+ /** + * 저장된 좋아요 상태가 [isLiked]와 일치하는 경우에만 삭제합니다. + * + * `@return` 매칭되어 삭제된 경우 true, 일치하지 않아 삭제하지 않은 경우 false + */ suspend fun deletePendingLikeIfMatched( feedId: Long, isLiked: Boolean, ): Boolean🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@data/feed/src/main/java/com/into/websoso/data/feed/store/PendingFeedLikeStore.kt` around lines 17 - 20, The method deletePendingLikeIfMatched in PendingFeedLikeStore returns a Boolean but lacks documentation explaining what this return value represents (whether it indicates matching success, deletion success, or other states). Add a KDoc comment above the method that clearly documents the return value, specifying what the Boolean return type means in the context of this operation to help both implementers and callers understand the semantics.core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/feed/DefaultPendingFeedLikeStore.kt (1)
47-53: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueKotlin 인덱싱 구문 선호
Line 51에서
pendingLikes.put(feedId, isLiked)대신 Kotlin 관용적 인덱싱 구문pendingLikes[feedId] = isLiked를 사용하는 것이 더 idiomatic합니다.♻️ 제안 수정
val pendingLikes: MutableMap<Long, Boolean> = decodePendingLikes( preferences[PENDING_FEED_LIKES_KEY], ).toMutableMap() - pendingLikes.put(feedId, isLiked) + pendingLikes[feedId] = isLiked preferences[PENDING_FEED_LIKES_KEY] = encodePendingLikes(pendingLikes)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/feed/DefaultPendingFeedLikeStore.kt` around lines 47 - 53, In the DefaultPendingFeedLikeStore.kt file within the edit lambda of pendingFeedLikeDataStore, replace the Java-style map method call pendingLikes.put(feedId, isLiked) with the more idiomatic Kotlin indexing syntax pendingLikes[feedId] = isLiked. This makes the code more consistent with Kotlin conventions and improves readability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@data/feed/src/main/java/com/into/websoso/data/feed/repository/UpdatedFeedRepository.kt`:
- Around line 371-387: The syncPendingLikes() method has a race condition where
a snapshot of pending likes is read at the start, but if the user toggles the
same feed during synchronization in another ViewModel, the pending state changes
while the API call is still in flight, causing server and UI to become out of
sync. Fix this by re-checking the current pending state before deleting after
successful API completion in the onSuccess block of the runCatching in
syncPendingLikes(). Before calling deleteSyncedPendingLikeFromStore(id, isLiked)
and deleteSyncedPendingLikeFromMemory(id, isLiked), verify that the current
pending state still matches the original isLiked value from the snapshot, and
only proceed with deletion if it matches. If the state has changed, skip the
deletion and let the next sync cycle handle it.
- Around line 61-77: The restorePendingLikes() method only restores
pendingLikeStates but not originalLikeStates, causing state mismatch after app
restart. Modify the restorePendingLikes() function to also retrieve and restore
the originalLikeStates from the pendingFeedLikeStore alongside
pendingLikeStates. Update the pendingFeedLikeStore interface to include methods
that save and retrieve both pendingLikeStates and originalLikeStates together,
ensuring that when pending likes are restored after app restart, the original
server state is also available for comparison in trackPendingLikeState() and
related state management methods.
---
Nitpick comments:
In
`@core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/feed/DefaultPendingFeedLikeStore.kt`:
- Around line 47-53: In the DefaultPendingFeedLikeStore.kt file within the edit
lambda of pendingFeedLikeDataStore, replace the Java-style map method call
pendingLikes.put(feedId, isLiked) with the more idiomatic Kotlin indexing syntax
pendingLikes[feedId] = isLiked. This makes the code more consistent with Kotlin
conventions and improves readability.
In
`@data/feed/src/main/java/com/into/websoso/data/feed/store/PendingFeedLikeStore.kt`:
- Around line 17-20: The method deletePendingLikeIfMatched in
PendingFeedLikeStore returns a Boolean but lacks documentation explaining what
this return value represents (whether it indicates matching success, deletion
success, or other states). Add a KDoc comment above the method that clearly
documents the return value, specifying what the Boolean return type means in the
context of this operation to help both implementers and callers understand the
semantics.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6ba614bc-68cd-4ac2-a486-6c2c0b9bdcec
📒 Files selected for processing (10)
app/src/main/java/com/into/websoso/ui/feedDetail/UpdatedFeedDetailViewModel.ktcore/datastore/build.gradle.ktscore/datastore/src/main/java/com/into/websoso/core/datastore/datasource/feed/DefaultPendingFeedLikeStore.ktcore/datastore/src/main/java/com/into/websoso/core/datastore/datasource/feed/model/PendingFeedLikesPreferences.ktcore/datastore/src/main/java/com/into/websoso/core/datastore/di/DataStoreModule.ktcore/datastore/src/main/java/com/into/websoso/core/datastore/di/DataStoreQualifier.ktdata/feed/src/main/java/com/into/websoso/data/feed/repository/UpdatedFeedRepository.ktdata/feed/src/main/java/com/into/websoso/data/feed/repository/model/CachedFeedLikeState.ktdata/feed/src/main/java/com/into/websoso/data/feed/store/PendingFeedLikeStore.ktfeature/feed/src/main/java/com/into/websoso/feature/feed/FeedViewModel.kt
- 이미 나간 sync 요청이 성공했을 때 최신 로컬 상태와 다시 맞춰보는 보정 로직 - `UpdatedFeedRepository.kt`: 좋아요 동기화 성공 시 현재 상태를 재확인하여 처리하는 `handleSyncedPendingLike` 메서드 추가 - 동기화 중 사용자가 좋아요 상태를 변경한 경우, 해당 변경 사항이 유실되지 않도록 `pendingLikeStates`를 유지하고 업데이트하는 로직 적용 - 피드 캐시 또는 상세 상태에서 현재 좋아요 상태를 조회하는 `findCurrentLikeState` 메서드 추가로 데이터 정합성 강화
- 앱 재시작 후 pending 병합 시, 서버 원본 isLiked를 originalLikeStates에 기록해서 pending 제거 판단 기준을 복구 - `UpdatedFeedRepository` 내 `applyPendingLikeState` 및 `applyPendingLikeStateToDetail` 함수에서 좋아요 상태 변경 전 원본 값을 `originalLikeStates`에 저장하도록 수정하여 데이터 일관성 보장 기반 마련
- `DefaultPendingFeedLikeStore.kt`: `pendingLikes.put(feedId, isLiked)` 호출 방식을 코틀린 관용구인 인덱스 연산자(`[]`) 사용으로 변경
- `PendingFeedLikeStore.kt`: `deletePendingLikeIfMatched` 메서드에 파라미터 설명 및 반환값 정의를 포함한 KDoc 주석 추가
📌𝘐𝘴𝘴𝘶𝘦𝘴
📎𝘞𝘰𝘳𝘬 𝘋𝘦𝘴𝘤𝘳𝘪𝘱𝘵𝘪𝘰𝘯
📷𝘚𝘤𝘳𝘦𝘦𝘯𝘴𝘩𝘰𝘵
💬𝘛𝘰 𝘙𝘦𝘷𝘪𝘦𝘸𝘦𝘳𝘴
Summary by CodeRabbit
릴리스 노트