Conversation
WalkthroughThis update introduces a comprehensive reminder and notification feature set, including new database schema changes, domain models, UI components, and notification scheduling using WorkManager. Notification permissions are now managed with platform-specific implementations and user prompts. The codebase also underwent significant refactoring, including package restructuring, removal of the Clock abstraction, and updates to dependency injection, theming, and string localization. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI
participant ViewModel
participant ReminderScheduler
participant NotificationPermissionManager
participant WorkManager
participant NotificationUtils
User->>UI: Set Reminder on Reply
UI->>ViewModel: OnAddOrEditReply Intent
ViewModel->>ViewModel: Validate Reminder Date/Time
alt Permission Needed
ViewModel->>NotificationPermissionManager: ensureNotificationPermission()
NotificationPermissionManager-->>ViewModel: Permission Result
alt Permission Granted
ViewModel->>ReminderScheduler: scheduleReminder(reminderAt, params)
ReminderScheduler->>WorkManager: Enqueue Work
else Permission Denied
ViewModel->>UI: Show NotificationPermissionDialog
end
else No Permission Needed
ViewModel->>ReminderScheduler: scheduleReminder(reminderAt, params)
ReminderScheduler->>WorkManager: Enqueue Work
end
WorkManager->>NotificationUtils: showReminderNotification()
NotificationUtils->>User: Show Notification
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (26)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/StatusBar.kt (2)
10-15: Replace manual ARGB math with the built-inColor.toArgb()Compose already provides
Color.toArgb(), avoiding the custom multiplier constant and reducing risk of rounding errors.- window.statusBarColor = android.graphics.Color.argb( - (color.alpha * COLOR_MULTIPLIER).toInt(), - (color.red * COLOR_MULTIPLIER).toInt(), - (color.green * COLOR_MULTIPLIER).toInt(), - (color.blue * COLOR_MULTIPLIER).toInt() - ) + window.statusBarColor = color.toArgb()If you apply this, you can drop
COLOR_MULTIPLIER.
17-18: Null-safety forWindowInsetsController
WindowCompat.getInsetsControllercan returnnullon some OEM skins. Use a safe call to avoid a rare NPE.- WindowCompat - .getInsetsController(window, window.decorView).isAppearanceLightStatusBars = useDarkIcons + WindowCompat.getInsetsController(window, window.decorView) + ?.let { it.isAppearanceLightStatusBars = useDarkIcons }composeApp/build.gradle.kts (1)
218-220: Restrict WorkManager to Android source-setAdding
implementation(libs.androidx.work.runtime.ktx)in the top-leveldependencies {}block makes the artifact visible to every target produced by the multiplatform build.
Move it to the existingandroidMain.dependencies {}block (or useandroidImplementation) to avoid shipping unused Android-only code to other platforms and to prevent future linkage issues.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyOutlinedButton.kt (1)
42-43: Nit: modifier split adds no functional valueThe line-break re-formatting is harmless, but purely stylistic.
Feel free to keep it if it matches your formatter rules.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/AppConstants.kt (1)
3-21: Well-structured constants organization with room for improvement.The constants are logically grouped and properly typed. However, consider these improvements:
- Email exposure: Hardcoding a personal email address in constants may not be ideal for production code
- Magic numbers: Some constants like
REMINDER_DEFAULT_HOUR = 8could benefit from documentation explaining the business logic- Consider grouping: Related constants could be nested in inner objects for better organization
object AppConstants { const val EMPTY = "" const val DB_NAME = "replyradar.db" const val PACKAGE_NAME = "com.rafaelfelipeac.replyradar" - const val EMAIL = "rafaelfelipeac@gmail.com" + const val EMAIL = "rafaelfelipeac@gmail.com" // TODO: Move to build config for production const val PENDING_REPLY_ID_KEY = "PENDING_REPLY_ID" + object Defaults { + const val INITIAL_DATE = 0L + const val INITIAL_ID = 0L + const val INVALID_ID = -1L + const val REMINDER_DEFAULT_HOUR = 8 // 8 AM default reminder time + const val REMINDER_DEFAULT_MINUTE = 0 + const val REMINDER_TOMORROW_OFFSET = 1 + } - const val INITIAL_DATE = 0L - const val INITIAL_ID = 0L - const val INVALID_ID = -1L - const val REMINDER_DEFAULT_HOUR = 8 - const val REMINDER_DEFAULT_MINUTE = 0 - const val REMINDER_TOMORROW_OFFSET = 1 + object ReplyStates { + const val ON_THE_RADAR_INDEX = 0 + const val RESOLVED_INDEX = 1 + const val ARCHIVED_INDEX = 2 + } - const val ON_THE_RADAR_INDEX = 0 - const val RESOLVED_INDEX = 1 - const val ARCHIVED_INDEX = 2 }composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/ReplyRadarApplication.kt (1)
27-40: Solid notification channel implementation with minor considerations.The implementation correctly handles API level checks and uses string resources for internationalization. However, consider these aspects:
- High importance:
IMPORTANCE_HIGHshould be justified - this bypasses DND and makes sound/vibration- Error handling: Consider handling potential SecurityException or other system-level failures
private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val id = getString(notification_channel_id) - val name = getString(notification_channel_name) - val descriptionText = getString(notification_channel_description) - val importance = IMPORTANCE_HIGH - val channel = NotificationChannel(id, name, importance).apply { - description = descriptionText - } - val notificationManager = getSystemService(NotificationManager::class.java) - - notificationManager.createNotificationChannel(channel) + try { + val id = getString(notification_channel_id) + val name = getString(notification_channel_name) + val descriptionText = getString(notification_channel_description) + val importance = IMPORTANCE_HIGH // Consider IMPORTANCE_DEFAULT if high priority isn't required + val channel = NotificationChannel(id, name, importance).apply { + description = descriptionText + } + val notificationManager = getSystemService(NotificationManager::class.java) + notificationManager.createNotificationChannel(channel) + } catch (e: Exception) { + // Log error but don't crash the app + } } }composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/FloatingActionButton.kt (1)
13-26: Consider renaming to avoid naming conflict with Material3 component.The function name
FloatingActionButtonconflicts with the imported Material3 component, which could lead to confusion and potential compilation issues.Consider renaming the function to be more specific:
-fun FloatingActionButton(onIntent: (ReplyListScreenIntent) -> Unit, colorScheme: ColorScheme) { +fun ReplyListFloatingActionButton(onIntent: (ReplyListScreenIntent) -> Unit, colorScheme: ColorScheme) {Otherwise, the component implementation is clean with proper Material3 usage and accessibility support.
composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/core/util/FakeReminderScheduler.kt (1)
6-21: Add utility methods for test assertions.The test fake correctly implements the interface but lacks utility methods for verifying interactions. Consider adding methods to access the recorded data for test assertions.
class FakeReminderScheduler : ReminderScheduler { private val scheduledReminders = mutableListOf<Pair<Long, NotificationReminderParams>>() private val cancelledReminders = mutableListOf<Long>() override fun scheduleReminder( reminderAtMillis: Long, notificationReminderParams: NotificationReminderParams ) { scheduledReminders.add(reminderAtMillis to notificationReminderParams) } override fun cancelReminder(replyId: Long) { cancelledReminders.add(replyId) } + + fun getScheduledReminders(): List<Pair<Long, NotificationReminderParams>> = scheduledReminders.toList() + fun getCancelledReminders(): List<Long> = cancelledReminders.toList() + fun wasReminderScheduled(reminderAtMillis: Long): Boolean = + scheduledReminders.any { it.first == reminderAtMillis } + fun wasReminderCancelled(replyId: Long): Boolean = cancelledReminders.contains(replyId) + fun clear() { + scheduledReminders.clear() + cancelledReminders.clear() + } }composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/DatetimeExt.kt (1)
9-11: Consider timezone consistency with the companion function.The
toEpochMillis()function implicitly uses the system timezone, whiletoLocalDate()allows specifying a timezone parameter. This could lead to inconsistencies if both functions are used together.Consider making the timezone handling consistent:
-fun LocalDate.toEpochMillis(): Long { - return this.atStartOfDayIn(TimeZone.currentSystemDefault()).toEpochMilliseconds() -} +fun LocalDate.toEpochMillis(timeZone: TimeZone = TimeZone.currentSystemDefault()): Long { + return this.atStartOfDayIn(timeZone).toEpochMilliseconds() +}composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesScreen.kt (1)
24-39: Simplify the nested layout structure.The nested Box and Column layout appears unnecessarily complex. The outer Box and inner Box serve similar purposes (centering content), which can be simplified.
Consider this simplified structure:
- Box( - modifier = Modifier - .fillMaxSize(), - contentAlignment = Alignment.Center - ) { - Column( - modifier = Modifier - .fillMaxSize() - .background(colorScheme.background), - verticalArrangement = Arrangement.Center - ) { - Box( - modifier = Modifier - .fillMaxSize(), - contentAlignment = Alignment.Center - ) { + Column( + modifier = Modifier + .fillMaxSize() + .background(colorScheme.background) + ) {composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.android.kt (1)
17-18: Consider more intuitive default time values.The default time of 12:12 seems arbitrary. Consider using more intuitive defaults like 12:00 (noon) or the current time.
-private const val HOUR_DEFAULT_INITIAL_HOUR = 12 -private const val HOUR_DEFAULT_INITIAL_MINUTE = 12 +private const val HOUR_DEFAULT_INITIAL_HOUR = 12 +private const val HOUR_DEFAULT_INITIAL_MINUTE = 0composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderSchedulerImpl.kt (5)
14-18: LGTM! Consider the edge case for delay exactly equal to zero.The class structure and constant definition look good. The
INVALID_DELAY = 0constant provides clear semantic meaning for invalid delays.Consider whether a delay of exactly 0 milliseconds should be treated as invalid. If immediate scheduling is a valid use case, you might want to use a negative value or rename the constant to better reflect its purpose.
35-54: LGTM! Well-structured WorkRequest creation.The method properly configures the WorkRequest with delay, input data, and tagging. The use of string resources for keys ensures consistency across the codebase.
Consider extracting the input data creation to improve readability:
private fun enqueueReminder( delay: Long, notificationReminderParams: NotificationReminderParams ) { with(notificationReminderParams) { + val inputData = workDataOf( + context.getString(notification_reminder_reply_id) to replyId, + context.getString(notification_reminder_title) to notificationTitle, + context.getString(notification_reminder_content) to notificationContent + ) + val workRequest = OneTimeWorkRequestBuilder<ReminderWorker>() .setInitialDelay(delay, MILLISECONDS) - .setInputData( - workDataOf( - context.getString(notification_reminder_reply_id) to replyId, - context.getString(notification_reminder_title) to notificationTitle, - context.getString(notification_reminder_content) to notificationContent - ) - ) + .setInputData(inputData) .addTag(getTag(replyId)) .build()
24-26: Consider race condition with system time changes.The delay calculation using
System.currentTimeMillis()could be affected by system time changes. Consider usingSystemClock.elapsedRealtime()for more reliable scheduling.-private fun getDelay(reminderAtMillis: Long) = reminderAtMillis - System.currentTimeMillis() +private fun getDelay(reminderAtMillis: Long): Long { + // Use elapsed realtime to avoid issues with system time changes + val currentTimeMillis = System.currentTimeMillis() + return reminderAtMillis - currentTimeMillis +}
44-46: Optimize string resource access.Accessing string resources multiple times in a loop context could impact performance. Consider caching these keys as constants.
+private companion object { + private const val KEY_REPLY_ID = "notification_reminder_reply_id" + private const val KEY_TITLE = "notification_reminder_title" + private const val KEY_CONTENT = "notification_reminder_content" +} -context.getString(notification_reminder_reply_id) to replyId, -context.getString(notification_reminder_title) to notificationTitle, -context.getString(notification_reminder_content) to notificationContent +KEY_REPLY_ID to replyId, +KEY_TITLE to notificationTitle, +KEY_CONTENT to notificationContent
58-58: Potential performance concern with string resource access.The
getTagmethod accesses string resources which could impact performance when called frequently during cancellation operations.Consider caching the tag template:
+private companion object { + private const val TAG_TEMPLATE = "reminder_%d" +} -private fun getTag(replyId: Long) = context.getString(notification_reminder_tag, replyId) +private fun getTag(replyId: Long) = String.format(TAG_TEMPLATE, replyId)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/NotificationUtils.kt (3)
23-46: LGTM! Well-implemented notification display with proper permission checking.The notification is correctly configured with appropriate settings for a reminder notification. The permission check prevents crashes on Android 13+.
Consider the potential for hash collisions when using
replyId.hashCode()as the notification ID. While unlikely for typical use cases, you might want to use thereplyId.toInt()directly if the ID range is suitable, or implement a more robust ID generation strategy:-NotificationManagerCompat.from(context).notify(replyId.hashCode(), notification) +NotificationManagerCompat.from(context).notify(replyId.toInt(), notification)
48-63: LGTM! Proper PendingIntent creation with correct flags.The PendingIntent is correctly configured with:
- Appropriate activity flags for launching from notification
- Modern
FLAG_IMMUTABLEflag for securityFLAG_UPDATE_CURRENTfor proper intent updatesSame hash collision consideration applies here for the request code. Consider using
replyId.toInt()if the ID range permits, for consistency with the notification ID.
45-45: Consider potential hash collision with replyId.hashCode().Using
replyId.hashCode()for both notification ID and PendingIntent request code could lead to collisions, especially with negative hash values. Consider using the replyId directly if it fits within int range, or implement a more robust ID generation strategy.-NotificationManagerCompat.from(context).notify(replyId.hashCode(), notification) +NotificationManagerCompat.from(context).notify(replyId.toInt(), notification) // And in getPendingIntent: -replyId.hashCode(), +replyId.toInt(),Or implement collision-resistant ID generation:
+private fun generateNotificationId(replyId: Long): Int { + return (replyId and 0xFFFFFFFF).toInt() +}Also applies to: 59-59
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyTimestampInfo.kt (1)
34-63: LGTM! Logical timestamp priority with proper formatting.The timestamp display logic correctly prioritizes the most relevant timestamp:
- Archived timestamp (highest priority)
- Resolved timestamp
- Updated timestamp (only if different from created)
- Created timestamp (fallback)
The use of
INITIAL_DATEfor checking timestamp validity and localized string formatting is appropriate.Consider the edge case where
updatedAtequalscreatedAtbut both are set to meaningful values (notINITIAL_DATE). The current logic would show "Created" instead of "Updated", which might be more accurate as "Created" in this scenario.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyReminder.kt (1)
56-64: Consider handling state updates more atomically.When deleting a reminder, the state updates and picker visibility changes could be combined into a single state update to avoid potential race conditions.
onDeleteClick = { - onSelectedTimeChange(null) - onSelectedDateChange(null) - showTimePicker = false - showDatePicker = false + // Update all states atomically + onSelectedTimeChange(null) + onSelectedDateChange(null) + // Pickers are already closed when reminder is deleted }Since the pickers are only shown when actively selecting, they should already be closed when the delete action occurs.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (1)
13-18: Clarify constant naming and values.The constant
LOCAL_TIME_HOUR_DEFAULT = 24is confusing since valid hours are 0-23. Consider renaming toHOURS_IN_DAYor similar to clarify its purpose in the modulo operation.-const val LOCAL_TIME_HOUR_DEFAULT = 24 +const val HOURS_IN_DAY = 24And update the usage:
-return LocalTime(hour = nextHour % LOCAL_TIME_HOUR_DEFAULT, minute = LOCAL_TIME_MINUTE_DEFAULT) +return LocalTime(hour = nextHour % HOURS_IN_DAY, minute = LOCAL_TIME_MINUTE_DEFAULT)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreen.kt (2)
133-164: Consider adding error handling for notification content formatting.The
getNotificationTitleandgetNotificationContentfunctions use theformatutility which replaces placeholders. If the string templates don't match the expected number of arguments, this could cause issues.Consider wrapping the formatting in a try-catch or validating the template format:
is ScheduleReminder -> { + try { onIntent( OnScheduleReminder( reply = effect.reply, replyId = effect.replyId, notificationTitle = getNotificationTitle(strings, effect), notificationContent = getNotificationContent(strings, effect) ) ) + } catch (e: Exception) { + // Log error and show fallback message + snackbarHostState.showSnackbar(strings.notificationScheduleError) + } }
278-299: Consider simplifying the reminder validation logic for better readability.The current implementation uses multiple chained operations that make the logic harder to follow.
private fun onSaveReply( reply: Reply, onCheckNotificationPermission: (Reply) -> Unit, onAddOrEditReply: (Reply) -> Unit ) { val dateTime = getCurrentDateTime() - val reminderAt = reply.reminderAt.takeIf { it != INITIAL_DATE }?.dateTime() - val selectedTime = reminderAt?.time - val selectedDate = reminderAt?.date - return when { - selectedTime?.let { time -> - isDateTimeValid( - date = selectedDate, - time = time, - dateTime = dateTime - ) - } == true -> onCheckNotificationPermission(reply) + if (reply.reminderAt == INITIAL_DATE) { + onAddOrEditReply(reply) + return + } - else -> onAddOrEditReply(reply) + val reminderDateTime = reply.reminderAt.dateTime() + val isValid = isDateTimeValid( + date = reminderDateTime.date, + time = reminderDateTime.time, + dateTime = dateTime + ) + + if (isValid) { + onCheckNotificationPermission(reply) + } else { + onAddOrEditReply(reply) } }composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (2)
97-101: Consider using nullable type for pendingReplyId instead of INVALID_ID.Using
INVALID_IDas a sentinel value is less idiomatic in Kotlin compared to using nullable types.- private var pendingReplyId: Long? = INVALID_ID + private var pendingReplyId: Long? = nullThen update the check in
checkPendingReplyId:- if (pendingReplyId != INVALID_ID) { + if (pendingReplyId != null) {
310-328: Simplify redundant null checking in checkPendingReplyId.The
pendingReplyId?.letblock is redundant since we already know it's not null from the outer condition.if (reply != null) { onTabSelection() onOpenReply(reply) - pendingReplyId?.let { replyId -> - logUserAction( - actionType = OpenedNotification, - targetId = replyId - ) - } + logUserAction( + actionType = OpenedNotification, + targetId = pendingReplyId!! + ) pendingReplyId = null }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
composeApp/src/commonMain/composeResources/drawable/ic_close.pngis excluded by!**/*.pngcomposeApp/src/commonMain/composeResources/drawable/ic_date.pngis excluded by!**/*.pngcomposeApp/src/commonMain/composeResources/drawable/ic_notification.pngis excluded by!**/*.pngcomposeApp/src/commonMain/composeResources/drawable/ic_time.pngis excluded by!**/*.png
📒 Files selected for processing (107)
composeApp/build.gradle.kts(1 hunks)composeApp/schemas/com.rafaelfelipeac.replyradar.core.database.ReplyRadarDatabase/1.json(3 hunks)composeApp/schemas/com.rafaelfelipeac.replyradar.core.database.ReplyRadarDatabase/2.json(1 hunks)composeApp/src/androidMain/AndroidManifest.xml(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/AndroidApp.kt(2 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/MainActivity.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/Previews.kt(2 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/ReplyRadarApplication.kt(2 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/ConfigureSystemBars.kt(0 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/StatusBar.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/database/DatabaseFactory.kt(2 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/database/ReplyRadarMigrations.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/DatetimeExt.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformDatePicker.android.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.android.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/external/External.android.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/NotificationPermissionManager.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/NotificationUtils.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderSchedulerImpl.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderWorker.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Clock.kt(0 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/version/Version.android.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/di/Modules.android.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/app/ReplyRadarApp.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/AppConstants.kt(0 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/Dimens.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyConfirmationDialog.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyNotificationPermissionDialog.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyOutlinedButton.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyRadarError.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyReminder.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplySnackbar.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyTab.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyTextField.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyToggle.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/util/FormatReminderText.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/database/ReplyRadarDatabase.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformDatePicker.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/external/External.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/language/AppLanguage.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/navigation/AppNavHost.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/LocalNotificationPermissionManager.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/NotificationPermissionManager.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderScheduler.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/model/NotificationReminderParams.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/LocalReplyRadarStrings.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/Strings.kt(3 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsEn.kt(3 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsProvider.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsPt.kt(3 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ColorScheme.kt(3 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarColorScheme.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarColors.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarTheme.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarThemeAccessors.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/model/AppTheme.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/AppConstants.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Clock.kt(0 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Int.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Timestamp.kt(0 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Version.kt(0 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/version/Version.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/di/Modules.kt(0 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/activitylog/presentation/ActivityLogScreen.kt(11 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/app/settings/AppSettingsViewModel.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/database/entity/ReplyEntity.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/mapper/ReplyMapper.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/repository/ReplyRepositoryImpl.kt(4 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/di/ReplyModule.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/domain/model/Reply.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListEffect.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreen.kt(5 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreenIntent.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListState.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt(10 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/SnackbarState.kt(0 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/FloatingActionButton.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesArchivedScreen.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesOnTheRadarScreen.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesResolvedScreen.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesScreen.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyList.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyTimestampInfo.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/TopBar.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheet.kt(3 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetContent.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/data/repository/SettingsRepositoryImpl.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/repository/SettingsRepository.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/usecase/GetLanguageUseCase.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/usecase/GetThemeUseCase.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/usecase/SetLanguageUseCase.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/usecase/SetThemeUseCase.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsIntent.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsScreen.kt(10 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsState.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsViewModel.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/useractions/data/repository/UserActionRepositoryImpl.kt(3 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/useractions/domain/model/UserActionType.kt(3 hunks)composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/Shared.kt(1 hunks)composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/core/util/FakeClock.kt(0 hunks)composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/core/util/FakeReminderScheduler.kt(1 hunks)composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/settings/data/FakeSettingsRepository.kt(1 hunks)composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/settings/domain/FakeGetLanguageUseCase.kt(1 hunks)
⛔ Files not processed due to max files limit (26)
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/settings/domain/FakeGetThemeUseCase.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/app/settings/AppSettingsViewModelTest.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/ReplyRepositoryTest.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/ReplyListViewModelTest.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/GetLanguageUseCaseImplTest.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/GetThemeUseCaseImplTest.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/SetLanguageUseCaseImplTest.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/SetThemeUseCaseTest.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsViewModelTest.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/useractions/data/UserActionRepositoryTest.kt
- composeApp/src/desktopMain/kotlin/com/rafaelfelipeac/replyradar/Main.kt
- composeApp/src/desktopMain/kotlin/com/rafaelfelipeac/replyradar/core/database/DatabaseFactory.kt
- composeApp/src/desktopMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformDatePicker.desktop.kt
- composeApp/src/desktopMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.desktop.kt
- composeApp/src/desktopMain/kotlin/com/rafaelfelipeac/replyradar/core/external/External.desktop.kt
- composeApp/src/desktopMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Clock.desktop.kt
- composeApp/src/desktopMain/kotlin/com/rafaelfelipeac/replyradar/core/version/Version.desktop.kt
- composeApp/src/iosMain/kotlin/com/rafaelfelipeac/replyradar/MainViewController.kt
- composeApp/src/iosMain/kotlin/com/rafaelfelipeac/replyradar/core/database/DatabaseFactory.kt
- composeApp/src/iosMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformDatePicker.ios.kt
- composeApp/src/iosMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.ios.kt
- composeApp/src/iosMain/kotlin/com/rafaelfelipeac/replyradar/core/external/External.ios.kt
- composeApp/src/iosMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Clock.ios.kt
- composeApp/src/iosMain/kotlin/com/rafaelfelipeac/replyradar/core/version/Version.native.kt
- composeApp/src/main/res/values/strings.xml
- gradle/libs.versions.toml
💤 Files with no reviewable changes (9)
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/ConfigureSystemBars.kt
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Clock.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/di/Modules.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Version.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/core/util/FakeClock.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Clock.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/SnackbarState.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/AppConstants.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Timestamp.kt
🧰 Additional context used
🧬 Code Graph Analysis (14)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/MainActivity.kt (1)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/AndroidApp.kt (1)
AndroidApp(13-28)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/AndroidApp.kt (1)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/NotificationPermissionManager.kt (1)
rememberNotificationPermissionManager(29-83)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/useractions/data/repository/UserActionRepositoryImpl.kt (1)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (1)
getCurrentTimeMillis(25-27)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/repository/ReplyRepositoryImpl.kt (1)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (1)
getCurrentTimeMillis(25-27)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformDatePicker.android.kt (1)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (2)
getCurrentDateTime(21-23)isDateTimeValid(34-51)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/util/FormatReminderText.kt (2)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (2)
getCurrentDateTime(21-23)getDefaultTime(53-77)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/String.kt (1)
format(3-11)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyTimestampInfo.kt (2)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/String.kt (1)
format(3-11)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt (1)
formatTimestamp(16-21)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (6)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyButton.kt (1)
ReplyButton(12-25)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (2)
isDateTimeValid(34-51)getCurrentDateTime(21-23)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt (1)
getReminderTimestamp(23-56)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyOutlinedButton.kt (1)
ReplyOutlinedButton(26-56)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyConfirmationDialog.kt (1)
ReplyConfirmationDialog(26-95)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/String.kt (1)
format(3-11)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.android.kt (1)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (2)
isTimeValid(79-94)getCurrentDateTime(21-23)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesScreen.kt (3)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesOnTheRadarScreen.kt (1)
RepliesOnTheRadarScreen(16-43)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesResolvedScreen.kt (1)
RepliesResolvedScreen(12-24)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesArchivedScreen.kt (1)
RepliesArchivedScreen(13-26)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetContent.kt (3)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyReminder.kt (1)
ReplyReminder(41-156)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyTimestampInfo.kt (1)
ReplyTimestampInfo(19-32)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (1)
ReplyBottomSheetActions(40-103)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderWorker.kt (1)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/NotificationUtils.kt (1)
showReminderNotification(23-46)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreen.kt (7)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (1)
onIntent(102-108)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyNotificationPermissionDialog.kt (1)
NotificationPermissionDialog(9-35)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplySnackbar.kt (1)
ReplySnackbar(10-22)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/FloatingActionButton.kt (1)
FloatingActionButton(13-26)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyTab.kt (1)
ReplyTab(12-27)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (2)
getCurrentDateTime(21-23)isDateTimeValid(34-51)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/String.kt (1)
format(3-11)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheet.kt (2)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplySnackbar.kt (1)
ReplySnackbar(10-22)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetContent.kt (1)
ReplyBottomSheetContent(31-103)
⏰ 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). (1)
- GitHub Check: Build, Tests and Lint
🔇 Additional comments (169)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/StatusBar.kt (1)
1-1: All oldcore.util.StatusBarimports have been removedI ran a search for
com.rafaelfelipeac.replyradar.core.util.StatusBarand found no lingering imports. The package move tocom.rafaelfelipeac.replyradar.coreis fully applied—no further changes are needed.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarTheme.kt (1)
1-1: Theme package restructuring confirmedAll referenced theme entities are present under
com.rafaelfelipeac.replyradar.core.theme:
DarkColorScheme&LightColorSchemeinColorScheme.ktDarkExtraColors&LightExtraColorsinColorScheme.ktLocalReplyRadarColorsinReplyRadarColors.ktNo further changes required—approving the package move.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarColorScheme.kt (2)
1-1: Package restructuring is consistent.The package path change and corresponding import update align properly with the theme refactoring effort.
Also applies to: 6-6
26-27: New color property follows established pattern.The
replyBottomSheetIconColorextension property follows the same composable getter pattern as other color extensions, ensuring consistent theme access across the app.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyList.kt (2)
17-17: Import path updated consistently.The import update aligns with the theme package refactoring from
core.common.ui.themetocore.theme.
32-36: Code clarity improvements.The explicit parameter naming in
itemsIndexed(items = replies, ...)improves readability, and the modifier formatting maintains functionality while enhancing code organization.composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/external/External.android.kt (1)
1-1: Package restructuring improves organization.Moving from
core.utiltocore.externalbetter reflects the file's purpose of handling external app integrations (email and Play Store). The Android-specific implementation remains unchanged and continues to follow proper error handling patterns.composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/version/Version.android.kt (1)
1-1: Package restructuring enhances modularity.Moving from
core.utiltocore.versioncreates better separation of concerns by grouping version-related functionality. The Android implementation correctly handles version retrieval with proper null-safety fallback.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/LocalReplyRadarStrings.kt (1)
1-7: No stale references tocore.common.stringsfound
I ran the provided search scripts and confirmed there are zero hits forcore.common.stringsin imports or package declarations. All references have been updated. No further action needed.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyRadarError.kt (1)
7-13: Import updated correctly – no further action
LocalReplyRadarStringsnow resolves from the new package. Compiles cleanly and preserves behaviour.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyTextField.kt (1)
27-27: Confirmed:textFieldPlaceholderColoraccessor is present
ThetextFieldPlaceholderColorproperty is declared and exported in the new theme package—no build break will occur.Defined in:
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarColors.kt (
val textFieldPlaceholderColor)- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarColorScheme.kt (
val ColorScheme.textFieldPlaceholderColor)- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ColorScheme.kt (default values)
No further action required.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarThemeAccessors.kt (1)
1-9: Namespace realignment acknowledgedThe theme accessors class follows the new
core.themenamespace. No functional change – looks good.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/usecase/SetLanguageUseCase.kt (1)
3-15: No residualcore.common.languageimports detectedRan:
rg -n "core\.common\.language" --glob "*.kt"No matches found across all
.ktfiles—all modules appear migrated successfully.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/usecase/GetThemeUseCase.kt (1)
3-3: Import path updated – change is correct and consistent with the new theme module structure
No further issues spotted for this segment.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/language/AppLanguage.kt (1)
1-1: No residualcore.common.languageimports found
Ran repository-wide scans forcore.common.language(including import statements) and confirmed zero matches. The relocation is complete—no broken references detected.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/usecase/GetLanguageUseCase.kt (1)
3-3: Import path aligns with refactor – looks goodcomposeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/usecase/SetThemeUseCase.kt (1)
3-3: Theme import path updated correctly
No other changes required.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/model/AppTheme.kt (1)
1-1: No outdated AppTheme import paths detected
I ran a search for the oldcore.common.ui.theme.model.AppThemeimport and found no occurrences—callers have been successfully migrated.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyTab.kt (1)
10-10: Import path update looks correctThe new
core.themepackage is in line with the refactor; no further action required.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/Dimens.kt (1)
30-30: Consistent dimension naming — LGTM
iconButtonSizefits the existing naming scheme and fills the sizing gap betweeniconSizeLargeand button dimensions. No issues spotted.composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/settings/domain/FakeGetLanguageUseCase.kt (1)
3-4: Import relocation adopted correctlyThe fake use-case now references the new
core.languagemodule. Everything else remains intact.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsState.kt (1)
3-5: Import paths updated — looks fineThe
SettingsStatedata class is unchanged; only the package move is reflected. No further action needed.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListState.kt (1)
13-13: Excellent architectural improvement with effect-based UI handling.Removing
snackbarStatein favor of an effect-based system usingReplyListEffectis a clean architectural pattern that better separates UI state from side effects. This approach provides better control over snackbar lifecycle and user interactions.composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/Shared.kt (2)
7-7: Good practice centralizing test timestamp constants.Adding the
nowconstant improves test maintainability and consistency by eliminating magic numbers.
25-25: Consistent use of centralized test constant.Using the
nowconstant instead of a hardcoded literal maintains consistency across test data and makes future updates easier.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/app/settings/AppSettingsViewModel.kt (1)
5-6: ✓ Package reorganization verifiedThe imports in
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/app/settings/AppSettingsViewModel.kt
now correctly reference:
com.rafaelfelipeac.replyradar.core.language.AppLanguagecom.rafaelfelipeac.replyradar.core.theme.model.AppThemeShell checks confirm both files exist at the new paths and are consistently used across the codebase (22 and 21 occurrences respectively). No further changes required.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/data/repository/SettingsRepositoryImpl.kt (1)
7-8: Consistent package reorganization across the codebase.The import path updates are consistent with the package restructuring seen in other files, moving from
core.common.*to more directcore.*packages. This maintains consistency across the settings data layer.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsViewModel.kt (1)
5-6: No obsolete package references detectedA repository-wide search for
core.common.languageandcore.common.ui.theme.modelreturned no matches, confirming that all legacy package paths have been removed.composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/fakes/settings/data/FakeSettingsRepository.kt (1)
3-4: Imports updated correctly – no further action
Nothing else changed in this file. Looks good.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyOutlinedButton.kt (1)
22-23: Extension property verified: import is validThe
ColorScheme.buttonBorderColorextension is declared in
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarColorScheme.kt:8,
so the importcom.rafaelfelipeac.replyradar.core.theme.buttonBorderColorwill resolve correctly.
No further changes needed.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/external/External.kt (1)
1-1: Package relocation verified – allactualimplementations updatedAll platform-specific
External.*.ktfiles (Android, Desktop, iOS) now use the updated package directivecom.rafaelfelipeac.replyradar.core.external. No further changes are necessary.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/domain/repository/SettingsRepository.kt (1)
3-4: Imports updated correctly – no further action
The interface remains unchanged; imports point to the new packages.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsIntent.kt (1)
3-4: LGTM! Clean package refactoring.The import path updates align with the broader codebase reorganization from
core.common.*to more specific packages likecore.languageandcore.theme.model.composeApp/src/androidMain/AndroidManifest.xml (1)
5-5: LGTM! Required permission for notification features.The
POST_NOTIFICATIONSpermission is correctly added to support the new reminder notification functionality introduced in this PR.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyToggle.kt (2)
26-26: LGTM! Import path updated for package refactoring.The import path change aligns with the broader codebase reorganization from
core.common.stringstocore.strings.
75-79: LGTM! Improved parameter ordering and explicit sizing.The modifier parameter reordering and explicit
.size(iconSize)makes the code more readable while maintaining the same functionality.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsProvider.kt (1)
1-6: LGTM! Consistent package refactoring.The package declaration and import path updates align with the broader codebase reorganization, moving from
core.common.*to more specific packages likecore.stringsandcore.language.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/di/ReplyModule.kt (1)
34-35: LGTM! Added reminder scheduler dependency injection.The addition of
reminderSchedulerdependency to theReplyListViewModelcorrectly supports the new reminder scheduling functionality introduced in this PR.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/version/Version.kt (1)
1-3: LGTM! Clean expected function declaration.The package restructuring from
core.utiltocore.versionimproves code organization, and the expected function pattern is correctly implemented for multiplatform support.composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/MainActivity.kt (3)
6-7: Good addition of required constants.The imports for
INVALID_IDandPENDING_REPLY_ID_KEYsupport the notification-driven navigation feature.
14-14: Safe intent extra extraction.The null-safe extraction of
pendingReplyIdwith a proper fallback toINVALID_IDcorrectly handles cases where the intent might be null or missing the expected extra.
17-17: Proper parameter passing to AndroidApp.The
pendingReplyIdparameter is correctly passed toAndroidApp, enabling notification-driven navigation as confirmed by the relevant code snippet showingAndroidAppaccepts aLong?parameter.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/navigation/AppNavHost.kt (2)
25-28: Clean function signature update.The addition of the
pendingReplyIdparameter properly extends the navigation host to support notification-driven navigation.
44-44: Appropriate parameter threading.The
pendingReplyIdis correctly passed only toReplyListScreenRootsince it's the screen responsible for handling notification-triggered reply opening. Other navigation destinations don't need this parameter.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/useractions/data/repository/UserActionRepositoryImpl.kt (3)
3-3: Good refactoring to use centralized datetime utility.The import change from
ClocktogetCurrentTimeMillisaligns with the broader refactoring to remove the Clock abstraction and use centralized datetime utilities.
33-33: Direct function call improves code clarity.Using
getCurrentTimeMillis()directly is cleaner than the previousclock.now()approach and maintains the same functionality as confirmed by the datetime utility implementation.
20-20: Clock dependency removed and DI updated accordinglyThe
Clockparameter has been successfully removed fromUserActionRepositoryImpl, and the Koin module no longer provides or injectsClock. The repository is now instantiated with onlyuserActionDaoandreplyDao, matching the updated constructor.• UserActionRepositoryImpl constructor no longer declares
Clock(now onlyUserActionDao,ReplyDao).
•UserActionModule.kt’ssingleOf(::UserActionRepositoryImpl)binding aligns with the new two-parameter signature.
• No remaining references toClockin DI modules for user actions.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyConfirmationDialog.kt (2)
51-54: Good formatting improvements for better readability.The multi-line formatting of
Spacermodifier parameters enhances code readability and follows common Compose coding conventions.Also applies to: 62-65, 78-81
68-69: Consistent formatting applied to Row modifier.The multi-line formatting is consistently applied across all modifier parameters in the file.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ReplyRadarColors.kt (2)
1-1: Package restructuring looks good.The package name change from
core.common.ui.themetocore.themesimplifies the structure and aligns with the broader refactoring mentioned in the summary.
14-16: New color property addition follows good practices.The
replyBottomSheetIconColorproperty is properly added with consistent naming conventions. The trailing comma onsnackbarBackgroundColorimproves maintainability for future additions.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesOnTheRadarScreen.kt (3)
6-6: Import path simplification is consistent.The change from
core.common.stringstocore.stringsaligns with the broader package restructuring seen in the theme files.
11-11: Intent renaming improves clarity.The change from
OnReplyClicktoOnOpenReplybetter describes the intent's purpose and aligns with the comprehensive refactoring mentioned in the summary.Also applies to: 37-37
34-35: Code formatting enhancement.The multi-line formatting of
Modifier.fillMaxSize()improves readability without changing functionality.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesResolvedScreen.kt (1)
6-6: Consistent refactoring across similar components.The changes mirror those in
RepliesOnTheRadarScreen.kt- import path simplification, intent renaming fromOnReplyClicktoOnOpenReply, and improved code formatting. This consistency across similar components is excellent for maintainability.Also applies to: 9-9, 18-21
composeApp/schemas/com.rafaelfelipeac.replyradar.core.database.ReplyRadarDatabase/1.json (2)
5-5: Identity hash properly updated for schema changes.The identity hash change correctly reflects the database schema modifications, which is essential for Room to detect and handle schema changes properly.
Also applies to: 122-122
9-9: Migration Logic Confirmed forreminderAtColumn
- In
ReplyRadarMigrations.kt(MIGRATION_1_2) we addALTER TABLE replies ADD COLUMN reminderAt INTEGER NOT NULL DEFAULT 0- This migration is included in
ALL_MIGRATIONSand applied via.addMigrations(*ALL_MIGRATIONS)inDatabaseFactory.ktNo additional changes required—migration covers existing data.
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/database/DatabaseFactory.kt (3)
6-6: Import path change consistent with package restructuring.The change from
core.AppConstantstocore.util.AppConstantsaligns with the broader package reorganization seen throughout the codebase.
7-7: Migration support properly implemented.The addition of
ALL_MIGRATIONSimport and its usage in.addMigrations(*ALL_MIGRATIONS)correctly implements database migration support for the schema changes, ensuring smooth upgrades for existing users.Also applies to: 19-19
16-19: Explicit generic type parameter improves code clarity.Adding the explicit
<ReplyRadarDatabase>generic type parameter toRoom.databaseBuilderenhances type safety and code readability.composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/Previews.kt (1)
8-8: LGTM! Preview updated correctly for new ReplyListScreen signature.The changes properly update the preview to accommodate the new
effectparameter andonActivityLogClickcallback, using an appropriate empty flow for the preview context.Also applies to: 28-29
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/di/Modules.android.kt (1)
3-3: LGTM! DI module correctly configured for reminder scheduling.The singleton binding for
ReminderScheduleris properly set up with the Android context injection. The singleton scope is appropriate for a scheduling service.Also applies to: 8-9, 21-21
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/model/NotificationReminderParams.kt (1)
1-7: LGTM! Well-designed data class for notification parameters.The
NotificationReminderParamsdata class has a clean structure with appropriate types and clear property names, making it suitable for encapsulating notification reminder data.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/LocalNotificationPermissionManager.kt (1)
1-7: LGTM! Composition local properly implemented.The
LocalNotificationPermissionManagerfollows standard Compose composition local patterns with appropriate error handling for missing providers and clear naming conventions.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/mapper/ReplyMapper.kt (1)
15-16: LGTM! Consistent bidirectional mapping for reminderAt property.The addition of
reminderAtproperty mapping is correctly implemented in both directions, maintaining consistency betweenReplydomain model andReplyEntitydata class.Also applies to: 28-29
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplySnackbar.kt (1)
10-22: Well-designed reusable snackbar component with good theming integration.The component follows Compose best practices and properly integrates with Material3 theming. The use of extension properties from the theme system ensures consistency across the app.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/theme/ColorScheme.kt (2)
24-25: Consistent color additions with good naming convention.The new colors
snackbarBackgroundColorandreplyBottomSheetIconColorare properly defined for both light and dark themes with appropriate contrast values. The naming follows the established convention and clearly indicates their usage context.Also applies to: 43-44
1-1: Package restructuring validated
Search across the codebase found no remaining references tocom.rafaelfelipeac.replyradar.core.common.ui.theme. All imports have been updated to the newcom.rafaelfelipeac.replyradar.core.themepackage. No further action is required.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/NotificationPermissionManager.kt (1)
3-8: Well-designed interface following good practices.The interface is clean with clear method signatures. Using suspend functions is appropriate for permission requests and navigation actions that may involve async operations. The Boolean return type for
ensureNotificationPermission()provides clear success/failure indication.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyNotificationPermissionDialog.kt (1)
9-35: Clean dialog implementation following Compose best practices.The dialog component is well-structured with proper use of Material3 AlertDialog, localized strings, and composition-based callbacks. The implementation follows standard patterns for permission request dialogs.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/Int.kt (1)
3-6: Clean utility implementation for consistent formatting.The extension function is well-implemented with proper constants and clear naming. Using
padStartis the correct approach for left-padding with zeros to ensure consistent two-digit formatting.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsScreen.kt (2)
34-52: Import path updates align with package restructuring.The import path changes reflect the package reorganization mentioned in the PR summary, moving from generic
commonpackages to more specific packages likeutil,language,strings,theme, etc. This improves code organization.
104-107: Improved modifier chain formatting for better readability.The formatting changes to modifier chains and parameter positioning improve code readability and consistency. The repositioning of
verticalAlignmentin Row composables follows a more logical parameter order.Also applies to: 111-114, 118-121, 156-159, 191-194, 210-213, 228-228, 234-234, 252-253, 256-257, 262-265, 281-281, 283-283, 297-298, 301-302, 307-310, 363-366
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/AndroidApp.kt (1)
14-14: Proper integration of notification permission management.The changes correctly integrate the notification permission system by:
- Adding the nullable
pendingReplyIdparameter for notification-driven navigation- Obtaining the platform-specific notification permission manager via
rememberNotificationPermissionManager()- Passing both parameters to
ReplyRadarAppfor downstream handlingThe integration follows good architectural patterns for platform-specific functionality.
Also applies to: 25-26
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderScheduler.kt (1)
5-13: LGTM! Clean interface design with proper abstraction.The interface follows good design principles with clear method signatures and appropriate separation of concerns between scheduling and cancellation operations.
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/database/ReplyRadarMigrations.kt (1)
8-20: LGTM! Proper database migration implementation.The migration correctly adds the
reminderAtcolumn with appropriate constraints and default value. The dualmigratemethod implementation supports different SQLite APIs, and the SQL syntax is correct.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/repository/ReplyRepositoryImpl.kt (2)
3-4: LGTM! Clean refactoring from Clock dependency to utility function.The replacement of the Clock abstraction with direct utility function calls simplifies the code while maintaining the same functionality.
18-44: LGTM! Consistent time handling refactoring.The replacement of
clock.now()calls withgetCurrentTimeMillis()and the updated constant usage maintain the same logical behavior while simplifying the time handling approach.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/database/entity/ReplyEntity.kt (2)
5-5: LGTM! Updated import aligns with refactored constants.The import change from the old constants location to the new
core.util.AppConstantslocation is consistent with the broader refactoring.
14-19: LGTM! Proper addition of reminderAt field with consistent defaults.The new
reminderAtfield is properly integrated with:
- Appropriate default value using
INITIAL_DATE- Consistent naming convention
- Proper Long type for timestamp storage
- Alignment with database schema changes
All timestamp fields now consistently use the updated
INITIAL_DATEconstant.composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/DatetimeExt.kt (1)
13-17: LGTM! Good timezone handling.The implementation correctly handles timezone conversion and provides a sensible default parameter.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/domain/model/Reply.kt (2)
3-3: LGTM! Improved import path.The updated import path for
INITIAL_DATEreflects the package restructuring and improves organization.
11-15: LGTM! Good use of named constant and new reminder field.The replacement of magic number
0with theINITIAL_DATEconstant improves code readability and maintainability. The addition of thereminderAtfield properly supports the new reminder scheduling feature.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.kt (1)
7-16: LGTM! Well-designed multiplatform interface.The expect function signature is well-structured with appropriate parameters for a time picker component. The inclusion of
selectedDatealongsideselectedTimeis logical for validation purposes (e.g., preventing past time selection). The customizable text parameters provide good flexibility for different languages and contexts.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/app/ReplyRadarApp.kt (3)
11-20: LGTM! Clean integration of notification functionality.The updated imports reflect the package restructuring and properly bring in the required notification and strings functionality.
25-29: LGTM! Appropriate parameter additions for notification features.The new parameters integrate well with the reminder/notification functionality:
notificationPermissionManagerenables dependency injection of permission handlingpendingReplyIdsupports navigation from notification taps- Both parameters have sensible types and nullability
46-51: LGTM! Proper composition local integration.The notification permission manager is correctly provided through CompositionLocalProvider, making it available throughout the composition tree. The
pendingReplyIdis appropriately passed to the navigation host to handle notification-based navigation.composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderWorker.kt (2)
12-15: LGTM: Proper Worker class structureThe Worker class follows the standard WorkManager pattern with correct constructor parameters and inheritance.
29-37: LGTM: Proper notification handling and resultThe notification utility call and success result are correctly implemented. The function properly delegates to the notification utility which handles permission checks.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/TopBar.kt (4)
26-27: LGTM: Clean composable function signatureThe function has a clear, descriptive name and appropriate callback parameters for the user interactions.
32-41: LGTM: Well-structured activity log text componentThe clickable text implementation is correct with proper alignment, padding, and styling. The use of
clickablemodifier is appropriate for the interaction.
43-51: LGTM: Centered app title with appropriate stylingThe centered title uses proper alignment and typography styling. The font size customization with
fontSizeLargeprovides good visual hierarchy.
53-67: LGTM: Properly implemented settings icon buttonThe icon button is correctly implemented with proper alignment, padding, and accessibility support through the content description.
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformDatePicker.android.kt (4)
19-29: LGTM: Proper function signature and parameter handlingThe actual function correctly implements the expected interface with all required parameters.
32-41: LGTM: Correct date picker state with proper restrictionsThe date picker state properly initializes with the selected date and correctly restricts selectable dates to current date and future dates only.
45-95: LGTM: Proper dialog implementation with state managementThe dialog implementation correctly handles show/hide state, provides proper confirm and dismiss buttons, and manages the date picker component appropriately.
61-71: No changes needed for null-selectedTime handlingThe
onTimeInvalidatedcallback simply clears or resets the selected time (e.g. viaonSelectedTimeChange(null)in the consumer). Invoking it whenselectedTimeis alreadynullis idempotent and has no side-effects beyond ensuring the state stays cleared. The current logic correctly treats “no time chosen” as invalid for a newly picked date without introducing any regressions.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformDatePicker.kt (1)
7-16: LGTM: Well-designed multiplatform interfaceThe expected function signature is well-designed with:
- Appropriate nullable types for optional selections
- Clear callback parameter names and types
- Cross-platform kotlinx-datetime types
- Comprehensive parameter set for customization
The interface provides good flexibility for platform-specific implementations while maintaining type safety.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/util/FormatReminderText.kt (5)
13-18: LGTM: Proper null handlingThe early return when both date and time are null is correct and prevents unnecessary processing.
20-26: LGTM: Proper setup and helper function callsThe current datetime retrieval, default time calculation, and delegation to helper functions is well-structured.
27-34: LGTM: Clean string formatting logicThe conditional formatting based on available date and time parts is well-implemented, using the template formatting utility appropriately.
36-59: LGTM: Comprehensive date part formattingThe
getDatePartfunction correctly handles:
- Explicit date selection with proper DD/MM/YYYY formatting
- Today/Tomorrow logic when only time is selected
- Null case when neither is applicable
The Today/Tomorrow logic correctly compares the reminder time with current time.
61-69: LGTM: Consistent time formattingThe
getTimePartfunction provides consistent HH:MM formatting using thetoTwoDigitString()utility, properly handling both selected and default times.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesScreen.kt (2)
18-23: LGTM! Clean composable function signature.The function parameters and structure are well-designed for a tab-based UI component that delegates rendering to specific screen implementations.
40-55: LGTM! Proper screen routing logic.The when expression correctly maps page indices to their corresponding screen components, and all parameters are properly passed through.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/useractions/domain/model/UserActionType.kt (2)
11-12: LGTM! New user action types align with reminder feature.The
ScheduledandOpenedNotificationaction types are appropriately named and follow the existing pattern for tracking user interactions with the reminder and notification system.
41-42: LGTM! String constants follow naming convention.The new constants
SCHEDULEDandOPENED_NOTIFICATIONare consistently named and properly defined.composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.android.kt (2)
31-44: LGTM! Proper time picker state initialization and validation.The time picker state is correctly initialized with provided or default values, and the time validation logic properly prevents selection of past times using the
isTimeValidutility function.
46-81: LGTM! Well-structured AlertDialog implementation.The dialog properly handles user interactions, correctly enables/disables the confirm button based on validation, and appropriately calls all callback functions. The dialog state management ensures proper cleanup.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListEffect.kt (1)
5-19: LGTM! Well-designed effect system structure.The sealed interface approach properly encapsulates different UI effects, and the nested
SnackbarStateinterface effectively groups related snackbar effects. The effect types align well with the notification and reminder features.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt (2)
16-21: LGTM! Clean timestamp formatting implementation.The function correctly converts milliseconds to a readable date-time format using the extension function and proper zero-padding for minutes.
30-49: I’d like to inspect the fullTimestamp.ktimplementation to confirm how it converts between epoch andLocalDateTime(and whether it applies a timezone). Could you run:#!/bin/bash sed -n '1,200p' composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.ktcomposeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderSchedulerImpl.kt (3)
20-29: LGTM! Clean validation and delegation pattern.The method correctly validates the delay before proceeding with scheduling, preventing unnecessary work requests for past times.
31-33: LGTM! Proper use of WorkManager cancellation by tag.The implementation correctly uses WorkManager's tag-based cancellation, which is the recommended approach for canceling specific work requests.
56-58: LGTM! Simple and correct helper methods.Both helper methods are well-implemented:
getDelaycorrectly calculates the time differencegetTaguses string resources for consistent tag formattingcomposeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/activitylog/presentation/ActivityLogScreen.kt (8)
37-37: LGTM! Proper imports for new user action types and updated package paths.The new imports correctly add support for the
ScheduledandOpenedNotificationuser action types, along with their corresponding icons. The import path updates align with the package restructuring mentioned in the PR.Also applies to: 44-44, 46-46, 61-61, 64-64, 81-82
98-98: LGTM! Improved modifier formatting for better readability.The formatting changes improve code readability by placing modifiers on separate lines, which is a good Compose convention.
Also applies to: 131-132, 142-143, 155-156, 172-175
263-264: LGTM! Correct icon mappings for new user action types.The new cases properly map the
ScheduledandOpenedNotificationaction types to their appropriate icons (ic_timeandic_notification) within theMessagetarget type, which is logically correct.
302-303: LGTM! Consistent localized verb mappings for new action types.The new cases correctly provide localized verbs for the
ScheduledandOpenedNotificationaction types, maintaining consistency with the existing pattern.
37-37: LGTM! Import path updates align with package restructuring.The import path changes from
core.common.stringstocore.strings, and similar updates for theme and datetime utilities are consistent with the package restructuring mentioned in the PR.Also applies to: 44-44, 46-46
61-61: LGTM! New user action types properly imported.The imports for
Scheduled,OpenedNotificationaction types and their corresponding icons (ic_time,ic_notification) are correctly added to support the new reminder and notification features.Also applies to: 64-64, 81-82
263-264: LGTM! Icon mapping updated for new action types.The
getIconByActionTypefunction correctly maps the newScheduledandOpenedNotificationaction types to their respective icons when the target type isMessage.
302-303: LGTM! Action verb mapping updated consistently.The
getActionVerbfunction properly handles the new action types with appropriate localized strings forScheduledandOpenedNotification.composeApp/schemas/com.rafaelfelipeac.replyradar.core.database.ReplyRadarDatabase/2.json (2)
8-78: LGTM! Proper database schema update for reminder functionality.The addition of the
reminderAtcolumn to the replies table is correctly implemented:
- Proper INTEGER NOT NULL constraint for timestamp storage
- Maintains all existing columns and constraints
- Primary key configuration remains intact
79-118: LGTM! Well-designed user_actions table schema.The table schema correctly models user actions with:
- Appropriate nullable constraints (targetType and targetId can be null)
- Proper data types for each field
- Auto-generated primary key
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyTimestampInfo.kt (3)
19-32: LGTM! Well-structured composable with proper null safety.The component correctly:
- Uses
ColumnScopeextension for proper layout context- Implements null-safe access to the reply data
- Applies appropriate styling and alignment
20-32: LGTM! Well-structured Compose component with proper null handling.The component correctly uses
ColumnScopeextension, handles null state gracefully with safe call operator, and follows Material3 design guidelines with appropriate typography and alignment.
35-63: LGTM! Logical timestamp priority implementation.The
getTimestampInfofunction implements a clear priority hierarchy for timestamp display:
- Archived timestamp (highest priority)
- Resolved timestamp
- Updated timestamp (if different from created)
- Created timestamp (fallback)
The logic correctly uses
INITIAL_DATEconstant for comparison and properly formats timestamps with localized strings.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsPt.kt (3)
1-3: Package restructuring looks good.The package change from
core.common.stringstocore.stringssimplifies the package structure, and the import has been correctly updated to match.
45-58: Reminder strings are well-structured and properly localized.The Portuguese translations are appropriate and the placeholder pattern for date/time formatting is consistent with the
formatutility function usage.
108-121: Notification and activity log strings are complete and user-friendly.The Portuguese translations effectively communicate the notification permission requirements and provide clear CTAs. The notification content templates handle both cases with and without subject appropriately.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetContent.kt (3)
32-39: Good refactoring with clear separation of concerns.The composable now focuses on input management while delegating complex UI logic to specialized components. The explicit callbacks (
onSave,onResolve,onArchive,onDelete,onInvalidReminderValue) provide better clarity than a single intent handler.
43-45: Proper state management for reminder date and time.The extraction correctly filters out initial/default dates and properly converts the timestamp to date and time components. Using
remember(reminderAt)ensures the state updates when the reminder changes.
78-100: Clean component composition with proper responsibility delegation.Each component has a well-defined purpose:
ReplyReminder: Manages reminder selection UIReplyTimestampInfo: Displays timestampsReplyBottomSheetActions: Handles actions and validationThe keyboard management enhances user experience.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (3)
106-146: Well-structured state-based UI rendering.The pattern matching on reply states (active, resolved, archived) provides clear separation of UI logic for each state. The use of
weight(1f)ensures proper space distribution in the row layout.
192-218: Proper implementation of delete confirmation flow.The delete dialog correctly manages its visibility state and provides clear messaging to the user by including the reply name in the confirmation message.
223-236: Clean implementation of reply creation/update logic.The function properly handles both scenarios using Kotlin's copy method for immutability when editing existing replies.
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/NotificationPermissionManager.kt (3)
43-52: Correct handling of Android version compatibility.The implementation properly returns
truefor Android versions below TIRAMISU (API 33) where POST_NOTIFICATIONS permission is not required, and correctly checks the permission status for newer versions.
54-68: Sophisticated coroutine implementation for permission handling.The use of
suspendCancellableCoroutinewithsnapshotFloweffectively bridges the callback-based permission API with suspend functions. The cancellation handling ensures no memory leaks.
71-80: Safe implementation of app settings navigation.The function safely handles the context cast and creates the proper intent to navigate to the app's settings page.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyReminder.kt (3)
73-107: Well-structured platform picker integration.The conditional rendering and callback handling for both date and time pickers is properly implemented. The
onTimeInvalidatedcallback in the date picker ensures consistency when changing dates.
115-147: Good UX consideration with keyboard management.The icon buttons properly close the keyboard before showing pickers, preventing UI overlap issues. Accessibility is well-handled with content descriptions.
158-193: Clean implementation of reminder text display.The conditional rendering and delete functionality are properly implemented with appropriate styling and layout.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheet.kt (3)
24-30: Excellent architectural refactoring from intent-based to callback-based design.The explicit callbacks (
onSave,onResolve,onArchive,onDelete,onDismiss) improve code clarity, testability, and follow Compose best practices by making data flow more explicit and reducing coupling between components.
32-42: Well-implemented snackbar state management.The
LaunchedEffectproperly handles the invalid reminder value flag by showing the snackbar message and resetting the flag. The use ofremember { SnackbarHostState() }ensures the snackbar state persists across recompositions.
80-80: Good placement of ReplySnackbar component.Placing the
ReplySnackbarinside theModalBottomSheetensures snackbar messages are displayed within the context of the bottom sheet, providing better user experience for validation errors.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreenIntent.kt (4)
8-8: Good addition for handling pending reply state.The
OnPendingReplyIdintent with optionalLong?parameter provides flexibility for managing pending reply scenarios, which aligns well with the reminder scheduling feature.
11-11: Better naming for improved clarity.Renaming
OnReplyClicktoOnOpenReplyis more descriptive and clearly indicates the intent's purpose.
16-16: Smart consolidation of add/edit intents.Combining
OnAddReplyandOnEditReplyintoOnAddOrEditReplyreduces code duplication since both operations likely share similar handling logic in the view model.
23-33: Well-structured notification permission intent interface.The
NotificationPermissionIntentsealed interface is well-designed with clear separation of concerns:
- Permission management (
OnRequestNotificationPermission,OnCheckNotificationPermission)- Navigation (
OnGoToSettings)- Reminder scheduling (
OnScheduleReminderwith comprehensive parameters)The
OnScheduleReminderintent includes all necessary parameters for notification scheduling.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/Strings.kt (4)
1-1: Clean package restructuring.Moving from
core.common.stringstocore.stringssimplifies the package structure and improves organization.
40-53: Comprehensive reminder string properties.The reminder-related strings cover all necessary UI elements including labels, validation messages, icon descriptions, and picker button texts. The naming follows consistent patterns with the existing codebase.
89-90: Appropriate activity log verbs for new user actions.The
activityLogUserActionScheduledVerbandactivityLogUserActionOpenedNotificationVerbstrings properly support the new user action types for reminder scheduling and notification interaction tracking.
96-102: Well-designed notification permission and content strings.The notification permission dialog strings provide clear messaging, and the notification content templates with placeholders (
%1,%2) offer flexibility for different notification scenarios (with and without subject).composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsEn.kt (4)
1-3: Proper package and import updates.The package change to
core.stringsand import update tocore.version.getAppVersionalign with the overall package restructuring.
45-58: Natural and user-friendly reminder translations.The English translations are clear and conversational. Particularly good choices:
- "today"/"tomorrow" for relative dates
- "The selected date and time has already passed." for clear validation feedback
- Simple "OK"/"Cancel" for picker buttons
108-109: Appropriate English verbs for activity logging.The activity log verbs "scheduled a reminder for" and "opened a notification for" are grammatically correct and clearly describe the user actions.
115-121: Well-crafted notification permission and content text.The notification permission dialog text is informative and user-friendly without being pushy. The notification content templates use natural language that will read well when placeholders are filled.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (2)
19-32: Solid datetime utility functions.The basic datetime utilities (
now(),getCurrentDateTime(),getCurrentTimeMillis(), and theLong.dateTime()extension) provide a clean interface for common datetime operations and properly replace the previous Clock abstraction.
53-77: Complex but functional default time logic.The
getDefaultTimefunction handles multiple scenarios for determining an appropriate default time. The logic appears correct for validating selected time, falling back to a default time, and calculating next available hour when needed.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreen.kt (2)
79-94: LGTM! Good implementation of pending reply handling.The
LaunchedEffectproperly handles the pending reply ID from notifications, ensuring it's processed when the composable is first composed or when the ID changes.
301-334: Well-structured helper functions for message generation.The functions properly handle different snackbar states and notification content variations based on whether a subject is present.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (2)
229-238: Good implementation of upsert with reminder scheduling.The function correctly determines the action type and schedules the reminder after the reply is saved, ensuring a valid reply ID is available.
284-300: Clean implementation of reminder scheduling.Good use of
with()scope function and proper separation of concerns between scheduling the reminder and logging the user action.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesArchivedScreen.kt (3)
6-6: LGTM! Import path updated correctly.The import path change from
core.common.stringstocore.stringsaligns with the package restructuring mentioned in the PR summary.
9-9: LGTM! Intent import updated consistently.The import change from
OnReplyClicktoOnOpenReplyis consistent with the intent renaming refactoring across the reply list components.
19-23: LGTM! Formatting and intent usage updated correctly.The modifier chain formatting improves readability, and the intent usage change from
OnReplyClicktoOnOpenReplymaintains consistency with the refactoring effort.composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/NotificationUtils.kt (2)
41-43: LGTM! Proper permission checking implemented.The permission check for
POST_NOTIFICATIONSis correctly implemented with early return when permission is not granted, preventing SecurityException on Android 13+.
52-55: LGTM! Proper intent configuration for notification tap.The intent configuration with
FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASKensures the app launches cleanly from the notification, and the reply ID is properly passed as an extra.
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderWorker.kt
Show resolved
Hide resolved
...eApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/database/ReplyRadarDatabase.kt
Show resolved
Hide resolved
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt
Outdated
Show resolved
Hide resolved
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt
Show resolved
Hide resolved
...n/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/repository/ReplyRepositoryImpl.kt
Outdated
Show resolved
Hide resolved
...features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt
Show resolved
Hide resolved
...otlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListEffect.kt
Show resolved
Hide resolved
...ain/kotlin/com/rafaelfelipeac/replyradar/features/useractions/domain/model/UserActionType.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (1)
78-82: Fix reminder validation logic to prevent potential null pointer issues.The validation logic has the same issue identified in a previous review. The current implementation only checks if
selectedTimeis not null before callingisDateTimeValid, but this could cause issues if the function expects non-null parameters.Apply this fix to ensure safe validation:
- val reminderIsValid = selectedTime != null && isDateTimeValid( - selectedDate, - selectedTime, - getCurrentDateTime() - ) + val reminderIsValid = when { + selectedDate != null && selectedTime != null -> isDateTimeValid(selectedDate, selectedTime, getCurrentDateTime()) + selectedDate == null && selectedTime == null -> true // No reminder selected + else -> false // Incomplete reminder data + }
🧹 Nitpick comments (2)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreen.kt (2)
12-12: Unnecessary import for ExperimentalMaterial3ApiThe
ExperimentalMaterial3Apiimport is present but the annotation@OptIn(ExperimentalMaterial3Api::class)is only used for theReplyListScreencomposable. Consider removing this import if it's not needed elsewhere, or ensure it's properly used.
280-301: Potential edge case in date validation logicThe
onSaveReplyfunction has a complex validation flow that could benefit from clearer error handling. The nested conditional withtakeIfand nullable operations might be hard to debug if issues arise.Consider simplifying the logic for better readability:
private fun onSaveReply( reply: Reply, onCheckNotificationPermission: (Reply) -> Unit, onAddOrEditReply: (Reply) -> Unit ) { - val dateTime = getCurrentDateTime() - val reminderAt = reply.reminderAt.takeIf { it != INITIAL_DATE }?.dateTime() - val selectedTime = reminderAt?.time - val selectedDate = reminderAt?.date - - return when { - selectedTime?.let { time -> - isDateTimeValid( - date = selectedDate, - time = time, - dateTime = dateTime - ) - } == true -> onCheckNotificationPermission(reply) - - else -> onAddOrEditReply(reply) - } + if (reply.reminderAt == INITIAL_DATE) { + onAddOrEditReply(reply) + return + } + + val reminderDateTime = reply.reminderAt.dateTime() + val currentDateTime = getCurrentDateTime() + + if (isDateTimeValid(reminderDateTime.date, reminderDateTime.time, currentDateTime)) { + onCheckNotificationPermission(reply) + } else { + onAddOrEditReply(reply) + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (32)
composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/ReplyRadarApplication.kt(2 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/database/DatabaseFactory.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/database/ReplyRadarMigrations.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/NotificationPermissionManager.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/NotificationUtils.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/app/ReplyRadarApp.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyNotificationPermissionDialog.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyReminder.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyToggle.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/util/FormatReminderText.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/navigation/AppNavHost.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsEn.kt(3 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsPt.kt(3 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/activitylog/presentation/ActivityLogScreen.kt(11 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/repository/ReplyRepositoryImpl.kt(4 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListEffect.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreen.kt(5 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt(10 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/FloatingActionButton.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesArchivedScreen.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesOnTheRadarScreen.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesResolvedScreen.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyTimestampInfo.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/TopBar.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetContent.kt(2 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsScreen.kt(10 hunks)composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/ReplyRepositoryTest.kt(9 hunks)composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/ReplyListViewModelTest.kt(7 hunks)config/detekt/detekt.yml(3 hunks)
✅ Files skipped from review due to trivial changes (4)
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesOnTheRadarScreen.kt
- composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/ReplyRepositoryTest.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListEffect.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt
🚧 Files skipped from review as they are similar to previous changes (21)
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesResolvedScreen.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyNotificationPermissionDialog.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/RepliesArchivedScreen.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/settings/presentation/SettingsScreen.kt
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/database/ReplyRadarMigrations.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/repository/ReplyRepositoryImpl.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/navigation/AppNavHost.kt
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/ReplyRadarApplication.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyToggle.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsPt.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/app/ReplyRadarApp.kt
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/NotificationUtils.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/util/FormatReminderText.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/TopBar.kt
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/database/DatabaseFactory.kt
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/notification/NotificationPermissionManager.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyReminder.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/activitylog/presentation/ActivityLogScreen.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyTimestampInfo.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/FloatingActionButton.kt
🧰 Additional context used
🧬 Code Graph Analysis (2)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetContent.kt (3)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyReminder.kt (1)
ReplyReminder(41-163)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/ReplyTimestampInfo.kt (1)
ReplyTimestampInfo(18-29)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (1)
ReplyBottomSheetActions(40-107)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreen.kt (7)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (1)
onIntent(102-108)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyNotificationPermissionDialog.kt (1)
NotificationPermissionDialog(9-32)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplySnackbar.kt (1)
ReplySnackbar(10-22)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/FloatingActionButton.kt (1)
FloatingActionButton(13-26)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyTab.kt (1)
ReplyTab(12-27)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (2)
getCurrentDateTime(21-23)isDateTimeValid(34-51)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/String.kt (1)
format(3-11)
⏰ 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). (1)
- GitHub Check: Build, Tests and Lint
🔇 Additional comments (22)
composeApp/src/commonTest/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/ReplyListViewModelTest.kt (4)
64-64: Good addition of reminder scheduler dependency.The integration of
FakeReminderSchedulerproperly supports testing the new reminder functionality.Also applies to: 73-73
101-101: Intent renaming improves clarity.The rename from
OnReplyClicktoOnOpenReplybetter describes the action's purpose.
127-138: Well-structured tests for reminder functionality.The test properly validates that:
- No reminder is scheduled when
reminderAtisINITIAL_DATEScheduleRemindereffect is emitted when a valid reminder timestamp is provided- The effect contains the correct reply data
The separation of concerns between state and effect testing is excellent.
Also applies to: 140-154
129-129: Intent unification simplifies the API.Consolidating separate add and edit intents into
OnAddOrEditReplyreduces complexity while maintaining functionality.Also applies to: 159-159
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetContent.kt (3)
34-38: Improved callback interface design.The rename from
onCompletetoonSaveis more semantically clear, and the addition ofonInvalidReminderValueprovides better error handling separation.
43-45: Clean state extraction from reminder timestamp.The conversion of
reminderAtto separateselectedDateandselectedTimestate variables is well-implemented, with proper null handling and dependency on the reminder value.
78-100: Excellent modularization of UI components.Breaking down the bottom sheet into focused components (
ReplyReminder,ReplyTimestampInfo,ReplyBottomSheetActions) improves maintainability and separation of concerns.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (3)
40-107: Well-designed component structure for bottom sheet actions.The component properly:
- Handles conditional UI based on reply state and mode
- Validates reminder inputs before saving
- Provides clear callback separation for different actions
- Manages button states and layouts appropriately
152-223: Excellent state-specific button management.The state button components (
ActiveStateButtons,ResolvedStateButtons,ArchivedStateButton) provide appropriate actions for each reply state, with proper confirmation dialog for destructive actions.
227-240: Clean helper function for reply creation.The
getReplyToSavefunction properly handles both edit and create scenarios, correctly setting the reminder timestamp in both cases.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/strings/StringsEn.kt (4)
1-1: Good package restructuring and lint management.The move to
core.stringspackage and updated import paths align with the broader codebase reorganization. The MaxLineLength suppression is appropriate for string definitions.Also applies to: 3-3, 5-5
48-61: Comprehensive reminder-related strings.The reminder strings cover all necessary UI elements:
- Labels and status messages
- Icon content descriptions for accessibility
- Error messages for validation
- Picker button texts
111-112: New activity log verbs support reminder tracking.The addition of "scheduled a reminder for" and "opened a notification for" verbs properly extends the activity logging system for the new functionality.
118-124: Well-structured notification permission and content strings.The notification permission dialog strings provide clear user communication, and the notification content templates use proper placeholder formatting for dynamic data.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListScreen.kt (4)
133-166: Excellent effect handling implementationThe side effect collection using
LaunchedEffect(Unit)with proper flow collection is well-implemented. The when expression covers all effect types appropriately, and the notification permission flow is handled correctly.
168-176: Good UI state management for permission dialogThe notification permission dialog implementation correctly uses local state management with proper dismiss and navigation handling.
311-328: String formatting functions look goodThe notification title and content formatting functions properly handle the optional subject field and use the format utility function correctly.
82-93: pendingReplyId handling validated
- LaunchedEffect keyed on
pendingReplyIdonly runs on initial composition or when that key changes- The ViewModel’s internal
pendingReplyIdis cleared after processing, preventing duplicate intents
No further changes are needed.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (4)
97-99: Effect flow implementation is well-designedThe introduction of
MutableSharedFlow<ReplyListEffect>for one-time UI effects is a good architectural decision, separating side effects from state management.
148-156: New notification permission intent handling looks goodThe notification permission intent handling is well-structured and follows the existing pattern. Each intent is properly delegated to dedicated methods.
229-238: Reminder scheduling logic is well-integratedThe upsert reply logic correctly checks for reminder dates and emits the appropriate effect. The action type inference based on reply ID is clean.
284-300: Reminder scheduling implementation is comprehensiveThe
onScheduleRemindermethod properly uses the reminder scheduler and logs user actions. The parameter mapping is clear and follows good practices.
...in/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt
Outdated
Show resolved
Hide resolved
...in/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt
Outdated
Show resolved
Hide resolved
...in/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (1)
77-87: Reminder validation logic is correctly implemented.The validation logic properly delegates null handling to
isDateTimeValid(), which according to the utility function handles all combinations of null/non-null date and time parameters appropriately. The current implementation is safe and follows the expected pattern.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
CHANGELOG.md(1 hunks)README.md(2 hunks)composeApp/build.gradle.kts(2 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.android.kt(1 hunks)composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderWorker.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/activitylog/presentation/ActivityLogScreen.kt(11 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/repository/ReplyRepositoryImpl.kt(4 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt(10 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt(1 hunks)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/useractions/domain/model/UserActionType.kt(3 hunks)config/detekt/detekt.yml(3 hunks)
✅ Files skipped from review due to trivial changes (2)
- CHANGELOG.md
- README.md
🚧 Files skipped from review as they are similar to previous changes (8)
- composeApp/build.gradle.kts
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/reminder/ReminderWorker.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/data/repository/ReplyRepositoryImpl.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/activitylog/presentation/ActivityLogScreen.kt
- composeApp/src/androidMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/PlatformTimePicker.android.kt
- composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/useractions/domain/model/UserActionType.kt
- config/detekt/detekt.yml
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: rafaelfelipeac
PR: rafaelfelipeac/replyradar#5
File: config/detekt/detekt.yml:15-17
Timestamp: 2025-07-24T20:32:51.112Z
Learning: The user rafaelfelipeac prefers to create tech debt tasks to track future cleanup and refactoring work when temporarily relaxing code quality thresholds, showing a proactive approach to technical debt management.
Learnt from: rafaelfelipeac
PR: rafaelfelipeac/replyradar#5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt:0-0
Timestamp: 2025-07-24T22:13:32.250Z
Learning: The user rafaelfelipeac consistently implements robust solutions that go beyond the immediate problem, adding defensive programming measures like the isPendingReplyHandled flag in the ReplyListViewModel to prevent duplicate processing, showing strong attention to edge cases and race conditions.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (3)
Learnt from: rafaelfelipeac
PR: #5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt:310-329
Timestamp: 2025-07-24T20:32:50.673Z
Learning: In ReplyRadar app, Reply entities have mutually exclusive states: a reply can only be in one state at a time (pending/resolved/archived). This means replies cannot exist in multiple collections simultaneously, eliminating concerns about race conditions when processing replies across different state-based collections in the ReplyListViewModel.
Learnt from: rafaelfelipeac
PR: #5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt:0-0
Timestamp: 2025-07-24T22:13:32.250Z
Learning: The user rafaelfelipeac consistently implements robust solutions that go beyond the immediate problem, adding defensive programming measures like the isPendingReplyHandled flag in the ReplyListViewModel to prevent duplicate processing, showing strong attention to edge cases and race conditions.
Learnt from: rafaelfelipeac
PR: #5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListEffect.kt:21-21
Timestamp: 2025-07-24T20:10:20.763Z
Learning: In ReplyListEffect.ScheduleReminder, the replyId parameter is necessary because it represents the actual database ID returned from upsertReply operation, which differs from reply.id during new reply creation where the reply object initially has a placeholder/default ID.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (1)
Learnt from: rafaelfelipeac
PR: #5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt:310-329
Timestamp: 2025-07-24T20:32:50.673Z
Learning: In ReplyRadar app, Reply entities have mutually exclusive states: a reply can only be in one state at a time (pending/resolved/archived). This means replies cannot exist in multiple collections simultaneously, eliminating concerns about race conditions when processing replies across different state-based collections in the ReplyListViewModel.
🧬 Code Graph Analysis (1)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (6)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyButton.kt (1)
ReplyButton(12-25)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (2)
isDateTimeValid(34-56)getCurrentDateTime(21-23)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Timestamp.kt (1)
getReminderTimestamp(37-70)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyOutlinedButton.kt (1)
ReplyOutlinedButton(26-56)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/common/ui/components/ReplyConfirmationDialog.kt (1)
ReplyConfirmationDialog(26-95)composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/util/String.kt (1)
format(3-11)
⏰ 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). (1)
- GitHub Check: Build, Tests and Lint
🔇 Additional comments (10)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/components/replybottomsheet/ReplyBottomSheetActions.kt (3)
116-149: Well-structured state-dependent button rendering.The conditional logic correctly handles the mutually exclusive reply states (active/resolved/archived) and delegates to appropriate specialized composables. The use of
weight(WEIGHT)ensures proper layout distribution in edit mode.
190-223: Excellent confirmation dialog implementation for destructive actions.The delete confirmation dialog properly uses local state management and the format utility to create a personalized confirmation message. This follows UI best practices for destructive operations.
227-240: Clean utility functions with proper conditional logic.The
getReplyToSavefunction elegantly handles both create and update scenarios using the elvis operator, and properly includes the reminder timestamp functionality. The implementation is concise and readable.composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/core/datetime/Datetime.kt (3)
13-18: Clear and well-named constants for time calculations.The constant definitions provide good semantic meaning for time-related calculations. The naming convention is consistent and descriptive.
34-56: Comprehensive date/time validation logic.The validation function correctly handles all combinations of null/non-null date and time parameters, ensuring reminders are only set for future times. The logic is clear and covers all necessary cases.
58-82: Well-designed fallback strategy for default time selection.The function implements a logical hierarchy: preferred user time → default app time → next available hour. The modulo operation correctly handles 24-hour wrap-around for edge cases.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (4)
97-101: Well-implemented effect-based architecture with defensive programming.The introduction of
MutableSharedFlowfor effects provides a clean separation between state and one-time events. TheisPendingReplyHandledflag demonstrates good defensive programming to prevent duplicate processing, which aligns with your robust implementation approach.
156-166: Excellent solution for race condition prevention.The
handlePendingReplyIdOnceimplementation perfectly addresses the previous race condition concerns by immediately processing the pending reply ID with current state while preventing duplicate handling through the defensive flag. This demonstrates strong attention to edge cases.
295-311: Clean integration of reminder scheduling with proper logging.The
onScheduleRemindermethod effectively integrates the ReminderScheduler and maintains consistent user action logging. The pattern of extracting parameters and scheduling the reminder is clear and follows established conventions.
240-249: Excellent unification of add/edit reply logic.The unified
onUpsertReplymethod elegantly handles both create and edit scenarios with clean action type inference. The integration of reminder scheduling through effects maintains separation of concerns while reducing code duplication.
...in/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt(10 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: rafaelfelipeac
PR: rafaelfelipeac/replyradar#5
File: config/detekt/detekt.yml:15-17
Timestamp: 2025-07-24T20:32:51.160Z
Learning: The user rafaelfelipeac prefers to create tech debt tasks to track future cleanup and refactoring work when temporarily relaxing code quality thresholds, showing a proactive approach to technical debt management.
Learnt from: rafaelfelipeac
PR: rafaelfelipeac/replyradar#5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt:0-0
Timestamp: 2025-07-24T22:13:32.263Z
Learning: The user rafaelfelipeac consistently implements robust solutions that go beyond the immediate problem, adding defensive programming measures like the isPendingReplyHandled flag in the ReplyListViewModel to prevent duplicate processing, showing strong attention to edge cases and race conditions.
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (3)
Learnt from: rafaelfelipeac
PR: #5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt:310-329
Timestamp: 2025-07-24T20:32:50.724Z
Learning: In ReplyRadar app, Reply entities have mutually exclusive states: a reply can only be in one state at a time (pending/resolved/archived). This means replies cannot exist in multiple collections simultaneously, eliminating concerns about race conditions when processing replies across different state-based collections in the ReplyListViewModel.
Learnt from: rafaelfelipeac
PR: #5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt:0-0
Timestamp: 2025-07-24T22:13:32.263Z
Learning: The user rafaelfelipeac consistently implements robust solutions that go beyond the immediate problem, adding defensive programming measures like the isPendingReplyHandled flag in the ReplyListViewModel to prevent duplicate processing, showing strong attention to edge cases and race conditions.
Learnt from: rafaelfelipeac
PR: #5
File: composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListEffect.kt:21-21
Timestamp: 2025-07-24T20:10:20.784Z
Learning: In ReplyListEffect.ScheduleReminder, the replyId parameter is necessary because it represents the actual database ID returned from upsertReply operation, which differs from reply.id during new reply creation where the reply object initially has a placeholder/default ID.
⏰ 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). (1)
- GitHub Check: Build, Tests and Lint
🔇 Additional comments (11)
composeApp/src/commonMain/kotlin/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt (11)
80-80: LGTM! ReminderScheduler dependency added correctly.The addition of
ReminderSchedulerfollows proper dependency injection patterns and is necessary for the new reminder scheduling functionality.
97-101: Excellent implementation of effect handling and defensive programming.The new
_effectflow properly handles one-time UI effects, and the pendingReplyId improvements address previous inconsistencies:
- Nullable initialization to
nullis semantically correctisPendingReplyHandledflag prevents duplicate processing (great defensive programming!)
147-154: LGTM! Notification permission intent handling follows established patterns.The method structure is consistent with existing intent handlers and properly delegates to specific handler methods.
156-166: Excellent solution for pending reply handling with race condition prevention.This method demonstrates strong defensive programming:
- Immediate processing eliminates race conditions
isPendingReplyHandledflag prevents duplicate processing- Clean separation of concerns with checkPendingReplyId
This is a more robust solution than simple immediate processing, showing attention to edge cases.
168-177: Good refactoring for reply opening logic.Extracting this logic into a dedicated method improves code organization and reusability.
193-196: LGTM! Maintains flow-based pending reply checking.The addition of
checkPendingReplyIdcalls in data flows works well with the immediate processing inhandlePendingReplyIdOnce, ensuring comprehensive coverage.
240-249: Excellent unification of add/edit functionality with smart reminder handling.Key improvements:
- Smart action type inference based on
reply.id == INITIAL_ID- Conditional reminder scheduling only when
reminderAt != INITIAL_DATE- Proper effect emission for UI handling
The logic is clean and handles both creation and editing scenarios effectively.
256-256: Good architectural improvement using effect-based snackbar handling.Replacing state updates with effect emissions for snackbars provides better separation of concerns and one-time UI events handling.
279-289: LGTM! Clean notification permission effect methods.These methods properly emit notification-related effects following the established pattern. Simple and effective implementation.
295-311: Comprehensive reminder scheduling implementation.The method correctly:
- Schedules reminders using the injected ReminderScheduler
- Creates proper NotificationReminderParams
- Logs the scheduling action for user activity tracking
- Uses the correct replyId from the intent parameter
342-346: Good extraction of tab selection logic.Clean separation of concerns with a dedicated method for tab selection state updates.
...in/com/rafaelfelipeac/replyradar/features/reply/presentation/replylist/ReplyListViewModel.kt
Show resolved
Hide resolved
|
@coderabbitai, can you organize all the still valid nitpick comments in a list? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chainI'll help you organize the still valid nitpick comments. Let me gather the existing review comments from this PR first. @rafaelfelipeac, I searched for existing review comments on this PR, but it appears there are no previous review comments to organize. The GitHub API calls returned empty results, indicating that either:
Since there are no existing nitpick comments to organize, there's nothing to list at this time. If you'd like me to perform a fresh review of the code changes and identify potential nitpick items, I'd be happy to do that instead. Would you like me to:
🐰 🏁 Script executed: Length of output: 160431 🏁 Script executed: Length of output: 153233 🏁 Script executed: Length of output: 68322 @rafaelfelipeac Here is an organized list of all still valid nitpick comments from this PR: 1.
|
|
@coderabbitai, can you organize all the still valid nitpick comments in a list? Add details, examples and discussion, when needed. I will use this list in a future PR to attack the nitpick points. |
|
Tip For best results, initiate chat on the files or code changes. @rafaelfelipeac Here's a comprehensive, detailed list of all still valid nitpick comments for your future PR: 🔧 Detailed Nitpick Comments List1. StatusBar.kt - Color & Safety ImprovementsFile: Issues:
Details & Examples: // Current approach (manual ARGB calculation)
val argb = (alpha * 255.0f + 0.5f).toInt() shl 24 or
(red * 255.0f + 0.5f).toInt() shl 16 or
(green * 255.0f + 0.5f).toInt() shl 8 or
(blue * 255.0f + 0.5f).toInt()
// Preferred approach
val argb = color.toArgb()
// Null-safety improvement needed
activity?.window?.insetsController?.let { controller ->
// Safe operations here
}Why it matters: Manual ARGB calculations are error-prone and less readable. Null-safety prevents potential crashes. 2. Build Configuration - WorkManager ScopeFile: Issue: WorkManager dependency should be restricted to Android source-set Details: Currently WorkManager is added to common dependencies, but it's Android-specific. Example Fix: // Move from commonMain dependencies to:
androidMain.dependencies {
implementation(libs.androidx.work.runtime.ktx)
}Why it matters: Prevents build issues on other platforms and clarifies platform-specific dependencies. 3. AppConstants.kt - Production ReadinessFile: Issues:
Details & Discussion: // Current
const val EMAIL = "rafaelfelipeac@gmail.com" // Personal email exposed
// Suggested improvements
object ContactInfo {
const val SUPPORT_EMAIL = "support@replyradar.com" // Generic email
// Or load from build config/environment
}
object TimeConstants {
/** Default reminder hour (1 PM) */
const val DEFAULT_REMINDER_HOUR = 13
/** Default reminder minute */
const val DEFAULT_REMINDER_MINUTE = 0
/** Offset for next day calculation */
const val NEXT_DAY_OFFSET = 1
}Why it matters: Production apps shouldn't expose personal emails. Documented constants improve maintainability. 4. ReplyRadarApplication.kt - Notification ChannelFile: Issues:
Details & Discussion: // Current approach lacks justification and error handling
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
// Why IMPORTANCE_HIGH? Maybe IMPORTANCE_DEFAULT is sufficient
getString(R.string.notification_channel_id),
getString(R.string.notification_channel_name),
NotificationManager.IMPORTANCE_HIGH // ← Needs justification
)
// Add error handling here
}
}
// Suggested improvement
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
val channel = NotificationChannel(
getString(R.string.notification_channel_id),
getString(R.string.notification_channel_name),
// IMPORTANCE_DEFAULT unless reminders are truly urgent
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = getString(R.string.notification_channel_description)
}
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager?.createNotificationChannel(channel)
} catch (e: Exception) {
// Log error but don't crash the app
}
}
}Why it matters: IMPORTANCE_HIGH makes notifications very intrusive. Error handling prevents app crashes. 5. FloatingActionButton.kt - Naming ConflictFile: Issue: Name conflicts with Material3's FloatingActionButton Details: // Current - causes import confusion
@Composable
fun FloatingActionButton(...)
// Suggested alternatives
@Composable
fun ReplyFloatingActionButton(...)
// or
@Composable
fun AddReplyFab(...)Why it matters: Prevents import confusion and makes the component's purpose clearer. 6. FakeReminderScheduler.kt - Test UtilitiesFile: Issue: Missing utility methods for test assertions Details & Examples: class FakeReminderScheduler : ReminderScheduler {
private val _scheduledReminders = mutableListOf<Pair<Long, NotificationReminderParams>>()
private val _cancelledReminders = mutableListOf<Long>()
// Add these utility methods
fun getScheduledReminders(): List<Pair<Long, NotificationReminderParams>> = _scheduledReminders.toList()
fun getCancelledReminders(): List<Long> = _cancelledReminders.toList()
fun wasReminderScheduled(replyId: Long): Boolean =
_scheduledReminders.any { it.second.replyId == replyId }
fun wasReminderCancelled(replyId: Long): Boolean =
_cancelledReminders.contains(replyId)
fun getScheduledReminderFor(replyId: Long): Pair<Long, NotificationReminderParams>? =
_scheduledReminders.find { it.second.replyId == replyId }
fun clear() {
_scheduledReminders.clear()
_cancelledReminders.clear()
}
}Why it matters: Makes tests more readable and assertions more precise. 7. DatetimeExt.kt - Timezone ConsistencyFile: Issue: Potential timezone inconsistency Details & Discussion: // Current - might have timezone mismatches
fun LocalDate.toEpochMillis(): Long {
return this.atStartOfDay(TimeZone.currentSystemDefault()).toEpochMilliseconds()
}
fun Long.toLocalDate(timeZone: TimeZone = TimeZone.currentSystemDefault()): LocalDate {
return Instant.fromEpochMilliseconds(this).toLocalDateTime(timeZone).date
}
// Consider: Should both functions use the same timezone approach?
// Maybe add explicit timezone parameters for clarityWhy it matters: Timezone mismatches can cause date calculation errors, especially around daylight saving transitions. 8. RepliesScreen.kt - Layout OptimizationFile: Issue: Overly nested layout structure Details: // Current - deeply nested
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
// Content
}
}
}
// Simplified alternative
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
) {
// Direct content without extra Box wrapper
}Why it matters: Reduces composition overhead and improves performance. 9. PlatformTimePicker.android.kt - UX ImprovementFile: Issue: Non-intuitive default time (12:12) Details: // Current default
val initialTime = selectedTime ?: LocalTime(12, 12)
// More intuitive alternatives
val initialTime = selectedTime ?: LocalTime(9, 0) // 9:00 AM
// or current time + 1 hour
val initialTime = selectedTime ?: Clock.System.now()
.toLocalDateTime(TimeZone.currentSystemDefault())
.time.let { LocalTime(it.hour + 1, 0) }Why it matters: Better user experience with sensible defaults. 10. ReminderSchedulerImpl.kt - Edge Cases & PerformanceFile: Issues:
Details & Examples: // Current approach
private fun getDelayMillis(reminderAtMillis: Long): Long {
return reminderAtMillis - System.currentTimeMillis()
}
// Improved with edge case handling
private fun getDelayMillis(reminderAtMillis: Long): Long {
val delay = reminderAtMillis - System.currentTimeMillis()
return when {
delay <= 0 -> 0L // Handle immediate scheduling
delay < MIN_DELAY_MS -> MIN_DELAY_MS // Minimum delay
else -> delay
}
}
// Resource optimization
companion object {
private const val MIN_DELAY_MS = 1000L // 1 second minimum
private const val REPLY_ID_KEY = "REPLY_ID_KEY" // Cache keys
private const val NOTIFICATION_TITLE_KEY = "NOTIFICATION_TITLE_KEY"
private const val NOTIFICATION_CONTENT_KEY = "NOTIFICATION_CONTENT_KEY"
}Why it matters: Prevents edge case issues and improves performance through caching. 11. NotificationUtils.kt - Hash Collision RiskFile: Issue: Potential hash collision with Details: // Current - potential collision
NotificationManagerCompat.from(context).notify(replyId.hashCode(), notification)
// Safer alternatives
NotificationManagerCompat.from(context).notify(replyId.toInt(), notification)
// or if replyId might be too large
NotificationManagerCompat.from(context).notify(
(replyId and 0x7FFFFFFF).toInt(), // Ensure positive int
notification
)Why it matters: Hash collisions could cause notification replacement issues. 12. ReplyTimestampInfo.kt - Logic Edge CaseFile: Issue: Edge case where updatedAt == createdAt but both are meaningful Details: // Current logic might miss some cases
private fun getTimestampInfo(reply: Reply): String {
// Consider: What if updatedAt equals createdAt but both are set to meaningful times?
// Current logic: updatedAt != createdAt
// Better: updatedAt != INITIAL_DATE && updatedAt != createdAt
}Why it matters: Ensures accurate timestamp display in all scenarios. 13. ReplyReminder.kt - State ManagementFile: Issue: Non-atomic state updates on delete Details: // Current - separate state updates
onDeleteClick = {
onSelectedTimeChange(null)
onSelectedDateChange(null)
showTimePicker = false
showDatePicker = false
closeKeyboard?.invoke()
}
// Better - atomic update or use effect
onDeleteClick = {
// Group related state changes
onSelectedTimeChange(null)
onSelectedDateChange(null)
// Reset picker states
showTimePicker = false
showDatePicker = false
closeKeyboard?.invoke()
}Why it matters: Prevents inconsistent intermediate states during deletion. 14. Datetime.kt - Naming ClarityFile: Issue: Unclear constant naming Details: // Current
private const val LOCAL_TIME_HOUR_DEFAULT = 13
// Clearer alternatives
private const val DEFAULT_REMINDER_HOUR = 13 // 1 PM
// or with documentation
/** Default reminder time: 1:00 PM */
private const val DEFAULT_REMINDER_HOUR = 13Why it matters: Self-documenting code reduces cognitive load. 15. ReplyListScreen.kt - Error Handling & LogicFile: Issues:
Details: // Add error handling for string formatting
private fun getNotificationContent(strings: Strings, effect: ScheduleReminder): String {
return try {
if (effect.reply.subject.isNotBlank()) {
strings.notificationContent.format(effect.reply.name, effect.reply.subject)
} else {
strings.notificationContentWithoutSubject.format(effect.reply.name)
}
} catch (e: Exception) {
// Fallback content
"Reminder: ${effect.reply.name}"
}
}
// Simplify validation logic in onSaveReply
private fun onSaveReply(
reply: Reply,
onCheckNotificationPermission: (Reply) -> Unit,
onAddOrEditReply: (Reply) -> Unit
) {
val hasReminder = reply.reminderAt != INITIAL_DATE
if (hasReminder) {
onCheckNotificationPermission(reply)
} else {
onAddOrEditReply(reply)
}
}Why it matters: Prevents crashes from malformed strings and improves code readability. 16. ReplyListViewModel.kt - Type Safety & LogicFile: Issues:
Details: // Current approach with magic constant
private var pendingReplyId: Long? = null
// vs
private var pendingReplyId: Long = INVALID_ID
// Simplify null checking
private fun checkPendingReplyId(replies: List<Reply>, onTabSelection: () -> Unit) {
pendingReplyId?.let { id ->
replies.find { it.id == id }?.let { reply ->
onTabSelection()
onOpenReply(reply)
// ... rest of logic
pendingReplyId = null
}
}
}Why it matters: Nullable types are more idiomatic Kotlin than magic constants. Reduces redundant checks. 📋 Implementation Priority SuggestionsHigh Priority (affects functionality/safety):
Medium Priority (code quality/maintainability):
Low Priority (style/optimization):
This comprehensive list should serve as your roadmap for addressing technical debt in future PRs! 🚀 🧠 Learnings used |
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Refactor
Chores