Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SplashViewModel에서 토큰 체크 + Remote Config fetch 병렬 실행 - 팝업이 닫히기 전까지 네비게이션 차단 (uiState.first) - BuyOrNotViewModel에서 업데이트 로직 제거 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Walkthrough앱 업데이트 전략을 Firebase RemoteConfig로 구현하며, 스플래시 화면에 소프트/강제 업데이트 다이얼로그를 추가합니다. 네비게이션 계층 전반에 Changes
Sequence DiagramsequenceDiagram
participant MainActivity as MainActivity
participant BuyOrNotApp as BuyOrNotApp
participant NavHost as BuyOrNotNavHost
participant SplashRoute as SplashRoute
participant ViewModel as SplashViewModel
participant Repository as AppUpdateRepository
participant RemoteConfig as RemoteConfigDataSource
participant Preferences as AppPreferencesRepository
participant Dialog as Update Dialog
MainActivity->>BuyOrNotApp: onFinish: finishAffinity()
BuyOrNotApp->>NavHost: onFinish callback
NavHost->>SplashRoute: onFinish callback
SplashRoute->>ViewModel: 스플래시 초기화
ViewModel->>Repository: getAppUpdateInfo() 비동기 조회
Repository->>RemoteConfig: fetchAppUpdateConfig()
RemoteConfig-->>Repository: AppUpdateInfo 반환
ViewModel->>Preferences: lastSoftUpdateShownTime 확인
Repository-->>ViewModel: 버전 및 전략 정보 수신
ViewModel->>ViewModel: UpdateStrategy 기반 DialogType 결정
ViewModel-->>SplashRoute: uiState.updateDialogType 업데이트
SplashRoute->>Dialog: SOFT/FORCE 다이얼로그 표시
Dialog->>ViewModel: DismissSoftUpdate 인텐트
ViewModel->>Preferences: lastSoftUpdateShownTime 저장
Dialog->>SplashRoute: onFinish 콜백 (강제 업데이트)
SplashRoute->>MainActivity: onFinish 실행
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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: 5
🧹 Nitpick comments (1)
feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/navigation/AuthNavigation.kt (1)
27-33: KDoc에onFinish파라미터 문서화 누락
@param onFinish설명이 KDoc에 추가되지 않았습니다. 강제 업데이트 시 앱 종료를 위한 콜백임을 명시하면 좋겠습니다.📝 제안하는 수정
* `@param` onNavigateToLogin 로그인 화면으로 이동할 때 실행될 콜백 * `@param` onNavigateToHome 홈 화면으로 이동할 때 실행될 콜백 + * `@param` onFinish 강제 업데이트 다이얼로그에서 앱 종료 시 실행될 콜백 */🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/navigation/AuthNavigation.kt` around lines 27 - 33, KDoc for the NavGraphBuilder.splashScreen function is missing documentation for the onFinish parameter; update the KDoc block for splashScreen to add an `@param` onFinish entry that clearly states it is a callback invoked to finish/exit the app (e.g., "앱 종료를 위한 콜백, 스플래시 완료 시 호출됨"), so readers see the purpose of onFinish alongside onNavigateToLogin and onNavigateToHome.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@core/data/src/main/java/com/sseotdabwa/buyornot/core/data/datasource/RemoteConfigDataSourceImpl.kt`:
- Around line 35-36: RemoteConfigDataSourceImpl currently lets exceptions from
remoteConfig.fetchAndActivate().await() bubble up, which causes
SplashViewModel.checkTokenAndNavigate()/appUpdateRepository.getAppUpdateInfo()
to see updateInfo==null and force UpdateDialogType.None; wrap the
fetchAndActivate() call in a try/catch inside RemoteConfigDataSourceImpl (around
the fetchAndActivate().await() usage), log the exception, and return a safe
fallback (e.g., false or cached/previous Remote Config values) instead of
rethrowing so transient Remote Config failures are absorbed at this layer and
downstream callers like determineDialogType can continue using defaults or
cached values.
In `@docs/PR-bugfix-65-qa-2.md`:
- Around line 1-53: The PR includes a documentation file that documents a
different change set (it contains "closed `#65`" and the bugfix/refactor list)
while the PR title and scope are about "#83 업데이트 전략 구현"; either replace the
document content so it accurately describes the `#83` update strategy (update the
top header, checklist, Work Description and changed-file lists to reflect `#83`)
or remove/exclude this markdown from the commit/PR; locate the markdown that
currently contains "closed `#65`" and the Work Description sections (the
PR-bugfix-65-qa-2.md content) and update or remove it, then re-commit so the PR
body and changed files match the `#83` scope.
- Around line 37-40: Update the document to reflect the actual behavior of
HomeViewModel.optimisticVoteUpdate by replacing "API 응답 확정 전까지 UI에 결과를 반영하지 않도록
처리" with "수정: 투표 시 낙관적 업데이트로 투표 결과를 즉시 반영하도록 처리" and add a brief note
referencing HomeViewModel.optimisticVoteUpdate as the implemented method; if
instead you intend to prevent premature exposure, explicitly describe the
mitigation approach that would be implemented (e.g., delaying UI update until
API confirms) and reference the same HomeViewModel.optimisticVoteUpdate as the
place to change.
In
`@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt`:
- Around line 116-119: The dismissSoftUpdate function currently only clears
updateDialogType after the timestamp save completes, which can block
checkTokenAndNavigate if updateLastSoftUpdateShownTime fails or stalls; change
dismissSoftUpdate (and its viewModelScope.launch) to call updateState {
it.copy(updateDialogType = UpdateDialogType.None) } in a finally block so the
dialog state is always cleared regardless of success, and move
appPreferencesRepository.updateLastSoftUpdateShownTime(...) into the try block
(optionally catch and log the exception) to ensure checkTokenAndNavigate is not
indefinitely blocked.
- Around line 100-104: The FORCE branch currently returns UpdateDialogType.Force
whenever updateInfo.updateStrategy == UpdateStrategy.FORCE, which ignores
latestVersion; change the condition to require the user is actually behind the
latest release (i.e., combine updateInfo.updateStrategy == UpdateStrategy.FORCE
with currentVersion < updateInfo.latestVersion) so that UpdateDialogType.Force
is only returned for users with currentVersion < updateInfo.latestVersion (keep
the existing currentVersion < updateInfo.minimumVersion and the SOFT branch
logic intact); update the when expression that references currentVersion,
updateInfo.minimumVersion, updateInfo.latestVersion, and
updateInfo.updateStrategy accordingly.
---
Nitpick comments:
In
`@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/navigation/AuthNavigation.kt`:
- Around line 27-33: KDoc for the NavGraphBuilder.splashScreen function is
missing documentation for the onFinish parameter; update the KDoc block for
splashScreen to add an `@param` onFinish entry that clearly states it is a
callback invoked to finish/exit the app (e.g., "앱 종료를 위한 콜백, 스플래시 완료 시 호출됨"), so
readers see the purpose of onFinish alongside onNavigateToLogin and
onNavigateToHome.
🪄 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: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 244fb78f-b697-4f15-babb-dc02d4d81505
📒 Files selected for processing (22)
app/src/main/java/com/sseotdabwa/buyornot/MainActivity.ktapp/src/main/java/com/sseotdabwa/buyornot/navigation/BuyOrNotNavHost.ktapp/src/main/java/com/sseotdabwa/buyornot/ui/BuyOrNotApp.ktapp/src/main/java/com/sseotdabwa/buyornot/ui/BuyOrNotViewModel.ktcore/data/build.gradle.ktscore/data/src/main/java/com/sseotdabwa/buyornot/core/data/datasource/RemoteConfigDataSource.ktcore/data/src/main/java/com/sseotdabwa/buyornot/core/data/datasource/RemoteConfigDataSourceImpl.ktcore/data/src/main/java/com/sseotdabwa/buyornot/core/data/di/DataModule.ktcore/data/src/main/java/com/sseotdabwa/buyornot/core/data/di/RemoteConfigModule.ktcore/data/src/main/java/com/sseotdabwa/buyornot/core/data/repository/AppPreferencesRepositoryImpl.ktcore/data/src/main/java/com/sseotdabwa/buyornot/core/data/repository/AppUpdateRepositoryImpl.ktcore/datastore/src/main/java/com/sseotdabwa/buyornot/core/datastore/AppPreferencesDataSource.ktcore/datastore/src/main/java/com/sseotdabwa/buyornot/core/datastore/AppPreferencesDataSourceImpl.ktdocs/PR-bugfix-65-qa-2.mddomain/src/main/java/com/sseotdabwa/buyornot/domain/model/AppUpdateInfo.ktdomain/src/main/java/com/sseotdabwa/buyornot/domain/repository/AppPreferencesRepository.ktdomain/src/main/java/com/sseotdabwa/buyornot/domain/repository/AppUpdateRepository.ktfeature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/navigation/AuthNavigation.ktfeature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashContract.ktfeature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashScreen.ktfeature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.ktgradle/libs.versions.toml
There was a problem hiding this comment.
♻️ Duplicate comments (2)
feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt (2)
118-123:⚠️ Potential issue | 🟠 Major타임스탬프 저장 실패 시 스플래시에서 영구 대기 상태에 빠집니다.
updateLastSoftUpdateShownTime호출이 실패하거나 지연되면updateState가 실행되지 않아checkTokenAndNavigate()의uiState.first { it.updateDialogType == UpdateDialogType.None }조건이 충족되지 않습니다. 사용자가 "나중에" 버튼을 눌러도 앱이 멈춘 상태로 남게 됩니다.🛠️ finally 블록으로 상태 해제 보장
private fun dismissSoftUpdate() { viewModelScope.launch { - appPreferencesRepository.updateLastSoftUpdateShownTime(System.currentTimeMillis()) - updateState { it.copy(updateDialogType = UpdateDialogType.None) } + try { + appPreferencesRepository.updateLastSoftUpdateShownTime(System.currentTimeMillis()) + } catch (e: CancellationException) { + throw e + } catch (e: Exception) { + Log.w(TAG, "Failed to persist soft update dismissal", e) + } finally { + updateState { it.copy(updateDialogType = UpdateDialogType.None) } + } } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt` around lines 118 - 123, In dismissSoftUpdate ensure updateDialogType is reset even if appPreferencesRepository.updateLastSoftUpdateShownTime fails by moving updateState into a finally (or use runCatching { ... }.onFailure { ... } .also { updateState(...) } pattern); specifically, in the dismissSoftUpdate function call updateLastSoftUpdateShownTime inside a try and call updateState { it.copy(updateDialogType = UpdateDialogType.None) } in finally so that checkTokenAndNavigate's uiState.first { it.updateDialogType == UpdateDialogType.None } can proceed regardless of persistence errors.
102-104:⚠️ Potential issue | 🔴 Critical
FORCE전략에서 버전 비교가 누락되어 최신 버전 사용자도 차단됩니다.현재 로직은
updateStrategy == FORCE일 때 버전 비교 없이 바로UpdateDialogType.Force를 반환합니다. Remote Config를FORCE로 설정하는 순간 이미 최신 버전을 사용 중인 사용자도 강제 업데이트 팝업에 막히게 됩니다.🛠️ 버전 비교 조건 추가
return when { currentVersion < updateInfo.minimumVersion -> UpdateDialogType.Force - updateInfo.updateStrategy == UpdateStrategy.FORCE -> UpdateDialogType.Force + updateInfo.updateStrategy == UpdateStrategy.FORCE && + currentVersion < updateInfo.latestVersion -> UpdateDialogType.Force updateInfo.updateStrategy == UpdateStrategy.SOFT &&🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt` around lines 102 - 104, The force-update branch in SplashViewModel erroneously returns UpdateDialogType.Force whenever updateInfo.updateStrategy == UpdateStrategy.FORCE without checking the user's currentVersion; change the condition so the FORCE strategy only triggers a forced update when the user is actually below the required version (e.g., require currentVersion < updateInfo.minimumVersion in the branch that checks updateInfo.updateStrategy == UpdateStrategy.FORCE), referencing the currentVersion, updateInfo.minimumVersion, updateInfo.updateStrategy and UpdateDialogType to locate and fix the logic.
🧹 Nitpick comments (2)
feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt (2)
72-75: 패키지 정보 조회 예외 처리 고려
getPackageInfo()는 이론적으로NameNotFoundException을 던질 수 있습니다. 자체 패키지 조회이므로 실제로 발생할 가능성은 거의 없지만, 방어적 코딩 차원에서 예외 처리를 추가하면 더 안전합니다.♻️ 방어적 예외 처리 추가
val currentVersion = - PackageInfoCompat - .getLongVersionCode(context.packageManager.getPackageInfo(context.packageName, 0)) - .toInt() + runCatching { + PackageInfoCompat + .getLongVersionCode(context.packageManager.getPackageInfo(context.packageName, 0)) + .toInt() + }.getOrElse { + Log.e(TAG, "Failed to get package version", it) + 0 // 버전 0은 모든 minimumVersion보다 낮으므로 강제 업데이트 트리거 + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt` around lines 72 - 75, Wrap the package info lookup in a try/catch in SplashViewModel around the call to PackageInfoCompat.getLongVersionCode(context.packageManager.getPackageInfo(context.packageName, 0)) to handle android.content.pm.PackageManager.NameNotFoundException; on catch, log the exception (or use existing logger) and use a safe default for currentVersion (e.g., 0) so the app remains stable if package info cannot be retrieved.
59-66: 예외 로깅 누락으로 디버깅이 어려워질 수 있습니다.
userPreferencesRepository.userType.first()호출 시 발생하는 예외가 무시되고 있어, 프로덕션에서 토큰 검증 실패 원인을 추적하기 어렵습니다.♻️ 예외 로깅 추가 제안
val hasValidToken = try { userPreferencesRepository.userType.first() != UserType.GUEST } catch (e: CancellationException) { throw e } catch (e: Exception) { + Log.w(TAG, "Failed to check user token", e) false }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt` around lines 59 - 66, The exception thrown from userPreferencesRepository.userType.first() inside the hasValidToken computation is being swallowed, making post-deploy debugging hard; update the catch (e: Exception) branch in SplashViewModel's hasValidToken logic to log the exception (preserving the existing CancellationException rethrow) before returning false—use the project's logging facility (e.g., Logger/Timber/Log) and include context like "failed to read userType in SplashViewModel" and the exception so the root cause is recorded.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In
`@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt`:
- Around line 118-123: In dismissSoftUpdate ensure updateDialogType is reset
even if appPreferencesRepository.updateLastSoftUpdateShownTime fails by moving
updateState into a finally (or use runCatching { ... }.onFailure { ... } .also {
updateState(...) } pattern); specifically, in the dismissSoftUpdate function
call updateLastSoftUpdateShownTime inside a try and call updateState {
it.copy(updateDialogType = UpdateDialogType.None) } in finally so that
checkTokenAndNavigate's uiState.first { it.updateDialogType ==
UpdateDialogType.None } can proceed regardless of persistence errors.
- Around line 102-104: The force-update branch in SplashViewModel erroneously
returns UpdateDialogType.Force whenever updateInfo.updateStrategy ==
UpdateStrategy.FORCE without checking the user's currentVersion; change the
condition so the FORCE strategy only triggers a forced update when the user is
actually below the required version (e.g., require currentVersion <
updateInfo.minimumVersion in the branch that checks updateInfo.updateStrategy ==
UpdateStrategy.FORCE), referencing the currentVersion,
updateInfo.minimumVersion, updateInfo.updateStrategy and UpdateDialogType to
locate and fix the logic.
---
Nitpick comments:
In
`@feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt`:
- Around line 72-75: Wrap the package info lookup in a try/catch in
SplashViewModel around the call to
PackageInfoCompat.getLongVersionCode(context.packageManager.getPackageInfo(context.packageName,
0)) to handle android.content.pm.PackageManager.NameNotFoundException; on catch,
log the exception (or use existing logger) and use a safe default for
currentVersion (e.g., 0) so the app remains stable if package info cannot be
retrieved.
- Around line 59-66: The exception thrown from
userPreferencesRepository.userType.first() inside the hasValidToken computation
is being swallowed, making post-deploy debugging hard; update the catch (e:
Exception) branch in SplashViewModel's hasValidToken logic to log the exception
(preserving the existing CancellationException rethrow) before returning
false—use the project's logging facility (e.g., Logger/Timber/Log) and include
context like "failed to read userType in SplashViewModel" and the exception so
the root cause is recorded.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: cfcc235f-f1c2-49a2-95ad-76602011bfef
📒 Files selected for processing (2)
feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashContract.ktfeature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt
🚧 Files skipped from review as they are similar to previous changes (1)
- feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashContract.kt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
core/datastore/src/main/java/com/sseotdabwa/buyornot/core/datastore/UserPreferencesDataSourceImpl.kt (1)
41-45: 예외 처리 시 로깅 추가 고려
UserType.valueOf()파싱 실패 시 기본값으로 폴백하는 방어적 패턴은 적절하지만, 디버깅을 위해 로깅을 추가하면 더 좋습니다. (동일한 패턴이 lines 55-59에도 존재)📝 로깅 추가 제안
prefs[Keys.USER_TYPE]?.let { try { UserType.valueOf(it) } catch (e: IllegalArgumentException) { + // Log.w("UserPreferences", "Invalid UserType value: $it", e) UserPreferences().userType } } ?: UserPreferences().userType,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core/datastore/src/main/java/com/sseotdabwa/buyornot/core/datastore/UserPreferencesDataSourceImpl.kt` around lines 41 - 45, The code in UserPreferencesDataSourceImpl is swallowing IllegalArgumentException from UserType.valueOf(...) and silently falling back to UserPreferences().userType; update the catch block to log the invalid input value and the exception (include the offending string and e) using the module logger before returning the default, and apply the same logging change to the second identical parsing spot that also uses UserType.valueOf(...) so failures are recorded for debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@core/datastore/src/main/java/com/sseotdabwa/buyornot/core/datastore/UserPreferencesDataSourceImpl.kt`:
- Around line 41-45: The code in UserPreferencesDataSourceImpl is swallowing
IllegalArgumentException from UserType.valueOf(...) and silently falling back to
UserPreferences().userType; update the catch block to log the invalid input
value and the exception (include the offending string and e) using the module
logger before returning the default, and apply the same logging change to the
second identical parsing spot that also uses UserType.valueOf(...) so failures
are recorded for debugging.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 55d6af08-1400-490d-9c61-9689ee51cb68
📒 Files selected for processing (9)
core/data/src/main/java/com/sseotdabwa/buyornot/core/data/datasource/RemoteConfigDataSourceImpl.ktcore/data/src/main/java/com/sseotdabwa/buyornot/core/data/repository/AppUpdateRepositoryImpl.ktcore/datastore/src/main/java/com/sseotdabwa/buyornot/core/datastore/AppPreferencesDataSourceImpl.ktcore/datastore/src/main/java/com/sseotdabwa/buyornot/core/datastore/UserPreferencesDataSourceImpl.ktcore/network/src/main/java/com/sseotdabwa/buyornot/core/network/AuthEventBus.ktdocs/CommitConvention.mddocs/Modularization.mddocs/SnackbarStateManagement.mdfeature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt
💤 Files with no reviewable changes (3)
- docs/CommitConvention.md
- docs/Modularization.md
- docs/SnackbarStateManagement.md
🚧 Files skipped from review as they are similar to previous changes (4)
- core/data/src/main/java/com/sseotdabwa/buyornot/core/data/repository/AppUpdateRepositoryImpl.kt
- core/datastore/src/main/java/com/sseotdabwa/buyornot/core/datastore/AppPreferencesDataSourceImpl.kt
- core/data/src/main/java/com/sseotdabwa/buyornot/core/data/datasource/RemoteConfigDataSourceImpl.kt
- feature/auth/src/main/java/com/sseotdabwa/buyornot/feature/auth/ui/SplashViewModel.kt
🛠 Related issue
closed #83
어떤 변경사항이 있었나요?
✅ CheckPoint
PR이 다음 요구 사항을 충족하는지 확인하세요.
✏️ Work Description
업데이트해 주세요.
권장합니다.
Firebase Remote Config를 통해 강제/소프트 업데이트 팝업을 제어하는 기능을 추가했습니다.
동작 방식
Remote Config 파라미터
android_minimum_versionandroid_latest_versionandroid_update_strategyNONE/SOFT/FORCE팝업 종류
주요 변경 파일
domain/model/AppUpdateInfo.kt— 업데이트 도메인 모델 및UpdateStrategyenum 추가domain/repository/AppUpdateRepository.kt— Repository 인터페이스 추가core/data/datasource/RemoteConfigDataSourceImpl.kt— Firebase Remote Config fetch 구현core/datastore/AppPreferencesDataSource.kt— 소프트 업데이트 마지막 노출 시각 저장 추가feature/auth/ui/SplashViewModel.kt— 업데이트 체크 로직 추가, 팝업 닫힐 때까지 네비게이션 차단feature/auth/ui/SplashScreen.kt— 업데이트 다이얼로그 UI 추가feature/auth/ui/SplashContract.kt—UpdateDialogType,DismissSoftUpdateIntent 추가😅 Uncompleted Tasks
📢 To Reviewers
SplashViewModel에서uiState.first { it.updateDialogType == UpdateDialogType.None }으로 네비게이션을 차단합니다. 강제 업데이트의 경우 앱이 종료되기 전까지 이 suspend 함수가 계속 대기하는 구조입니다.runCatching으로null을 반환하여 팝업 미표시 후 정상 진행합니다.AppPreferencesDataStore에 마지막 표시 시각을 저장해 24시간 제한을 구현했습니다.NONE적용)📃 RCA 룰
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항
기타