-
Notifications
You must be signed in to change notification settings - Fork 1
Merge release/1.1.3 to develop #255
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
Conversation
β¦λ°±κ·ΈλΌμ΄λ μμ μ²λ¦¬
β¦-status [REFACTOR] μ΄μΈ μμ± μν κ΄λ¦¬μ© FortuneCreateStatusFlow λμ
β¦om-sheet [FEAT] μ λ°μ΄νΈ κ³΅μ§ λ°ν μνΈ
Pre-merge checks and finishing touchesβ Failed checks (1 warning)
β Passed checks (2 passed)
β¨ Finishing touches
π§ͺ Generate unit tests
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Caution
Some comments are outside the diff and canβt be posted inline due to platform limitations.
β οΈ Outside diff range comments (7)
core/network/src/main/java/com/yapp/network/di/NetworkModule.kt (2)
41-50: νμμμ 300μ΄λ κ³Όλ β μ€ν¨ κ°μ§ μ§μ°/리μμ€ μ μ μ¦κ°λ³΄νΈκ°μΌλ‘λ κ³Όν©λλ€. μΌλ° APIλ λ μ§§κ², λμ©λ μ /λ€μ΄λ‘λλ§ per-callλ‘ λ리λ κ² μμ ν©λλ€. μ΄ νΈμΆ μ νμ μν΄ callTimeoutλ κ³ λ €ν΄ μ£ΌμΈμ.
- .readTimeout(300, TimeUnit.SECONDS) - .writeTimeout(300, TimeUnit.SECONDS) - .connectTimeout(300, TimeUnit.SECONDS) + .connectTimeout(15, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .callTimeout(60, TimeUnit.SECONDS)
41-50: κΈ΄κΈ: μΈμ¦ Interceptor/Authenticator λλ½ β λ³΄νΈ API μ€ν¨(λΈλ‘컀), μ¦μ 볡ꡬ νμcore/network/src/main/java/com/yapp/network/di/NetworkModule.ktμ provideHttpClient(λΌμΈ 41β49)μμ OkHttpClientμ loggingInterceptorλ§ λ±λ‘λμ΄ μμΌλ©°, μ μ₯μ(.kt/.java) μ 체 κ²μ κ²°κ³Ό addInterceptor/.authenticator νΈμΆ λ° Authorization ν ν° μ£Όμ νμ μ΄ λ°κ²¬λμ§ μμ β λ³΄νΈ APIλ Authorization ν€λκ° μμΌλ©΄ 401/μ€ν¨ λ°μ.
μ‘°μΉ(κΆμ₯): provideHttpClientμ μΈμ¦ Interceptor λ°/λλ Authenticator μμ‘΄μ± μ£Όμ ν Builderμ μ μ©(μ: optional authInterceptor/authenticator νλΌλ―Έν° ν addInterceptor/authenticator νΈμΆ) λ° ν ν° μ£Όμ Β·401 μ¬λ°κΈ λ‘μ§ μ μ λμ νμΈ.feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingViewModel.kt (1)
134-147: λΉ μ¬μ΄λ λͺ©λ‘ μ IndexOutOfBoundsException μν.soundsκ° λΉ λ¦¬μ€νΈλ©΄ index 0 μ κ·Όμμ ν¬λμκ° λ©λλ€. μμ κ°λλ₯Ό μΆκ°νμΈμ.
λ€μμ²λΌ κΈ°λ³Έ μ ν λ‘μ§μ μμ νκ² λ°κΎΈλ κ²μ μ μν©λλ€.
- alarmUseCase.getAlarmSounds().onSuccess { sounds -> - val defaultSoundIndex = sounds.indexOfFirst { it.title == "Homecoming" }.takeIf { it >= 0 } ?: 0 - val defaultSoundUri = sounds[defaultSoundIndex] + alarmUseCase.getAlarmSounds().onSuccess { sounds -> + val defaultSound = sounds.firstOrNull { it.title == "Homecoming" } ?: sounds.firstOrNull() + if (defaultSound == null) { + Log.w("OnboardingViewModel", "No alarm sounds available; skip creating alarm") + return@onSuccess + }κ·Έλ¦¬κ³ μ¬μ©λΆ:
- soundUri = "${defaultSoundUri.uri}", + soundUri = defaultSound.uri,feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt (1)
73-79: μ ν μ΄λ²€νΈ λ‘κΉ μ΄ λλ½λμμ΅λλ€ (logEvent λ―Έμ£Όμ ).OnboardingGenderScreenμ logEvent νλΌλ―Έν°κ° κΈ°λ³Έκ° λΉ λλ€μ¬μ μ±λ³ μ ν λ‘κ·Έκ° μ¬λΌμ§λλ€. Routeμμ μ£Όμ νμΈμ.
λ€μκ³Ό κ°μ΄ μ£Όμ μ κΆμ₯ν©λλ€.
OnboardingGenderScreen( state = state, bottomSheetState = bottomSheetState, currentStep = 5, totalSteps = 6, processAction = viewModel::processAction, + logEvent = analyticsHelper::logEvent, )feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionActivity.kt (1)
102-105: API 33 μ μ© registerReceiver μ€λ²λ‘λ μ¬μ©μΌλ‘ νμ OSμμ ν¬λμ λ°μRECEIVER_EXPORTED νλκ·Έλ₯Ό λ°λ 3-μΈμ μ€λ²λ‘λλ Android 13(API 33)+ μ μ©μ λλ€. νμ¬ μ½λ κ·Έλλ‘λ©΄ API 32 μ΄νμμ NoSuchMethodErrorλ‘ ν¬λμκ° λ©λλ€. SDK κ°λλ‘ λΆκΈ°ν΄ μ£ΌμΈμ.
private fun registerAlarmInteractionActivityCloseReceiver() { val filter = IntentFilter(AlarmConstants.ACTION_ALARM_INTERACTION_ACTIVITY_CLOSE) - registerReceiver(broadcastReceiver, filter, RECEIVER_EXPORTED) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + registerReceiver(broadcastReceiver, filter, RECEIVER_EXPORTED) + } else { + @Suppress("DEPRECATION") + registerReceiver(broadcastReceiver, filter) + } }core/common/src/main/java/com/yapp/common/navigation/route/MissionRoute.kt (1)
3-3: μλͺ»λ importλ‘ μ»΄νμΌ μ€ν¨ κ°λ₯μ±MissionModeλ
com.yapp.domain.modelν¨ν€μ§λ‘ 보μ λλ€. import κ²½λ‘λ₯Ό μμ ν΄ μ£ΌμΈμ.-import com.yapp.domain.MissionMode +import com.yapp.domain.model.MissionModefeature/home/src/main/java/com/yapp/home/HomeScreen.kt (1)
295-299: LocalDensity μΊ‘μ² λλ½μΌλ‘ μ»΄νμΌ μλ¬ μ λ°.μλμμ
placeable.height.toDp()λ₯Ό νΈμΆνμ§λ§Densityμ€μ½νκ° μμ΄ μ»΄νμΌμ μ€ν¨ν©λλ€.LocalDensity.currentλ₯Ό μΊ‘μ²ν΄ μ¬μ©ν΄ μ£ΌμΈμ.var sheetHalfExpandHeight by remember { mutableStateOf(0.dp) } + val density = LocalDensity.current
π§Ή Nitpick comments (70)
feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt (4)
308-316: νλμ½λ©λ 20.dp λ°λ³΅ μ΅μνλμΌν μν ν¨λ© κ°μ΄ μ¬λ¬ κ³³μμ λ°λ³΅λ©λλ€. λ‘컬 μμλ‘ μΆμΆν΄ μ μ§λ³΄μμ±μ λμ΄λ©΄ μ’κ² μ΅λλ€.
μλμ²λΌ κ°λ¨ν μ 리ν μ μμ΅λλ€:
@@ - OrbitBottomSheetLayout(sheetState = bottomSheetState) { - Column( + OrbitBottomSheetLayout(sheetState = bottomSheetState) { + val contentHorizontalPadding = 20.dp + Column( @@ - AlarmAddEditSelectDaysSection( - modifier = Modifier.padding(horizontal = 20.dp), + AlarmAddEditSelectDaysSection( + modifier = Modifier.padding(horizontal = contentHorizontalPadding), @@ - AlarmAddEditSettingsSection( - modifier = Modifier.padding(horizontal = 20.dp), + AlarmAddEditSettingsSection( + modifier = Modifier.padding(horizontal = contentHorizontalPadding), @@ - .padding( - start = 20.dp, - end = 20.dp, + .padding( + start = contentHorizontalPadding, + end = contentHorizontalPadding, bottom = 12.dp, ),Also applies to: 325-329
286-286: λ€λΉκ²μ΄μ λ° ν¨λ© μ€λ³΅ μ¬μ§
OrbitBottomSheetLayoutμ΄ λ΄λΆμμnavigationBarsPadding()μ μ μ©νλ―λ‘, μ μ₯ λ²νΌμbottom = 12.dpμ ν©μ³μ Έ μΌλΆ κΈ°κΈ°(3βbutton λ΄λΉκ²μ΄μ λ±)μμ μ§λμΉκ² ν° νλ¨ μ¬λ°±μ΄ μκΈΈ μ μμ΅λλ€. UXμΈ‘ νμΈ ν νμ μ λ²νΌ 컨ν μ΄λμλimePadding()λ§ μΆκ°νκ±°λ, νλ¨ μ¬λ°±μ 쑰건λΆλ‘ μ€μ΄λ κ²μ κ³ λ €ν΄ μ£ΌμΈμ.Also applies to: 321-329
321-324: μ μ₯ λ²νΌ νμ±ν 쑰건 μ°λ μ μνμ
enabled = trueλ‘ λμ΄ μμ΄ λΉμ μ μ λ ₯/λ―Έλ³κ²½ μνμμλ μ μ₯ κ°λ₯ν μ μμ΅λλ€. μ ν¨μ±/λ³κ²½ μ¬λΆ νλκ·Έκ° μλ€λ©΄ μ°λμ κΆμ₯ν©λλ€(μ:enabled = state.isSaveEnabled).
288-331: μν νλ©΄/ν°νΈ νλν νκ²½μμμ μ€ν¬λ‘€ κ°λ₯μ± κ²ννμ¬ λ£¨νΈ
Columnμ μ€ν¬λ‘€μ΄ μμ΄, λ΄μ©μ΄ κΈΈμ΄μ§λ μν(μΈμ΄/ν°νΈ μ€μΌμΌ, μμ€ν μ μ€μ² μμ ν©μ°)μμ νλ¨ λ²νΌμ΄ κ°λ €μ§ μ μμ΅λλ€. μ¬μ κ° μλ€λ©΄LazyColumnμ ν νΉμ μΉμ λ³ μ€ν¬λ‘€ μ²λ¦¬ κ²ν λ₯Ό μ μν©λλ€.feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt (1)
326-331: λ κ°μ DropdownMenuκ° λμμ μ΄λ¦΄ μ μλ μν 곡κ°μ΄μ νμ Compose νΈλ¦¬μ μ‘΄μ¬νλ―λ‘ menuExpandedμ sortDropDownMenuExpandedκ° λμμ trueκ° λλ©΄ λ λ©λ΄κ° κ²Ήμ³ μ΄λ¦΄ μ μμ΅λλ€. νΈμΆ μΈ‘ λΆλ³μμΌλ‘ μνΈ λ°°νλ₯Ό 보μ₯νμ§ μλλ€λ©΄, λ¨μΌ μνλ‘ ν΅ν©νλ νΈμ΄ μμ ν©λλ€.
κ°λ¨ μ μ:
- λ¨μΌ μνλ‘ ν΅ν©: enum class Menu { None, Main, Sort }λ₯Ό μ¬μ©νκ³ expanded = (menu == Main/Sort)λ‘ μ μ΄.
- νΉμ onClickSortμμ λ°λμ menuExpanded=falseλ₯Ό 보μ₯.
νΈμΆλΆμμ λ λΆλ¦°μ λμμ trueλ‘ λ§λ€μ§ μλ λ‘μ§μ΄ μλμ§ νμΈν΄μ£ΌμΈμ. μμΌλ©΄ μ 리ν©ν°λ₯Ό κΆμ₯ν©λλ€.
Also applies to: 333-338
data/src/main/java/com/yapp/data/remote/di/ServiceModule.kt (1)
16-17: λ©μλ λ€μ΄λ° μΌκ΄μ±(nit): provideβ¦ νν κΆμ₯Hilt κ΄λ‘μ provideXxxλ‘ λ§μΆλ©΄ κ°λ μ±μ΄ μ’μμ§λλ€.
- fun providesApiService(retrofit: Retrofit): ApiService = + fun provideApiService(retrofit: Retrofit): ApiService =core/network/src/main/java/com/yapp/network/di/NetworkModule.kt (3)
54-63: kotlinx.serialization 컨λ²ν° Optβin νμ κ°λ₯μ±νλ‘μ νΈ μ€μ μ λ°λΌ asConverterFactory μ¬μ© μ ExperimentalSerializationApi Optβinμ΄ νμν μ μμ΅λλ€. μ»΄νμΌ κ²½κ³ /μλ¬κ° 보μΈλ€λ©΄ μλμ²λΌ λͺ μ Optβin ν΄ μ£ΌμΈμ.
- fun provideRetrofit( + @OptIn(kotlinx.serialization.ExperimentalSerializationApi::class) + fun provideRetrofit( okHttpClient: OkHttpClient, buildConfigFieldProvider: BuildConfigFieldProvider, json: Json, ): Retrofit =
54-63: λΉβJSON/λΉ μλ΅ λλΉ: Scalars 컨λ²ν° μ λ±λ‘ κΆμ₯μλ²κ° text/plain λλ λΉ λ°λ(204/200 without body)λ₯Ό λ°ννλ μλν¬μΈνΈκ° μλ€λ©΄ JSON 컨λ²ν°λ§μΌλ‘λ μ€ν¨ν μ μμ΅λλ€. νμ μ ScalarsConverterFactoryλ₯Ό JSONλ³΄λ€ λ¨Όμ μΆκ°ν΄ μ£ΌμΈμ.
Retrofit.Builder() - .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) + .addConverterFactory(retrofit2.converter.scalars.ScalarsConverterFactory.create()) + .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) .baseUrl(buildConfigFieldProvider.get().baseUrl) .client(okHttpClient) .build()
54-63: baseUrl νΈλ μΌλ§ μ¬λμ 보μ₯Retrofitμ baseUrlμ΄ λ°λμ '/'λ‘ λλμΌ ν©λλ€. BuildConfig κ°μ΄ 보μ₯λμ§ μμΌλ©΄ λ°νμ μμΈκ° λ©λλ€. λ°©μ΄ μ½λ μΆκ°λ₯Ό κΆμ₯ν©λλ€.
- .baseUrl(buildConfigFieldProvider.get().baseUrl) + .baseUrl( + buildConfigFieldProvider.get().baseUrl.let { + if (it.endsWith("/")) it else "$it/" + } + )feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt (2)
168-168: νλμ½λ©λ λ²νΌ λΌλ²¨ i18n μ²λ¦¬ νμ.λ€κ΅μ΄ λ° μ κ·Όμ± μΌκ΄μ±μ μν΄ stringResource μ¬μ©μ κΆμ₯ν©λλ€.
리μμ€ ν€λ νλ‘μ νΈ μν©μ λ§κ² κ΅μ²΄νμΈμ.
- buttonLabel = "λ€μ", + buttonLabel = stringResource(id = R.string.common_button_next),
190-206: UI λΌλ²¨μ μν κ°μΌλ‘ μ§μ μ μ₯/λΉκ΅νλ ν¨ν΄μ i18n/λλ©μΈ μΌκ΄μ±μ μ·¨μ½ν©λλ€.νμ λ¬Έμμ΄(λ¨μ±/μ¬μ±) λμ λλ©μΈ μ½λ(μ: "MALE"/"FEMALE" λλ enum)λ₯Ό μνμ 보κ΄νκ³ , λΌλ²¨μ stringResourceλ‘ λ§€ννμΈμ.
κ΅μ νμ μλ² μ€ν€λ§ λ³κ²½μ κ°ν ννλ‘ λ€μκ³Ό κ°μ΄ κ°μ μ μ μν©λλ€.
- listOf("λ¨μ±", "μ¬μ±").forEach { gender -> + listOf( + "MALE" to stringResource(R.string.gender_male), + "FEMALE" to stringResource(R.string.gender_female), + ).forEach { (genderCode, genderLabel) -> Box(modifier = Modifier.weight(1f)) { OrbitGenderToggle( - label = gender, - isSelected = state.selectedGender == gender, + label = genderLabel, + isSelected = state.selectedGender == genderCode, onToggle = { logEvent( AnalyticsEvent( type = "onboarding_gender_select", properties = mapOf( - AnalyticsEvent.OnboardingPropertiesKeys.GENDER to gender, + AnalyticsEvent.OnboardingPropertiesKeys.GENDER to genderCode, ), ), ) - processAction(OnboardingContract.Action.UpdateGender(gender)) + processAction(OnboardingContract.Action.UpdateGender(genderCode)) }, ) } }리μμ€ ν€(R.string.gender_male/female)λ μ€μ νλ‘μ νΈ ν€λ‘ κ΅μ²΄ λ°λλλ€.
feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionContract.kt (1)
17-18: Boolean? β BooleanμΌλ‘ λ¨μννκ³ null κ²μ΄ν μ κ±° μ μμ΄κΈ° λ‘λ©μ
initialLoadingλ‘ μ΄λ―Έ κ°λ €μ§λ―λ‘shouldShowMissionStartμ μΌμ€ μν(null/true/false)λ λΆνμν©λλ€. λΆλ³(Boolean)λ‘ μ’ν νμ μμ μ±κ³Ό λΆκΈ° λ¨μνλ₯Ό κ°μ Έκ°λ©΄ μ’κ² μ΅λλ€.μλμ²λΌ λ³κ²½ μ, νλ©΄ μͺ½μ
isFirstMission != nullλΆκΈ°λ μ κ±° κ°λ₯ν©λλ€.- val shouldShowMissionStart: Boolean? = null, + val shouldShowMissionStart: Boolean = false,νλ©΄ λ°μ(λ€λ₯Έ νμΌ)λ ν¨κ» νμν©λλ€:
- isFirstMission: Boolean?, + shouldShowMissionStart: Boolean,λ° λ²νΌ λ λλ§μμ null λΆκΈ° μ κ±°.
feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionScreen.kt (5)
115-126: νλΌλ―Έν° λͺ /νμ μ μνμ μΌμΉνλλ‘ μ 리컴ν¬μ λΈ νλΌλ―Έν°
isFirstMission: Boolean?λ μνλͺ (shouldShowMissionStart)κ³Ό μλ―Έκ° λ€λ₯΄κ³ nullableμ λλ€. λμΌ λͺ μΉΒ·λΆλ³(Boolean)μΌλ‘ μ 리νλ©΄ μ΄ν΄μ μ¬μ©μ΄ μ¬μμ§λλ€.-private fun AlarmActionContent( +private fun AlarmActionContent( isAm: Boolean, hour: Int, minute: Int, todayDate: String, snoozeEnabled: Boolean, snoozeInterval: Int, snoozeCount: Int, - isFirstMission: Boolean?, + shouldShowMissionStart: Boolean, onSnoozeClick: () -> Unit, onDismissClick: () -> Unit, )νΈμΆλΆλ ν¨κ»:
- isFirstMission = state.shouldShowMissionStart, + shouldShowMissionStart = state.shouldShowMissionStart,
170-189: λ²νΌ λ λλ§μ null κ²μ΄ν μ κ±°λ‘ UI λ¨μν
initialLoadingνλ©΄μ΄ μμΌλ―λ‘ μ¬κΈ°μμnullλΆκΈ°λ λΆνμν©λλ€. νμ λ²νΌμ λ λλ§νκ³ λΌλ²¨λ§ λΆκΈ°νμΈμ.- if (isFirstMission != null) { - OrbitButton( - label = if (isFirstMission) { + OrbitButton( + label = if (shouldShowMissionStart) { stringResource(id = R.string.alarm_off_mission_start_btn) } else { stringResource(id = R.string.alarm_off_btn) - }, - enabled = true, - modifier = Modifier - .padding( - start = 40.dp, - end = 40.dp, - bottom = 48.dp, - ) - .height(62.dp), - onClick = onDismissClick, - ) - } else { - Spacer(modifier = Modifier.height(62.dp)) - } + }, + enabled = true, + modifier = Modifier + .padding(start = 40.dp, end = 40.dp, bottom = 48.dp) + .height(62.dp), + onClick = onDismissClick, + )
150-154: contentDescription νλμ½λ© β stringResourceλ‘ i18nμ κ·Όμ± λ¬Έμμ΄μ 리μμ€λ‘ λΆλ¦¬νλ κ²μ΄ μ’μ΅λλ€. 리μμ€ μΆκ° ν κ΅μ²΄λ₯Ό κΆμ₯ν©λλ€.
μ:
- contentDescription = "Alarm Action Character", + contentDescription = stringResource(id = R.string.alarm_action_character_cd),
208-213: "μ€μ /μ€ν" νλμ½λ© μ κ±°λ€κ΅μ΄ λμμ μν΄ λ¬Έμμ΄ λ¦¬ν°λ΄ λμ stringResource μ¬μ©μ κΆμ₯ν©λλ€.
μ:
text = stringResource(if (isAm) R.string.am else R.string.pm)
299-313: ν리뷰 μΌμ΄μ€ 보κ°(λ―Έμ μ 무 2μ’ )λ―Έμ μμ/μΌλ° μ’ λ£ λ²νΌ λΌλ²¨μ λͺ¨λ κ²μ¦ν μ μλλ‘ ν리뷰λ₯Ό 2κ°λ‘ λλλ κ²μ κΆμ₯ν©λλ€.
feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionViewModel.kt (3)
30-36: μ΄κΈ° Intent μμ OK, λ€λ§ μ΄κΈ°λ‘λ© ν΄μ νμ΄λ°λ§ μΌκ΄ν μ μ
fetchShouldShowMissionStart()βinitializeAlarmState()βstartClock()μμλ ν©λ¦¬μ μ λλ€.initialLoading = falseλ λ§€μ΄κ° μλλΌ μ²« ν±μμλ§ λ΄λ¦¬λλ‘ νλ©΄ λΆνμν μν κ°±μ μ μ€μΌ μ μμ΅λλ€.
64-82: 무ν 루νλ μ·¨μ μΉνμ μΌλ‘μ·¨μ μκ·Έλ μΈμ§ λͺ νμ±μ μν΄
while (true)λμcoroutineContext.isActiveμ¬μ©μ κΆμ₯ν©λλ€.+import kotlinx.coroutines.isActive @@ - private fun startClock() = intent { - while (true) { + private fun startClock() = intent { + while (coroutineContext.isActive) { val now = LocalTime.now() ... delay(1000L) } }
84-98: Snooze λ€μ€ ν κ°λμ°μ ν μ μ¬μ΄λμ΄ννΈ μ€λ³΅ λ΄λΉκ²μ΄μ κ°λ₯μ±μ΄ μμ΅λλ€. μΌμμ λμ€μμ΄λΈ νλκ·Έλ₯Ό μνμ μΆκ°νκ±°λ, μ²λ¦¬ μ€ κ°λλ₯Ό κΆμ₯ν©λλ€.
feature/home/src/main/AndroidManifest.xml (1)
3-3: κΆν μ€λ³΅ μ μΈ μ 리 μ μACCESS_NETWORK_STATEλ λ³΄ν΅ μ± λͺ¨λ λ§€λνμ€νΈμμλ§ μ μΈν©λλ€. νΌμ² λͺ¨λ μ μΈμ λ³ν© μ μ€λ³΅μ΄ λκ³ , λμ /μ¨λ맨λ λͺ¨λμΈ κ²½μ° λΆνμ κΆν λ ΈμΆμ΄ λ μ μμ΅λλ€. μ± λ§€λνμ€νΈμλ§ μ μ§νκ³ μ¬κΈ°μλ μ κ±°νλ κ²μ κΆμ₯ν©λλ€.
μ μ© diff:
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <!-- moved to app/src/main/AndroidManifest.xml -->core/alarm/src/main/java/com/yapp/alarm/scheduler/PostFortuneTaskScheduler.kt (1)
3-5: μ€μΌμ€λ§ κ°μμ± ν₯μμ μν λ°νκ°/λ¬Έμν μ μνΈμΆ μΈ‘μμ βνμ μ±κ³΅/μ€ν΅β μ¬λΆλ νΈλνΉ IDκ° νμν μ μμ΅λλ€. Boolean(μ±κ³΅/μ€ν΅) λ°ν λλ KDocλ‘ λμ 보μ₯μ λͺ μνλ κ°μ μ μ μν©λλ€.
μμ diff:
-interface PostFortuneTaskScheduler { - fun enqueueOnceForToday() -} +/** + * μ€λ λ μ§ κΈ°μ€μΌλ‘ 1νλ§ νμν©λλ€(μ€λ³΅ λ°©μ§). + * @return trueλ©΄ μλ‘ νμλ¨, falseλ©΄ μ΄λ―Έ νμλμ΄ μ€ν΅λ¨. + */ +interface PostFortuneTaskScheduler { + fun enqueueOnceForToday(): Boolean +}core/alarm/src/main/java/com/yapp/alarm/AndroidAlarmScheduler.kt (1)
20-27: λ‘κ·Έ μ€λ²ν€λ μ κ°(μ€ννΈλ μ΄μ€/λ¦΄λ¦¬μ€ λΉλ μ°¨λ¨)Throwable μ€ννΈλ μ΄μ€λ λΉμ©μ΄ ν½λλ€. λλ²κ·Έ/λ‘κ±° κ°λλ‘ μ ννκ³ μ€ννΈλ μ΄μ€λ μ κ±°νμΈμ.
κΆμ₯ diff:
- private fun logSchedule(tag: String, alarm: Alarm, triggerMillis: Long, extra: String = "") { - Log.d("ScheduleTrace", "scheduleAlarm Called", Throwable()) - Log.d( - "AlarmSchedule", - "[$tag] id=${alarm.id}, repeatDays=${alarm.repeatDays}, " + - "time=${java.time.Instant.ofEpochMilli(triggerMillis)} $extra", - ) - } + private fun logSchedule(tag: String, alarm: Alarm, triggerMillis: Long, extra: String = "") { + if (!BuildConfig.DEBUG && !Log.isLoggable("AlarmSchedule", Log.DEBUG)) return + Log.d( + "AlarmSchedule", + "[$tag] id=${alarm.id}, repeatDays=${alarm.repeatDays}, " + + "time=${java.time.Instant.ofEpochMilli(triggerMillis)} $extra" + ) + }core/ui/src/main/java/com/yapp/ui/component/navigation/NavigationBarScrim.kt (1)
16-26: μ¬μ¬μ©μ± κ°μ : μμ/λͺ¨λνμ΄μ΄ νλΌλ―Έν°ν μ μν λ§ μ€ν¬λ¦Ό μ»¬λ¬ μ¬μ©μ΄λ zIndex μ‘°μ μ΄ νμν μ μμ΄ νλΌλ―Έν°ννλ©΄ νμ©λκ° μ¬λΌκ°λλ€.
μμ diff:
-@Composable -fun BoxScope.NavigationBarScrim() { - Box( - modifier = Modifier - .align(Alignment.BottomCenter) - .fillMaxWidth() - .windowInsetsBottomHeight(WindowInsets.navigationBars) - .background(Color.Black) - .zIndex(1f), - ) -} +@Composable +fun BoxScope.NavigationBarScrim( + modifier: Modifier = Modifier, + color: Color = Color.Black, + zIndex: Float = 1f, +) { + Box( + modifier = modifier + .align(Alignment.BottomCenter) + .fillMaxWidth() + .windowInsetsBottomHeight(WindowInsets.navigationBars) + .background(color) + .zIndex(zIndex), + ) +}feature/home/src/main/res/values/strings.xml (2)
51-53: 'μ νλ¨' λΌλ²¨μ μ¬μ© λ§₯λ½μ a11y/UX κ΄μ μμ νμΈν΄ μ£ΌμΈμ.νμ΅ λ©λͺ¨μ(selectedMissionType/Countλ λ΄λΆ μν)κ³Ό κ°μ΄ 'μ νλ¨'μ΄ κ°μ ν μ€νΈλ‘ λ ΈμΆλλ©΄ μ μ₯/νμ μνλ‘ μ€μΈλ μ μμ΅λλ€. μ€ν¬λ¦°λ¦¬λμ© contentDescriptionλ‘λ§ μ°μ΄κ±°λ, UIμμλ 체ν¬/μ ν μνκ° λͺ νν μ λ¬λλλ‘ νμΈ λΆνλ립λλ€.
128-129: 'λ€μ λ³΄μ§ μκΈ°' λμ νμ (체ν¬λ°μ€ vs λ²νΌ) λͺ νν λ° ν μ€νΈ μΌκ΄μ± νμΈν΄λΉ λ¬Έμμ΄μ΄ ν κΈ(체ν¬λ°μ€)μΈμ§, 1νμ± λ²νΌμΈμ§μ λ°λΌ μ κ·Όμ± λ μ΄λΈ/μν μλ΄κ° λ¬λΌμ§λλ€. μμ ― νμ κ³Ό μΌμΉνλλ‘ λ³΄μ‘° ν μ€νΈ(μ: μ€λͺ /μ κ·Όμ± λ μ΄λΈ)λ₯Ό μΆκ°ν μ§ κ²ν ν΄ μ£ΌμΈμ.
app/src/main/java/com/yapp/orbit/di/AppVersionModule.kt (1)
11-18: @nAmed λμ νμ μΈμ΄νν @qualifier μ¬μ© μ μλ¬Έμμ΄ Qualifierλ μΆ©λ/μ€ν 리μ€ν¬κ° μμ΅λλ€. μ μ© @qualifierλ₯Ό λμ ν΄ νμ μΈμ΄ννκ² κ΄λ¦¬ν΄ μ£ΌμΈμ.
package com.yapp.orbit.di @@ import dagger.hilt.components.SingletonComponent -import javax.inject.Named import javax.inject.Singleton +import javax.inject.Qualifier @@ -@Module -@InstallIn(SingletonComponent::class) -object AppVersionModule { +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class AppVersion + +@Module +@InstallIn(SingletonComponent::class) +object AppVersionModule { @Provides @Singleton - @Named("appVersion") - fun provideAppVersion(): String = BuildConfig.VERSION_NAME + @AppVersion + fun provideAppVersion(): String = BuildConfig.VERSION_NAME }core/designsystem/src/main/res/raw/fortune_loading.json (1)
1-1: Lottie μλ³Έ λΌμ΄μ μ€/ν¬κΈ° κ²μ¦ νμ
- λμ©λ base64 WebP μμ μΈλΌμΈμ APK/λ©λͺ¨λ¦¬ ννλ¦°νΈλ₯Ό λ립λλ€. κ°λ₯νλ©΄ 벑ν°ν/μμ λΆλ¦¬/μμΆμ κ²ν νμΈμ.
- μλ³Έ λΌμ΄μ μ€(μμ μ μ΄μ©/λ³κ²½ νμ© μ¬λΆ)μ κ·μ νκΈ°λ₯Ό νμΈν΄ μ£ΌμΈμ.
domain/src/main/java/com/yapp/domain/model/AlarmDay.kt (1)
16-23: μλ°©ν₯ λ§€ν λ‘μ§μ λ§μ΅λλ€λ§, enum μμ μμ‘΄μ± μ κ±° κΆμ₯νμ¬ κ΅¬νμ entries/ordinalμ μμ‘΄ν©λλ€. enum μμ λ³κ²½μ μ·¨μ½νλ―λ‘ λͺ μμ λ§€νμΌλ‘ λ°κΎΈλ κ²μ κΆμ₯ν©λλ€.
-fun AlarmDay.toDayOfWeek(): DayOfWeek { - return DayOfWeek.of(((this.ordinal + 6) % 7) + 1) -} +fun AlarmDay.toDayOfWeek(): DayOfWeek = when (this) { + AlarmDay.SUN -> DayOfWeek.SUNDAY + AlarmDay.MON -> DayOfWeek.MONDAY + AlarmDay.TUE -> DayOfWeek.TUESDAY + AlarmDay.WED -> DayOfWeek.WEDNESDAY + AlarmDay.THU -> DayOfWeek.THURSDAY + AlarmDay.FRI -> DayOfWeek.FRIDAY + AlarmDay.SAT -> DayOfWeek.SATURDAY +} -fun DayOfWeek.toAlarmDay(): AlarmDay { - val index = (this.value % 7) - return AlarmDay.entries[index] -} +fun DayOfWeek.toAlarmDay(): AlarmDay = when (this) { + DayOfWeek.SUNDAY -> AlarmDay.SUN + DayOfWeek.MONDAY -> AlarmDay.MON + DayOfWeek.TUESDAY -> AlarmDay.TUE + DayOfWeek.WEDNESDAY -> AlarmDay.WED + DayOfWeek.THURSDAY -> AlarmDay.THU + DayOfWeek.FRIDAY -> AlarmDay.FRI + DayOfWeek.SATURDAY -> AlarmDay.SAT +}data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSource.kt (1)
9-10: Epoch λ¨μ/νμμ‘΄ λͺ μΈ νμ
- updateNoticeLastShownDateEpochFlowμ λ¨μ(μ΄/λ°λ¦¬μ΄)μ κΈ°μ€(UTC/local midnight) λͺ μκ° νμν©λλ€. λ μ§ λΉκ΅ λ‘μ§κ³Ό λΆμΌμΉ μ μ€λμν μ μμ΅λλ€.
- markUpdateNoticeShownTodayκ° μ΄λ€ κΈ°μ€ μκ°μ μ μ₯νλμ§ KDocμ λͺ νν λ¨κ²¨ μ£ΌμΈμ.
Also applies to: 15-16
app/src/main/java/com/yapp/orbit/OrbitApplication.kt (1)
11-11: λΉ κΈ°λ³Έ μμ±μ μ κ±° κ°λ₯static analysis λκ΅¬κ° μ§μ ν κ²μ²λΌ λΉ κΈ°λ³Έ μμ±μ
()λ μ κ±°ν μ μμ΅λλ€.-class OrbitApplication() : Application(), Configuration.Provider { +class OrbitApplication : Application(), Configuration.Provider {app/src/main/AndroidManifest.xml (1)
5-5: ACCESS_NETWORK_STATE κΆν μ€λ³΅ μ μΈ
android.permission.ACCESS_NETWORK_STATEκΆνμ΄ 5λ²κ³Ό 14λ² λΌμΈμ μ€λ³΅ μ μΈλμ΄ μμ΅λλ€.14λ² λΌμΈμ μ€λ³΅λ κΆν μ μΈμ μ κ±°νμΈμ:
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>Also applies to: 14-14
core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmReceiver.kt (1)
114-119: λ‘컬 ν¨μ μ μΈ μμΉ κ°μ νμ
ringsToday()ν¨μκ° μ½λ£¨ν΄ μ€μ½ν λ΄λΆμ μ μΈλμ΄ μμ΅λλ€. μ΄ ν¨μλ μνλ₯Ό λ³κ²½νμ§ μκ³ μμ ν¨μμ΄λ―λ‘ ν΄λμ€ λ 벨μ΄λ μλ¨μ μ μΈνλ κ²μ΄ λ μ μ ν©λλ€.ν¨μλ₯Ό ν΄λμ€μ private λ©μλλ‘ μ΄λνκ±°λ companion objectμ μΆκ°νμΈμ:
- fun Alarm.ringsToday(): Boolean { - if (repeatDays == 0) return true - - val todayAlarmDay = LocalDate.now().dayOfWeek.toAlarmDay() - return (repeatDays and todayAlarmDay.bitValue) != 0 - }ν΄λμ€ λ 벨μ μΆκ°:
private fun Alarm.ringsToday(): Boolean { if (repeatDays == 0) return true val todayAlarmDay = LocalDate.now().dayOfWeek.toAlarmDay() return (repeatDays and todayAlarmDay.bitValue) != 0 }domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt (2)
20-20: μ΄λ¦ λΆμΌμΉ κ°λ₯μ±: markFortuneAsFailed vs markFortuneFaileddatastore(UserPreferences) μͺ½ ꡬνμ markFortuneFailedλ‘ λ³΄μ λλ€. λ μ΄μ΄ κ° λͺ λͺ ν΅μΌμ κΆμ₯ν©λλ€. λλ©μΈ λ©μλλ₯Ό markFortuneFailedλ‘ λ§μΆκ±°λ λ°μ΄ν° κ³μΈ΅μ AsFailedλ‘ λ§μΆ° μ£ΌμΈμ.
- suspend fun markFortuneAsFailed() + suspend fun markFortuneFailed()
9-16: νμΈ μλ£ β λλ©μΈ API λ³κ²½μ΄ μ νλ¨; KDoc λ§μ΄κ·Έλ μ΄μ κ°μ΄λ μΆκ° κΆμ₯κ²μ¦ κ²°κ³Ό: μ΄μ μ¬λ³Ό(fortuneDateFlow λ±)μ μ½λλ² μ΄μ€μμ λ°κ²¬λμ§ μμκ³ , μ μ¬λ³Ό(fortuneDateEpochFlow, hasUnseenFortuneFlow, shouldShowFortuneToolTipFlow, isFirstAlarmDismissedTodayFlow, fortuneCreateStatusFlow)μ΄ domain/data/feature λͺ¨λ μ μμμ μ¬μ©λκ³ μμ΅λλ€.
νμΈ νμΌ(μ): domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt, data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt, data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt, core/datastore/UserPreferences.kt, feature/* (Home/Mission/Fortune/Alarm).
μ‘°μΉ: κ° Flowμ μλ―Έ(ν루/epoch κΈ°μ€, reset 쑰건)μ mark* κ³μ΄ λ©μλμ μν μ μ΄λ₯Ό κ°λ¨ν KDocμΌλ‘ λ¬ΈμννμΈμ.core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (2)
44-45: todayEpoch ν μ€νΈ κ°λ₯μ±/κ²°μ μ± κ°μ μ μλ‘컬 μκ°λ/μμ κ²½κ³ μ΄μ ν μ€νΈλ₯Ό μν΄ Clock μ£Όμ (λλ provider ν¨μ μ£Όμ )μ κΆμ₯ν©λλ€.
μ: μμ±μμ Clock μ£Όμ ν
LocalDate.now(clock).toEpochDay()μ¬μ©.
108-116: FIRST_ALARM_DISMISSED_TODAY νλκ·Έ μ 리(μ΅μ )νλ‘μ°μμ λ μ§ λΉκ΅λ‘ μμ νμ§λ§, λ°μ΄ν° μ²κ²°μ μν΄ λ μ§κ° λ°λλ©΄ νλκ·Έλ₯Ό falseλ‘ μ¬μ€μ νλ μ μ§λ³΄μμ© μ 리 λ‘μ§μ κ³ λ €ν΄λ³Ό μ μμ΅λλ€.
feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionActivity.kt (1)
52-65: λ€λΉκ²μ΄μ λ° ν¨λ© + μ€ν¬λ¦Ό μ‘°ν© μ¬μ© μ μ΄μ€ ν¨λ© μ¬λΆ νμΈ μμ²NavHostμ navigationBarsPaddingμ μ£Όκ³ λ°λ₯μ μ€ν¬λ¦Όμ κΉμμΌλ λλΆλΆ OKμ λλ€. λ€λ§ λ΄λΆ νλ©΄λ€μ΄ λ³λλ‘ navigationBarsPadding/WindowInsetsλ₯Ό μ²λ¦¬νκ³ μλ€λ©΄ νλ¨ μ¬λ°±μ΄ κ³Όλ€ν΄μ§ μ μμ΄ μ€μ λ¨λ§(μ μ€μ²/3λ²νΌ λ΄λΉ λͺ¨λ)μμ νμΈ λΆνλ립λλ€. λν Boxμ ν¬κΈ° μ μ½μ΄ λͺ¨νΈν κ²½μ°λ₯Ό λ§μΌλ €λ©΄ fillMaxSizeλ₯Ό λΆμ¬νλ κ²λ κ³ λ €ν΄ μ£ΌμΈμ.
core/common/src/main/java/com/yapp/common/navigation/route/MissionRoute.kt (1)
8-11: λ¬Έμμ΄ λμ νμ μΈμ΄ν enum μ¬μ© κ³ λ €
missionMode: StringλμMissionModeμ체λ₯Ό μ¬μ©νλ©΄ μ€ν/μ€ν λΆμΌμΉλ₯Ό μ»΄νμΌ νμμ μ°¨λ¨ν μ μμ΅λλ€(νμ μ @serializable enum). λ€λΉκ²μ΄μ μΈμ½λ©/λμ½λ© μν₯ λ²μλ₯Ό κ°μν΄ νμ 리ν©ν°λ‘ κ²ν ν΄ μ£ΌμΈμ.feature/fortune/src/main/java/com/yapp/fortune/page/FortunePager.kt (1)
43-61: νμ΄μ§ μΈλ±μ€ λ§€μ§λλ² μ 리 μ μ
in 1..4,5 ->λ± νλμ½λ©λ μΈλ±μ€λ μ μ§λ³΄μ μ μ€λ₯λ₯Ό μ λ°ν©λλ€. μμ/νμ κ°μΌλ‘ μ€μμ§μ€ννκ±°λ state κΈ°λ°μΌλ‘ κ³μ°νλλ‘ μ λ¦¬ν΄ μ£ΌμΈμ.feature/fortune/src/main/java/com/yapp/fortune/FortuneNavGraph.kt (1)
23-27: λ₯λ§ν¬ URI ν¨ν΄ μμν
"orbitapp://fortune"λ¬Έμμ΄μ μμλ‘ λΆλ¦¬ν΄ μ¬μ¬μ©νλ©΄ μ€νμ/μ€λ³΅ κ΄λ¦¬κ° μμν©λλ€.feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt (1)
47-49: Clock μ£Όμ μΌλ‘ ν μ€νΈ μ©μ΄μ±/μΌκ΄μ± ν₯μ μ μ
LocalDate.now()λμClockμ DI λ°μLocalDate.now(clock)μ μ°λ©΄ μ€νλΌμΈ/νμμ‘΄/ν μ€νΈ μλ리μ€μμ μμ μ μ λλ€.// μμ class AlarmSnoozeTimerViewModel @Inject constructor( private val clock: Clock, ... ) : ViewModel(), ... { ... val todayDate = LocalDate.now(clock).toEpochDay() }feature/fortune/src/main/java/com/yapp/fortune/scheduler/WorkManagerPostFortuneTaskScheduler.kt (1)
21-31: μΌμΌ κ³ μ μν¬ μ΄λ¦ μ λ΅ OK β νκ·Έ/λͺ¨λν°λ§ μΆκ° κΆμ₯μ λν¬ λ€μ΄λ°+KEEP μ μ± μ μλμ λΆν©ν©λλ€. μ΄μ λͺ¨λν°λ§μ μν΄ νκ·Έλ₯Ό μΆκ°νκ³ , μ€ν¨/μ¬μλ μΆμ μ΄ νμνλ©΄ λ‘κ·Έ/λΆμ μ΄λ²€νΈλ₯Ό Workerμμ λ°ννμΈμ.
val req = OneTimeWorkRequestBuilder<PostFortuneWorker>() .setConstraints(constraints) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 15, TimeUnit.SECONDS) + .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 15, TimeUnit.SECONDS) + .addTag(POST_FORTUNE_TAG) .build()// νμΌ νλ¨ λ± private const val POST_FORTUNE_TAG = "post_fortune"λν,
PostFortuneWorkerκ°@HiltWorkerλ‘ μ μΈλκ³HiltWorkerFactoryκ° Applicationμ μ°κ²°λμ΄ μλμ§ νμΈν΄ μ£ΌμΈμ.domain/src/main/java/com/yapp/domain/repository/UserInfoRepository.kt (1)
11-12: μ΄λ¦ λͺ νμ±: Epoch β EpochDay κΆμ₯
updateNoticeLastShownDateEpochFlowλ λ°λ¦¬μ΄ epochλ‘ μ€ν΄λ μ μμ΅λλ€. μΌ λ¨μλΌλ©΄...EpochDayFlowμ κ°μ΄ λͺ νν νλ κ²μ κ³ λ €ν΄ μ£ΌμΈμ(λλ©μΈ μ λ° λμ μ 리 μ μ ).feature/fortune/src/main/java/com/yapp/fortune/FortuneScreen.kt (4)
220-224: LottieAnimationμ widthκ° λ¬΄μλ©λλ€ (λ΄λΆμμ fillMaxWidth κ³ μ ).νμ¬ LottieAnimation μ»΄ν¬μ λΈμ΄ λ΄λΆμ μΌλ‘
modifier.fillMaxWidth()λ₯Ό κ°μ νλ―λ‘, νΈμΆλΆμ.width(375.dp)λ ν¨κ³Όκ° μμ΅λλ€. μλλλ‘ κ°λ‘/μΈλ‘ λΉμ¨μ λ§μΆλ €λ©΄aspectRatioλ‘ μ μ΄νκ±°λ widthλ₯Ό μ κ±°νμΈμ.μλμ²λΌ μμ κΆμ₯:
- LottieAnimation( - modifier = Modifier - .width(375.dp) - .height(267.dp), - resId = core.designsystem.R.raw.fortune_loading, - ) + LottieAnimation( + modifier = Modifier + .fillMaxWidth() + .aspectRatio(375f / 267f), + resId = core.designsystem.R.raw.fortune_loading, + )μΆκ° import:
+import androidx.compose.foundation.layout.aspectRatio
174-181: μ¬λΌμ΄λ© μΈλμΌμ΄ν° count νλμ½λ©(6) β μ€μ νμ΄μ§ μμ λκΈ°ν νμ.
rememberPagerState(pageCount = { state.fortunePages.size + 2 })μ λΆμΌμΉ μ μ§ν κ°μ μ€λ₯κ° λ©λλ€. λμΌ κ³μ°μ λλpagerState.pageCountλ‘ μΉννμΈμ.- SlidingIndicator( - currentIndex = pagerState.currentPage, - count = 6, + SlidingIndicator( + currentIndex = pagerState.currentPage, + count = pagerState.pageCount, // λμ: state.fortunePages.size + 2
PagerState.pageCountκ°μ© μ¬λΆ νμΈ λΆνλ립λλ€. λΆκ°νλ©΄ λμΌ λλ€ κ³μ°μμ μ¬μ©νμΈμ.
83-91: λΉ μ΄λ²€νΈ νμ ("") λ‘κΉ λ°©μ§.
else -> ""λ‘ μ€μ λ κ²½μ°μλ λ‘κ·Έλ₯Ό μμ΅λλ€. κ³΅λ°±μΈ κ²½μ° λ‘κΉ μ μ€ν΅νμΈμ.- analyticsHelper.logEvent( - AnalyticsEvent( - type = eventType, - properties = mapOf( - AnalyticsEvent.FortunePropertiesKeys.FORTUNE_PAGE_NUMBER to pagerState.currentPage + 1, - ), - ), - ) + if (eventType.isNotBlank()) { + analyticsHelper.logEvent( + AnalyticsEvent( + type = eventType, + properties = mapOf( + AnalyticsEvent.FortunePropertiesKeys.FORTUNE_PAGE_NUMBER to pagerState.currentPage + 1, + ), + ), + ) + }
191-199: 무ν 루ν LaunchedEffect λ¨μν κ°λ₯.
while(true) + delayλμrememberInfiniteTransitionλ± μ λλ©μ΄μ APIλ‘ ν κΈνλ©΄ κ°λ μ±κ³Ό μ·¨μ μ²λ¦¬ λͺ¨λ κ°μ λ©λλ€. κΈ°λ₯μ λμΌνλ―λ‘ μ νμ¬νμ λλ€.val transition = rememberInfiniteTransition(label = "deliverToggle") val phase by transition.animateFloat( initialValue = 0f, targetValue = 1f, animationSpec = infiniteRepeatable(animation = tween(2000), repeatMode = RepeatMode.Reverse), label = "phase" ) val isDelivering = phase > 0.5fdata/src/main/java/com/yapp/data/repositoryimpl/UserInfoRepositoryImpl.kt (1)
20-21: Epoch λ¨μ λͺ μ νμ(μ΄ vs λ°λ¦¬μ΄).
updateNoticeLastShownDateEpochFlow: Flow<Long?>μ λ¨μκ° λΆλͺ νν©λλ€. μΈν°νμ΄μ€/λλ©μΈ μ λ°μμepochMillisλ±μΌλ‘ μ΄λ¦μ λͺ μνκ±°λ KDocμ λ¨μλ₯Ό κ³ μ ν΄ μ£ΌμΈμ.data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSourceImpl.kt (1)
14-15: Epoch λ¨μ λͺ μ νμ(μ΄ vs λ°λ¦¬μ΄).
updateNoticeLastShownDateEpochFlowμ λ¨μλ₯Ό μΈν°νμ΄μ€μ μΌκ΄λκ² λ¬Έμν/λͺ λͺ ν΄ μ£ΌμΈμ. μμ λ μ΄μ΄μ λμΌ μ μ μ μ© κΆμ₯.feature/fortune/src/main/java/com/yapp/fortune/FortuneViewModel.kt (2)
53-72: μ€λ³΅ Success λ°©μ§: λμΌ μν μ¬λ°©μΆ μ μ€λ³΅ fetch κ°λ₯.
collectλ λμΌSuccessμ¬λ°©μΆμλfetchAndUpdateFortuneλ₯Ό λ€μ νΈμΆν μ μμ΅λλ€.distinctUntilChanged/collectLatestλ‘ λλ°μ΄μ€νμΈμ.-import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.distinctUntilChanged @@ - private fun observeFortune() = intent { - fortuneRepository.fortuneCreateStatusFlow.collect { status -> + private fun observeFortune() = intent { + fortuneRepository.fortuneCreateStatusFlow + .distinctUntilChanged() + .collectLatest { status ->
99-103: λ€νΈμν¬ μ€ν¨ μ UX λμ νμ.
getFortuneμ€ν¨ μ λ‘λ©λ§ ν΄μ λκ³ νλ©΄μ΄ μ μ§ μνκ° λ μ μμ΅λλ€. ν μ΄λ λλ μ¬μλ/μλ¦Ό ν μ€νΈ μ€ νλλ‘ μ²λ¦¬νμΈμ.}.onFailure { error -> Log.e("FortuneViewModel", "μ΄μΈ λ°μ΄ν° μμ² μ€ν¨: ${error.message}") reduce { state.copy(isLoading = false) } + postSideEffect(FortuneContract.SideEffect.NavigateToHome) }core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt (2)
49-53: Broadcast μκ° μ ν λλΉ: Flow first()μ νμμμ κΆμ₯.λΈλ‘λμΊμ€νΈ 컨ν μ€νΈμμλ μ§μ°μ΄ κΈΈμ΄μ§λ©΄ OSκ° μ€λ¨ν μ μμ΅λλ€.
withTimeoutμΌλ‘ μμ μ₯μΉ μΆκ°λ₯Ό κΆμ₯ν©λλ€.-import kotlinx.coroutines.withContext +import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeout @@ - val (fortuneCreateStatus, hasUnseenFortune) = withContext(Dispatchers.IO) { - val status = fortuneRepository.fortuneCreateStatusFlow.first() - val unseen = fortuneRepository.hasUnseenFortuneFlow.first() - status to unseen - } + val (fortuneCreateStatus, hasUnseenFortune) = withContext(Dispatchers.IO) { + withTimeout(3_000) { + val status = fortuneRepository.fortuneCreateStatusFlow.first() + val unseen = fortuneRepository.hasUnseenFortuneFlow.first() + status to unseen + } + }
81-82: Failure/Idle λΆκΈ° μ²λ¦¬ λͺ μμ μ.μ무 λμ μμμ΄ μλλΌλ©΄ OKμ λλ€. νμ μ λ‘κΉ /νΈλ μ΄μ±λ§ μΆκ° κ²ν .
feature/fortune/src/main/java/com/yapp/fortune/worker/PostFortuneWorker.kt (1)
49-55: μ¬μλ κΈ°μ€μ ꡬλΆ(μ¬μλ κ°λ₯/λΆκ°)νμΈμ.μλ² 4xx λ± μꡬ μ€ν¨μμλ Result.retry()λ₯Ό λ°ννλ©΄ λ°±μ€ν μ¬μλκ° λΆνμνκ² κ³μλ μ μμ΅λλ€. μ μ₯μ/λλ©μΈ μλ¬ νμ μ ꡬλΆν΄ μ¬μλ λΆκ°μΈ κ²½μ° Result.failure()λ₯Ό λ°ννλ λΆκΈ°λ₯Ό μΆκ°ν΄ μ£ΌμΈμ.
- onFailure = { - fortuneRepository.markFortuneAsFailed() - // WM λ°±μ€ν κ·μΉμ λ°λΌ μ¬μλ - Result.retry() - }, + onFailure = { e -> + fortuneRepository.markFortuneAsFailed() + // μ: λλ©μΈ μμΈ/HTTP μνμ λ°λΌ μ¬μλ μ¬λΆ κ²°μ + if (e is TransientNetworkException /* or 5xx */) { + Result.retry() + } else { + Result.failure() + } + },feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt (3)
110-115: μ‘μ μμμ μ κ·Όμ± Role λΆμ¬.λ²νΌ μν μ λͺ μν΄ μ€ν¬λ¦°λ¦¬λ νμ νμ§μ λμ¬μ£ΌμΈμ.
- Box( + Box( modifier = Modifier .weight(1f) - .clickable(onClick = onDontShowAgain) + .clickable(role = androidx.compose.ui.semantics.Role.Button, onClick = onDontShowAgain) .padding(vertical = 14.dp), contentAlignment = Alignment.Center, ) { @@ - Box( + Box( modifier = Modifier .weight(1f) - .clickable(onClick = onClose) + .clickable(role = androidx.compose.ui.semantics.Role.Button, onClick = onClose) .padding(vertical = 14.dp), contentAlignment = Alignment.Center, ) {Also applies to: 124-128
64-70: μ€ν¬λ¦Ό ν΄λ¦μ Ripple μ κ±° λ° λΌλ²¨ λΆμ¬.μ 체 μ€ν¬λ¦Ό ν΄λ¦μ λ¬Όκ²° ν¨κ³Όκ° λΆνμνλ©°, μ€ν¬λ¦°λ¦¬λ λΌλ²¨μ λΆμ¬νλ©΄ λ λ«μ΅λλ€.
- Box( + Box( modifier = Modifier .fillMaxSize() - .background(Color(0xFF17191F).copy(alpha = 0.85f)) - .clickable(onClick = onClose), + .background(Color(0xFF17191F).copy(alpha = 0.85f)) + .clickable( + onClickLabel = stringResource(id = R.string.update_notice_bottom_sheet_close), + indication = null, + interactionSource = remember { MutableInteractionSource() }, + onClick = onClose, + ), contentAlignment = Alignment.BottomCenter, ) {
93-101: λ°°λ μ΄λ―Έμ§ λ‘λ© crossfade μΆκ°λ‘ μ ν νμ§ κ°μ .λ€νΈμν¬ λ‘λ©μ κΉλΉ‘μμ μ€μ λλ€.
+import coil.request.ImageRequest @@ - AsyncImage( - model = imageUrl, + AsyncImage( + model = ImageRequest.Builder(context) + .data(imageUrl) + .crossfade(true) + .build(), contentDescription = null, contentScale = ContentScale.Crop, modifier = Modifier .fillMaxWidth() .aspectRatio(1f), )feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt (1)
142-149: λ Flowλ₯Ό μΌκ΄λ μ€λ μ·μΌλ‘ μ½μ΄ 쑰건 νμ νμΈμ.μλ‘ λ€λ₯Έ μμ μ first() κ²°κ³Ό μ‘°ν©μΌλ‘ κ²½κ³ νμ΄λ°μμ μλͺ»λ νλ¨μ΄ κ°λ₯. combineμΌλ‘ μ€λ μ·μ λ§λ λ€ first()λ₯Ό κΆμ₯ν©λλ€.
- val fortuneCreateStatus = fortuneRepository.fortuneCreateStatusFlow.first() - val hasUnseenFortune = fortuneRepository.hasUnseenFortuneFlow.first() + val (fortuneCreateStatus, hasUnseenFortune) = + kotlinx.coroutines.flow.combine( + fortuneRepository.fortuneCreateStatusFlow, + fortuneRepository.hasUnseenFortuneFlow, + ) { a, b -> a to b }.first()core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt (2)
112-115: Notification IDμ Int λ³ν μμ ν.Long β Int μΊμ€ν μ overflow μνμ΄ μμ΅λλ€. νμ μμ 32λΉνΈ λ²μλ‘ λ§€ννμΈμ.
- startForeground( - notificationId.toInt(), - createNotification(alarm, shouldNavigateToMission(alarm.missionType)), - ) + val notificationIdInt = (notificationId % Int.MAX_VALUE).toInt() + startForeground( + notificationIdInt, + createNotification(alarm, shouldNavigateToMission(alarm.missionType)), + )
199-206: μλΉμ€ μλͺ μ£ΌκΈ° μ€μ½νλ‘ ν΅μΌ.λ³λ CoroutineScope λμ serviceScopeλ₯Ό μ¬μ©ν΄ μ·¨μΒ·μ’ λ£ μ μΌκ΄λκ² μ 리λλλ‘ ν©λλ€.
- CoroutineScope(Dispatchers.IO).launch { + serviceScope.launch { alarmUseCase.updateAlarmActive( id = alarmId, active = false, ) }feature/home/src/main/java/com/yapp/home/HomeViewModel.kt (1)
457-464: λ€νΈμν¬ νμ μν/μ£Όμ ν Clock κ³ λ €.
- VALIDATED λ―ΈμΆ©μ‘±(ν¬νΈ/μ΄κΈ° μ°κ²°)μμλ νμλ₯Ό λ§μ μ μμ΅λλ€. INTERNETλ§ λ§μ‘± μ μΌλ¨ νμνλλ‘ μννκ±°λ, μ΅μ μ§μ° ν μ¬νκ°λ₯Ό κ³ λ €νμΈμ.
- LocalDate.now() κΈ°λ° λ‘μ§μ΄ λ§μΌλ―λ‘ ν μ€νΈ μ©μ΄μ±κ³Ό κ²½κ³ μμ (μμ ) μ μ΄λ₯Ό μν΄ Clock μ£Όμ λ κ³ λ €ν΄ λ³Ό λ§ν©λλ€.
data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt (2)
8-8: epoch λ¨μ λͺ νν ν΄μ£ΌμΈμ.
fortuneDateEpochFlowκ° epoch day(Long, toEpochDay) κΈ°λ°μ΄λ©΄ μ΄λ¦μfortuneDateEpochDayFlowλ±μΌλ‘ λ ꡬ체ννκ±°λ KDocμΌλ‘ βepoch millisecondsκ° μλβμ λͺ μν΄ μ£ΌμΈμ. νΌλμΌλ‘ μΈν λ²κ·Έλ₯Ό μ€μΌ μ μμ΅λλ€.
12-12: Tooltip λ€μ΄λ° μΌκ΄μ± κΉ¨μ§(βToolTipβ vs βTooltipβ).
shouldShowFortuneToolTipFlowμmarkFortuneTooltipShown()μ νκΈ°κ° λ€λ¦ λλ€. μΌκ΄λκ²Tooltipλ‘ λ§μΆ° μ£ΌμΈμ.μ μ© μ(μΈν°νμ΄μ€ κΈ°μ€):
- val shouldShowFortuneToolTipFlow: Flow<Boolean> + val shouldShowFortuneTooltipFlow: Flow<Boolean>Also applies to: 21-21
feature/home/src/main/java/com/yapp/home/HomeScreen.kt (4)
416-422: API λ 벨 λΆκΈ° λμ μμ μμ(WindowInsets.safeDrawing) μ¬μ© κΆμ₯.SDK 35 λΆκΈ°λ μ μ§λ³΄μ λΉμ©μ΄ ν¬κ³ κΈ°κΈ°λ³/μ μ‘°μ¬λ³ μΈμ μ°¨μ΄λ₯Ό ν‘μνμ§ λͺ»ν©λλ€. μμ νκ²
WindowInsets.safeDrawingκΈ°λ°μΌλ‘ μ/νλ¨ μΈμ μ ν©μ°νμΈμ.- val offset = if (Build.VERSION.SDK_INT < 35) { - 0.dp - } else { - statusBarHeight + navBarHeight - } - sheetHalfExpandHeight = screenHeight - contentHeight - offset + val safeInsets = WindowInsets.safeDrawing.asPaddingValues() + val systemBarsOffset = safeInsets.calculateTopPadding() + safeInsets.calculateBottomPadding() + sheetHalfExpandHeight = screenHeight - contentHeight - systemBarsOffsetλ€μν API(30/33/35) λ° μ μ€μ² λ΄λΉκ²μ΄μ /3βbutton λ΄λΉκ²μ΄μ μμ μ λ° νμ₯ μμΉκ° μλλλ‘μΈμ§ κ²μ¦ λΆνλ립λλ€.
515-518: μμ΄μ½ μ κ·Όμ± λΌλ²¨ νμ§ν νμ.
contentDescription = "Mail" / "Setting"μ νλμ½λ©/μλ¬Έμ λλ€.stringResourceλ‘ νμ§νλ λΌλ²¨μ μ κ³΅ν΄ μ£ΌμΈμ.μ:
contentDescription = stringResource(id = R.string.cd_mail) contentDescription = stringResource(id = R.string.cd_setting)λ¬Έμμ΄ λ¦¬μμ€κ° μλ€λ©΄ μΆκ° νμ.
Also applies to: 556-560
604-607: μ₯μμ© μ΄λ―Έμ§λ contentDescriptionμ nullλ‘.
SkyImageλ μ₯μμ©μΌλ‘ 보μ λλ€. μ€ν¬λ¦°λ¦¬λ μ€λ³΅ λλ μ λ°©μ§νλ €λ©΄contentDescription = nullμ²λ¦¬νμΈμ.- contentDescription = "IMG_MAIN_SKY", + contentDescription = null,
659-663: CD μΌκ΄ν: μ₯μμ©μ null, μλ―Έ μλ 컨νΈλ‘€μ 리μμ€λ‘.
- λ§νμ /λ³/λΉ μν μΌλ¬μ€νΈ λ± μ₯μμ©μ
contentDescription = nullκΆμ₯.AddAlarmButtonλ΄ μμ΄μ½μ μ ν μ€νΈκ° λΌλ²¨ μν μ νλ―λ‘ μμ΄μ½ CDλ nullμ΄ μμ ν©λλ€(μ€λ³΅ λλ λ°©μ§).μ:
- contentDescription = "IMG_MAIN_SPEECH_BUBBLE", + contentDescription = null,- contentDescription = "Add Alarm", + contentDescription = null,Also applies to: 672-680, 748-758, 827-831
data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt (2)
22-35: μ€λ νμ λ‘μ§μ μκ° μμ€ λ¨μΌν/ν μ€νΈ μ©μ΄μ± κ°μ .
LocalDate.now()κΈ°λ°todayEpoch()λ ν μ€νΈ/νμμ‘΄ κ²½κ³(μμ μ ν)μμ μ·¨μ½ν©λλ€. 곡μ©DateProvider/Clockλ₯Ό μ£Όμ νκ±°λUserPreferencesμ λμΌ λ‘μ§μ λ¨μΌ μμ€λ‘ λ ΈμΆν΄(μ:todayEpochDay()), μ¬κΈ°μλ κ·Έ κ°μ μ¬μ©νμΈμ. μ΄λ κ² νλ©΄ λλ©μΈ/λ°μ΄ν°μ€ν μ΄ κ° λΆμΌμΉ κ°λ₯μ±μ μ κ±°ν μ μμ΅λλ€.
36-36: μ€λ³΅ μ νΈ μ κ±° μ μ.
todayEpoch()λUserPreferencesμμ μ€λ³΅ κ°λ₯μ±μ΄ μμ΅λλ€. ν κ³³μΌλ‘ λͺ¨μΌκ³ μ¬μ¬μ©ν΄ μ£ΌμΈμ.
π Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
β Files ignored due to path filters (8)
core/designsystem/src/main/res/drawable-xhdpi/ic_100_buble.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable-xhdpi/ic_fortune_delivering_speech_bubble.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable-xhdpi/ic_fortune_waiting_speech_bubble.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable-xxhdpi/ic_100_buble.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable-xxhdpi/ic_fortune_delivering_speech_bubble.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable-xxhdpi/ic_fortune_waiting_speech_bubble.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable/ic_100_buble.pngis excluded by!**/*.pngproject.dot.pngis excluded by!**/*.png
π Files selected for processing (70)
.github/workflows/android_ci.yml(0 hunks)app/build.gradle.kts(2 hunks)app/src/main/AndroidManifest.xml(3 hunks)app/src/main/java/com/yapp/orbit/OrbitApplication.kt(1 hunks)app/src/main/java/com/yapp/orbit/OrbitNavHost.kt(4 hunks)app/src/main/java/com/yapp/orbit/di/AppVersionModule.kt(1 hunks)build-logic/src/main/java/com/yapp/convention/HiltAndroid.kt(1 hunks)build-logic/src/main/java/orbit.android.feature.gradle.kts(0 hunks)core/alarm/src/main/java/com/yapp/alarm/AndroidAlarmScheduler.kt(5 hunks)core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt(2 hunks)core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmReceiver.kt(3 hunks)core/alarm/src/main/java/com/yapp/alarm/receivers/RescheduleAlarmReceiver.kt(2 hunks)core/alarm/src/main/java/com/yapp/alarm/scheduler/PostFortuneTaskScheduler.kt(1 hunks)core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt(5 hunks)core/common/src/main/java/com/yapp/common/navigation/route/MissionRoute.kt(1 hunks)core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt(3 hunks)core/designsystem/src/main/res/raw/fortune_loading.json(1 hunks)core/network/src/main/java/com/yapp/network/di/NetworkModule.kt(2 hunks)core/network/src/main/java/com/yapp/network/di/Qualifier.kt(0 hunks)core/ui/src/main/java/com/yapp/ui/component/navigation/NavigationBarScrim.kt(1 hunks)data/src/main/java/com/yapp/data/local/datasource/AlarmLocalDataSource.kt(0 hunks)data/src/main/java/com/yapp/data/local/datasource/AlarmLocalDataSourceImpl.kt(0 hunks)data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt(1 hunks)data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt(2 hunks)data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSource.kt(1 hunks)data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSourceImpl.kt(2 hunks)data/src/main/java/com/yapp/data/remote/di/ServiceModule.kt(1 hunks)data/src/main/java/com/yapp/data/repositoryimpl/AlarmRepositoryImpl.kt(0 hunks)data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt(2 hunks)data/src/main/java/com/yapp/data/repositoryimpl/UserInfoRepositoryImpl.kt(1 hunks)domain/src/main/java/com/yapp/domain/model/AlarmDay.kt(2 hunks)domain/src/main/java/com/yapp/domain/model/FortuneCreateStatus.kt(1 hunks)domain/src/main/java/com/yapp/domain/model/MissionMode.kt(1 hunks)domain/src/main/java/com/yapp/domain/repository/AlarmRepository.kt(0 hunks)domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt(1 hunks)domain/src/main/java/com/yapp/domain/repository/UserInfoRepository.kt(1 hunks)feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionActivity.kt(2 hunks)feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionContract.kt(1 hunks)feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionScreen.kt(1 hunks)feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionViewModel.kt(3 hunks)feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt(1 hunks)feature/fortune/build.gradle.kts(1 hunks)feature/fortune/src/main/java/com/yapp/fortune/FortuneNavGraph.kt(2 hunks)feature/fortune/src/main/java/com/yapp/fortune/FortuneScreen.kt(3 hunks)feature/fortune/src/main/java/com/yapp/fortune/FortuneViewModel.kt(4 hunks)feature/fortune/src/main/java/com/yapp/fortune/di/SchedulerModule.kt(1 hunks)feature/fortune/src/main/java/com/yapp/fortune/page/FortunePager.kt(1 hunks)feature/fortune/src/main/java/com/yapp/fortune/scheduler/WorkManagerPostFortuneTaskScheduler.kt(1 hunks)feature/fortune/src/main/java/com/yapp/fortune/worker/PostFortuneWorker.kt(1 hunks)feature/home/build.gradle.kts(1 hunks)feature/home/src/main/AndroidManifest.xml(1 hunks)feature/home/src/main/java/com/yapp/home/HomeContract.kt(2 hunks)feature/home/src/main/java/com/yapp/home/HomeScreen.kt(17 hunks)feature/home/src/main/java/com/yapp/home/HomeViewModel.kt(9 hunks)feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt(2 hunks)feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt(10 hunks)feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt(3 hunks)feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt(1 hunks)feature/home/src/main/res/values/strings.xml(2 hunks)feature/mission/src/main/java/com/yapp/mission/MissionContract.kt(0 hunks)feature/mission/src/main/java/com/yapp/mission/MissionNavGraph.kt(2 hunks)feature/mission/src/main/java/com/yapp/mission/MissionScreen.kt(0 hunks)feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt(2 hunks)feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingAccessScreen.kt(0 hunks)feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingBirthdayScreen.kt(0 hunks)feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingCompleteScreen2.kt(0 hunks)feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt(3 hunks)feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingNavGraph.kt(1 hunks)feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingViewModel.kt(1 hunks)gradle/libs.versions.toml(4 hunks)
π€ Files with no reviewable changes (12)
- feature/mission/src/main/java/com/yapp/mission/MissionContract.kt
- domain/src/main/java/com/yapp/domain/repository/AlarmRepository.kt
- feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingBirthdayScreen.kt
- .github/workflows/android_ci.yml
- data/src/main/java/com/yapp/data/local/datasource/AlarmLocalDataSource.kt
- build-logic/src/main/java/orbit.android.feature.gradle.kts
- data/src/main/java/com/yapp/data/repositoryimpl/AlarmRepositoryImpl.kt
- feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingCompleteScreen2.kt
- feature/mission/src/main/java/com/yapp/mission/MissionScreen.kt
- feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingAccessScreen.kt
- data/src/main/java/com/yapp/data/local/datasource/AlarmLocalDataSourceImpl.kt
- core/network/src/main/java/com/yapp/network/di/Qualifier.kt
π§° Additional context used
π§ Learnings (4)
π Learning: 2025-07-27T15:20:35.256Z
Learnt from: DongChyeon
PR: YAPP-Github/Orbit-Android#238
File: feature/mission/src/main/java/com/yapp/mission/MissionScreen.kt:118-120
Timestamp: 2025-07-27T15:20:35.256Z
Learning: MissionRouteμ MissionScreenμ΄ κ°μ νμΌ(feature/mission/src/main/java/com/yapp/mission/MissionScreen.kt)μ μμ λ, MissionRouteμμ BackHandlerλ₯Ό μ¬μ©νλ©΄ νμΌ λ 벨μ import λ¬Έμ μ μ§λμ΄μΌ ν¨.
Applied to files:
feature/mission/src/main/java/com/yapp/mission/MissionNavGraph.ktcore/common/src/main/java/com/yapp/common/navigation/route/MissionRoute.kt
π Learning: 2025-09-14T15:32:32.628Z
Learnt from: DongChyeon
PR: YAPP-Github/Orbit-Android#252
File: feature/fortune/src/main/java/com/yapp/fortune/worker/PostFortuneWorker.kt:24-56
Timestamp: 2025-09-14T15:32:32.628Z
Learning: μ΄μΈ μμ² κ°μλ μ΅μ 1λΆ κ°κ²©μ΄ 보μ₯λμ΄ μμ΄μ PostFortuneWorkerμμ λμμ±/μμμ± λ¬Έμ λ₯Ό κ³ λ €νμ§ μμλ λ¨
Applied to files:
feature/fortune/src/main/java/com/yapp/fortune/worker/PostFortuneWorker.kt
π Learning: 2025-07-23T10:29:14.146Z
Learnt from: DongChyeon
PR: YAPP-Github/Orbit-Android#234
File: feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt:73-76
Timestamp: 2025-07-23T10:29:14.146Z
Learning: AlarmMissionBottomSheetμμ missionType/missionCount νλΌλ―Έν°λ νμ¬ μ μ₯λ κ°μ UIμ νμνκΈ° μν΄ μ¬μ©λκ³ , selectedMissionType/selectedMissionCountλ μ¬μ©μκ° λ³κ²½ μ€μΈ λ΄λΆ μμ
μνλ₯Ό κ΄λ¦¬νκΈ° μν΄ μ¬μ©λλ€. onDoneμ΄λ onSave μ½λ°±μ ν΅ν΄ λͺ
μμ μΌλ‘ μ μ₯ν λλ§ λ³κ²½μ¬νμ΄ λ°μλλ UX ν¨ν΄μ΄λ€.
Applied to files:
feature/home/src/main/res/values/strings.xmlfeature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt
π Learning: 2025-09-15T07:43:50.275Z
Learnt from: DongChyeon
PR: YAPP-Github/Orbit-Android#254
File: data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt:22-34
Timestamp: 2025-09-15T07:43:50.275Z
Learning: FortuneCreateStatusFlowμμ todayEpoch()λ₯Ό combine λ΄λΆμμ μ§μ νΈμΆνλ κ²μ΄ μΆ©λΆν μ΄μ : μ΄μΈ μμ±ν λλ§λ€ fortuneDateEpochFlowκ° λ³κ²½λμ΄ combineμ΄ μ¬νκ°λλ―λ‘, κ·Έ μκ°μ todayEpoch() κ³μ°μΌλ‘ μΆ©λΆν¨. μ΄μΈ μμ² κ°κ²© μ μ½μΌλ‘ μΈν΄ μμ λ‘€μ€λ² λ¬Έμ λ μ€μ©μ μΌλ‘ λ°μνμ§ μμ.
Applied to files:
feature/home/src/main/java/com/yapp/home/HomeViewModel.kt
𧬠Code graph analysis (10)
feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionActivity.kt (2)
feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionNavGraph.kt (1)
alarmInteractionNavGraph(33-69)core/ui/src/main/java/com/yapp/ui/component/navigation/NavigationBarScrim.kt (1)
NavigationBarScrim(16-26)
feature/fortune/src/main/java/com/yapp/fortune/page/FortunePager.kt (1)
feature/fortune/src/main/java/com/yapp/fortune/page/FortuneCompletePage.kt (1)
FortuneCompletePage(28-104)
feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt (1)
core/designsystem/src/main/java/com/yapp/designsystem/theme/Theme.kt (1)
OrbitTheme(12-28)
feature/fortune/src/main/java/com/yapp/fortune/FortuneScreen.kt (2)
core/ui/src/main/java/com/yapp/ui/component/lottie/LottieAnimation.kt (1)
LottieAnimation(22-85)core/designsystem/src/main/java/com/yapp/designsystem/theme/Theme.kt (1)
OrbitTheme(12-28)
feature/home/src/main/java/com/yapp/home/HomeScreen.kt (2)
feature/home/src/main/java/com/yapp/home/HomeViewModel.kt (1)
processAction(55-87)feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt (1)
UpdateNoticeBottomSheet(51-139)
feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt (1)
core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetLayout.kt (1)
OrbitBottomSheetLayout(31-59)
feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt (2)
feature/home/src/main/java/com/yapp/home/component/AlarmListDropDownMenu.kt (1)
AlarmListDropDownMenu(43-72)feature/home/src/main/java/com/yapp/home/component/AlarmSortDropDownMenu.kt (1)
AlarmSortDropDownMenu(36-67)
feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt (4)
core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetLayout.kt (1)
OrbitBottomSheetLayout(31-59)feature/onboarding/src/main/java/com/yapp/onboarding/OnBoardingScreen.kt (1)
OnboardingScreen(14-54)feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingViewModel.kt (1)
processAction(49-67)core/ui/src/main/java/com/yapp/ui/toggle/OrbitGenderToggle.kt (1)
OrbitGenderToggle(30-98)
core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (1)
data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt (1)
todayEpoch(36-36)
data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt (1)
core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (1)
todayEpoch(44-44)
πͺ detekt (1.23.8)
app/src/main/java/com/yapp/orbit/OrbitApplication.kt
[warning] 11-11: An empty default constructor can be removed.
(detekt.empty-blocks.EmptyDefaultConstructor)
core/alarm/src/main/java/com/yapp/alarm/receivers/RescheduleAlarmReceiver.kt
Outdated
Show resolved
Hide resolved
feature/fortune/src/main/java/com/yapp/fortune/worker/PostFortuneWorker.kt
Show resolved
Hide resolved
feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt
Show resolved
Hide resolved
feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt
Show resolved
Hide resolved
feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingViewModel.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
β»οΈ Duplicate comments (3)
feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt (2)
102-114: snapshotFlow μ€λ³΅ μ΄λ²€νΈ λ°©μ§ κ°μ νμνμ¬ κ΅¬νμμλ
distinctUntilChanged()λ₯Ό μ μ©νμ§λ§,LaunchedEffectμ keyκ° μ¬μ νUnitμ λλ€.sheetStateλ₯Ό keyλ‘ μ¬μ©νλ κ²μ΄ λ μμ ν©λλ€.λ€μκ³Ό κ°μ΄ μμ νμΈμ:
- LaunchedEffect(Unit) { + LaunchedEffect(sheetState) { snapshotFlow { sheetState.currentValue } .distinctUntilChanged() .collectLatest { value ->
98-98: Hidden μν μ μ΄ λ°©μ§ νμ
confirmValueChangeμ κ±°λ‘ μ¬μ©μκ° λλκ·Ένμ¬ Hidden μνλ‘ μ μ΄ν μ μμ΅λλ€. μνΈκ° νμ νμλμ΄μΌ νλ€λ©΄ Hidden μνλ₯Ό λͺ μμ μΌλ‘ μ°¨λ¨ν΄μΌ ν©λλ€.λ€μ μ€ νλλ₯Ό μ μ©νμΈμ:
μ΅μ 1: Hidden μν 건λλ°κΈ° (κΆμ₯)
- val sheetState = rememberStandardBottomSheetState() + val sheetState = rememberStandardBottomSheetState( + skipHiddenState = true + )μ΅μ 2: confirmValueChangeλ‘ λͺ μμ μ°¨λ¨
- val sheetState = rememberStandardBottomSheetState() + val sheetState = rememberStandardBottomSheetState( + confirmValueChange = { it != SheetValue.Hidden } + )core/alarm/src/main/java/com/yapp/alarm/receivers/RescheduleAlarmReceiver.kt (1)
30-31: goAsync μ μ© κ΅Ώ + μ± μ λ°μ΄νΈ ν μ¬μ€μΌμ€λ ν¨κ» μ²λ¦¬ μ μλΆν νλ§ μ²λ¦¬νλ©΄ μ± μ λ°μ΄νΈ μ§ν μλ μ¬μ€μ μ΄ λλ½λ μ μμ΅λλ€. ACTION_MY_PACKAGE_REPLACEDλ ν¨κ» μμ ν΄ λμΌ λ‘μ§μ νμ°λ κ±Έ κΆμ₯ν©λλ€. (μ΄μ 리뷰 μ½λ©νΈμ λμΌ μ μ)
- if (intent.action == Intent.ACTION_BOOT_COMPLETED) { + if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED) { val pending = goAsync() rescheduleAlarm(pending) }
π§Ή Nitpick comments (1)
core/alarm/src/main/java/com/yapp/alarm/receivers/RescheduleAlarmReceiver.kt (1)
35-44: μμΈ λ‘κΉ μΆκ°λ‘ λ¬Έμ μ§λ¨μ± κ°μ μ μνμ¬ μμΈκ° μΌμΌμ Έ μμΈ νμ μ΄ μ΄λ ΅μ΅λλ€. catchμμ λ‘κΉ ν finish 보μ₯ μ μ§ κΆμ₯.
- CoroutineScope(Dispatchers.IO + SupervisorJob()).launch { - try { - val alarms = alarmUseCase.getAllAlarms().first() - alarms - .filter { it.isAlarmActive } - .forEach { alarm -> androidAlarmScheduler.scheduleAlarm(alarm) } - } finally { - pendingResult.finish() - } - } + CoroutineScope(Dispatchers.IO + SupervisorJob()).launch { + try { + val alarms = alarmUseCase.getAllAlarms().first() + alarms + .filter { it.isAlarmActive } + .forEach { alarm -> androidAlarmScheduler.scheduleAlarm(alarm) } + } catch (t: Throwable) { + android.util.Log.e("RescheduleAlarmReceiver", "Failed to reschedule alarms", t) + } finally { + pendingResult.finish() + } + }
π Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
π Files selected for processing (2)
core/alarm/src/main/java/com/yapp/alarm/receivers/RescheduleAlarmReceiver.kt(2 hunks)feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt(4 hunks)
π§° Additional context used
𧬠Code graph analysis (1)
feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt (2)
feature/home/src/main/java/com/yapp/home/component/AlarmListDropDownMenu.kt (1)
AlarmListDropDownMenu(43-72)feature/home/src/main/java/com/yapp/home/component/AlarmSortDropDownMenu.kt (1)
AlarmSortDropDownMenu(36-67)
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build
- GitHub Check: Continuous Deployment
π Additional comments (4)
feature/home/src/main/java/com/yapp/home/component/bottomsheet/AlarmListBottomSheet.kt (2)
329-341: λλ‘λ€μ΄ λ©λ΄ μ‘°κ±΄λΆ λ λλ§ μ κ±° νμΈ
AlarmListDropDownMenuμAlarmSortDropDownMenuκ° μ΄μ νμ λ λλ§λλ©°,expandedμνλ§ μ λ¬λ©λλ€. μ΄λ μ±λ₯μ λ¬Έμ κ° μμ§λ§, λ λ©λ΄κ° λμμ μ΄λ¦΄ κ°λ₯μ±μ΄ μμ΅λλ€.λ λ©λ΄κ° λμμ μ΄λ¦¬μ§ μλλ‘ μν κ΄λ¦¬κ° μ μ ν λκ³ μλμ§ νμΈμ΄ νμν©λλ€. νΉν
menuExpandedμsortDropDownMenuExpandedκ° μνΈ λ°°νμ μΌλ‘ κ΄λ¦¬λλμ§ κ²μ¦νμΈμ.
93-93: onExpanded μ½λ°± μ¬μ© νμΈ β ν΄κ²°λ¨feature/home/src/main/java/com/yapp/home/HomeScreen.kt (lines 394β396)μμ onExpandedκ° νΈμΆλμ΄ processAction(HomeContract.Action.HideToolTip)λ₯Ό μ€νν©λλ€. μμ λΆνμ.
core/alarm/src/main/java/com/yapp/alarm/receivers/RescheduleAlarmReceiver.kt (2)
11-12: νμ import μΆκ° μ μ SupervisorJob, flow.first λμ λͺ¨λ μν©μ λ§κ³ π
29-33: Manifest μ€μ νμΈ: RECEIVE_BOOT_COMPLETEDΒ·intent-filterΒ·exported νμΈλ¨app/src/main/AndroidManifest.xmlμ RECEIVE_BOOT_COMPLETED κΆν(λΌμΈ 11)κ³Ό RescheduleAlarmReceiver 리μλ² μ μΈ(λΌμΈ 72β76) β intent-filter(android.intent.action.BOOT_COMPLETED) λ° android:exported="true"(λΌμΈ 73)κ° μ‘΄μ¬νλ―λ‘ BOOT_COMPLETED μμ μ€μ μ μΆ©μ‘±λ©λλ€.
Related issue π
closed #<issue_number>
μ΄λ€ λ³κ²½μ¬νμ΄ μμλμ?
CheckPoint β
PRμ΄ λ€μ μꡬ μ¬νμ μΆ©μ‘±νλμ§ νμΈνμΈμ.
Work Description βοΈ
Uncompleted Tasks π
To Reviewers π’
Summary by CodeRabbit
New Features
UI/UX
Improvements
Permissions
Chores