Skip to content

feat : Added Time Based Sorting#98

Draft
revanthkumarJ wants to merge 4 commits intoopenMF:devfrom
revanthkumarJ:time_based_sort
Draft

feat : Added Time Based Sorting#98
revanthkumarJ wants to merge 4 commits intoopenMF:devfrom
revanthkumarJ:time_based_sort

Conversation

@revanthkumarJ
Copy link
Contributor

@revanthkumarJ revanthkumarJ commented Dec 25, 2025

image image image image

Summary by CodeRabbit

  • New Features

    • Time-based dark mode: choose "Based on Time" in settings to enable automatic dark mode during a configurable time window (default 18:00–06:00).
    • New time-picker dialog in Settings to set start/end times with Apply/Cancel controls and updated localized strings.
  • Chores

    • Updated project wiring and dependencies to support the new theming features.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 25, 2025

📝 Walkthrough

Walkthrough

Adds time-based dark theme support: new TimeBasedTheme model and BASED_ON_TIME enum; DateHelper utilities; repository and datastore observables/setters; UI for selecting time ranges (TimeBasedThemeDialog) and settings wiring; AppViewModel observes and applies time-based theme updates. Also a small AppThemeExtensions branch added for BASED_ON_TIME.

Changes

Cohort / File(s) Summary
Data Models
core/model/.../TimeBasedTheme.kt, core/model/.../DarkThemeConfig.kt, core/model/.../UserData.kt
New TimeBasedTheme data class; added BASED_ON_TIME to DarkThemeConfig; UserData gains timeBasedTheme and DEFAULT updated (also enableScreenCapture set true).
Time Utilities
core/common/.../DateHelper.kt, cmp-android/src/main/kotlin/cmp/android/app/AppThemeExtensions.kt
New DateHelper with isDarkModeBasedOnTime(), formatTimeRange(), format(); AppThemeExtensions.isDarkMode now handles BASED_ON_TIME (mapped to false branch in extension).
Repository / Datastore
core/data/.../UserDataRepository.kt, core/data/.../UserDataRepositoryImpl.kt, core/datastore/.../UserPreferencesRepository.kt, core/datastore/.../UserPreferencesRepositoryImpl.kt
Added observeTimeBasedThemeConfig: Flow<TimeBasedTheme> and suspend setTimeBasedThemeConfig(TimeBasedTheme) across repo and datastore interfaces and implementations; wiring to persist and emit time-based theme.
App State & Navigation
cmp-navigation/src/commonMain/kotlin/cmp/navigation/AppViewModel.kt
AppState gains timeBasedTheme; new AppAction.Internal.TimeBasedThemeUpdate; AppViewModel observes time-based config, dispatches and handles updates, and computes darkTheme considering BASED_ON_TIME via DateHelper.
Settings UI & ViewModel
feature/settings/.../SettingsDialog.kt, feature/settings/.../SettingsScreen.kt, feature/settings/.../SettingsViewmodel.kt, feature/settings/build.gradle.kts
Added TimeBasedThemeDialog composable and helpers (TimeRow, TimePickerDialog); SettingsDialog signature gains onChangeTimeBasedTheme; SettingsViewmodel and UserEditableSettings include timeBasedTheme and updateTimeBasedThemeConfig(); added core.common dependency.
Resources & Classpath
feature/settings/src/commonMain/composeResources/values/strings.xml, cmp-android/dependencies/prodReleaseRuntimeClasspath.tree.txt
Added strings for time-based theme UI (start/end labels, apply/cancel/ok, labels); runtime classpath snapshot extended to include project :core:common entries in dependency tree.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant SettingsUI as Settings UI
    participant TimeDialog as TimeBasedThemeDialog
    participant SettingsVM as SettingsViewmodel
    participant Repo as UserDataRepository
    participant Prefs as UserPreferencesRepository
    participant AppVM as AppViewModel
    participant DateHelper as DateHelper
    participant Theme as AppThemeExtensions

    User->>SettingsUI: Choose "Based on Time"
    SettingsUI->>TimeDialog: Open time picker
    User->>TimeDialog: Set start/end -> Confirm
    TimeDialog->>SettingsVM: updateTimeBasedThemeConfig(timeBasedTheme)
    SettingsVM->>Repo: setTimeBasedThemeConfig(timeBasedTheme)
    Repo->>Prefs: setTimeBasedThemeConfig(timeBasedTheme)
    Prefs->>Prefs: Persist

    Prefs-->>AppVM: observeTimeBasedThemeConfig emits
    AppVM->>AppVM: Dispatch TimeBasedThemeUpdate
    AppVM->>DateHelper: isDarkModeBasedOnTime(start,end)
    DateHelper-->>AppVM: true/false
    AppVM->>Theme: Apply dark/light theme
    Theme-->>User: Render updated theme
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I nibble at dusk and nibble at dawn,
I set the hours where shadows are drawn;
A hop, a tick, a toggled light—
Time-made twilight feels just right;
Hooray for themes that follow the sun!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Added Time Based Sorting' does not accurately describe the changeset. The PR implements time-based theming (dark mode scheduling), not sorting functionality. Update the title to reflect the actual feature: 'feat: Add time-based dark mode theming' or 'feat: Implement scheduled dark mode based on time of day'.
Docstring Coverage ⚠️ Warning Docstring coverage is 2.70% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc74175 and eab2553.

📒 Files selected for processing (2)
  • core/datastore/src/commonMain/kotlin/org/mifos/core/datastore/UserPreferencesRepository.kt
  • core/datastore/src/commonMain/kotlin/org/mifos/core/datastore/UserPreferencesRepositoryImpl.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/datastore/src/commonMain/kotlin/org/mifos/core/datastore/UserPreferencesRepositoryImpl.kt
  • core/datastore/src/commonMain/kotlin/org/mifos/core/datastore/UserPreferencesRepository.kt

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@revanthkumarJ revanthkumarJ marked this pull request as ready for review December 25, 2025 07:04
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmp-android/src/main/kotlin/cmp/android/app/AppThemeExtensions.kt (1)

14-22: Incomplete implementation for time-based dark mode.

The BASED_ON_TIME case currently returns hardcoded false, which means time-based theming will always show light mode regardless of the configured time range.

The function should:

  1. Accept TimeBasedTheme parameter
  2. Call DateHelper.isDarkModeBasedOnTime(...) with the theme's time range
  3. Return the result of that calculation
🔎 Suggested fix
+import org.mifos.core.common.DateHelper
+import org.mifos.core.model.TimeBasedTheme

 fun DarkThemeConfig.isDarkMode(
     isSystemDarkMode: Boolean,
+    timeBasedTheme: TimeBasedTheme? = null,
 ): Boolean =
     when (this) {
         DarkThemeConfig.FOLLOW_SYSTEM -> isSystemDarkMode
         DarkThemeConfig.DARK -> true
         DarkThemeConfig.LIGHT -> false
-        DarkThemeConfig.BASED_ON_TIME -> false
+        DarkThemeConfig.BASED_ON_TIME -> {
+            timeBasedTheme?.let {
+                DateHelper.isDarkModeBasedOnTime(
+                    it.hourStart,
+                    it.minStart,
+                    it.hourEnd,
+                    it.minEnd
+                )
+            } ?: false
+        }
     }
🧹 Nitpick comments (7)
core/model/src/commonMain/kotlin/org/mifos/core/model/TimeBasedTheme.kt (1)

14-20: Consider adding validation or documentation for time value bounds.

The data class accepts any Int values, but hours should be 0-23 and minutes 0-59. Consider either:

  1. Adding init block validation
  2. Documenting expected ranges in KDoc

Also, property naming could be more explicit (minuteStart/minuteEnd vs minStart/minEnd).

🔎 Optional: Add validation
 @Serializable
 data class TimeBasedTheme(
     val hourStart: Int,
     val hourEnd: Int,
     val minStart: Int,
     val minEnd: Int,
-) 
+) {
+    init {
+        require(hourStart in 0..23) { "hourStart must be 0-23" }
+        require(hourEnd in 0..23) { "hourEnd must be 0-23" }
+        require(minStart in 0..59) { "minStart must be 0-59" }
+        require(minEnd in 0..59) { "minEnd must be 0-59" }
+    }
+}
feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsViewmodel.kt (1)

60-64: Missing analytics logging for time-based theme changes.

Other theme update functions (updateThemeBrand, updateDarkThemeConfig, updateDynamicColorPreference) log analytics events, but updateTimeBasedThemeConfig does not. This inconsistency may impact feature usage tracking.

🔎 Add analytics logging
     fun updateTimeBasedThemeConfig(timeBasedTheme: TimeBasedTheme) {
         viewModelScope.launch {
+            analyticsHelper.logTimeBasedThemeChanged(timeBasedTheme)
             settingsRepository.setTimeBasedThemeConfig(timeBasedTheme)
         }
     }

Add the helper function at the bottom of the file:

private fun AnalyticsHelper.logTimeBasedThemeChanged(theme: TimeBasedTheme) {
    logEvent(
        type = "time_based_theme_changed",
        params = mapOf(
            "hour_start" to theme.hourStart.toString(),
            "hour_end" to theme.hourEnd.toString(),
        ),
    )
}
feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsScreen.kt (3)

164-168: Use rememberSaveable for time picker state to survive configuration changes.

The time values use remember which will lose state on configuration changes (e.g., rotation). This could frustrate users who partially configured times.

🔎 Replace remember with rememberSaveable
-    var startHour by remember { mutableStateOf(initialTheme.hourStart) }
-    var startMinute by remember { mutableStateOf(initialTheme.minStart) }
-
-    var endHour by remember { mutableStateOf(initialTheme.hourEnd) }
-    var endMinute by remember { mutableStateOf(initialTheme.minEnd) }
+    var startHour by rememberSaveable { mutableStateOf(initialTheme.hourStart) }
+    var startMinute by rememberSaveable { mutableStateOf(initialTheme.minStart) }
+
+    var endHour by rememberSaveable { mutableStateOf(initialTheme.hourEnd) }
+    var endMinute by rememberSaveable { mutableStateOf(initialTheme.minEnd) }

277-314: Consider extracting TimePickerDialog to a shared design system component.

A similar TimePickerDialog exists in feature/home/src/commonMain/kotlin/org/mifos/feature/home/task/EditTaskScreen.kt (lines 331-355). Consider extracting to a shared component in the design system module to avoid duplication and ensure consistent behavior.


154-159: Add modifier parameter to public composable for flexibility.

TimeBasedThemeDialog is a public composable but lacks a modifier parameter, which limits caller customization.

🔎 Add modifier parameter
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun TimeBasedThemeDialog(
     initialTheme: TimeBasedTheme,
     onDismiss: () -> Unit,
     onConfirm: (TimeBasedTheme) -> Unit,
+    modifier: Modifier = Modifier,
 ) {

Then pass it to the AlertDialog.

feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsDialog.kt (1)

222-243: Extract complex string formatting to improve readability.

The string concatenation for the time-based theme option is complex and hard to maintain. Consider extracting to a helper function.

🔎 Extract to helper function
@Composable
private fun formatTimeBasedThemeLabel(theme: TimeBasedTheme): String {
    val basedOnTime = stringResource(Res.string.feature_settings_dark_mode_based_on_time)
    val darkLabel = stringResource(Res.string.feature_settings_dark_mode_label)
    val lightLabel = stringResource(Res.string.feature_settings_light_mode_label)
    
    val darkRange = DateHelper.formatTimeRange(
        theme.hourStart, theme.minStart,
        theme.hourEnd, theme.minEnd
    )
    val lightRange = DateHelper.formatTimeRange(
        theme.hourEnd, theme.minEnd,
        theme.hourStart, theme.minStart
    )
    
    return "$basedOnTime\n$darkLabel [$darkRange]\n$lightLabel [$lightRange]"
}

Then use:

SettingsDialogThemeChooserRow(
    text = formatTimeBasedThemeLabel(settings.timeBasedTheme),
    selected = settings.darkThemeConfig == DarkThemeConfig.BASED_ON_TIME,
    onClick = { onChangeDarkThemeConfig(DarkThemeConfig.BASED_ON_TIME) },
)
cmp-navigation/src/commonMain/kotlin/cmp/navigation/AppViewModel.kt (1)

101-116: Theme won't auto-update when time passes the threshold while app is open.

The time-based theme is only evaluated when ThemeUpdate action is dispatched (e.g., on settings change or app launch). If the user has the app open when the time threshold is crossed, the theme won't change until they navigate to settings.

Consider adding a periodic check or time-based trigger to re-evaluate the theme.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f0b88f and dc74175.

📒 Files selected for processing (16)
  • cmp-android/dependencies/prodReleaseRuntimeClasspath.tree.txt
  • cmp-android/src/main/kotlin/cmp/android/app/AppThemeExtensions.kt
  • cmp-navigation/src/commonMain/kotlin/cmp/navigation/AppViewModel.kt
  • core/common/src/commonMain/kotlin/org/mifos/core/common/DateHelper.kt
  • core/data/src/commonMain/kotlin/org/mifos/core/data/repository/UserDataRepository.kt
  • core/data/src/commonMain/kotlin/org/mifos/core/data/repositoryImpl/UserDataRepositoryImpl.kt
  • core/datastore/src/commonMain/kotlin/org/mifos/core/datastore/UserPreferencesRepository.kt
  • core/datastore/src/commonMain/kotlin/org/mifos/core/datastore/UserPreferencesRepositoryImpl.kt
  • core/model/src/commonMain/kotlin/org/mifos/core/model/DarkThemeConfig.kt
  • core/model/src/commonMain/kotlin/org/mifos/core/model/TimeBasedTheme.kt
  • core/model/src/commonMain/kotlin/org/mifos/core/model/UserData.kt
  • feature/settings/build.gradle.kts
  • feature/settings/src/commonMain/composeResources/values/strings.xml
  • feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsDialog.kt
  • feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsScreen.kt
  • feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsViewmodel.kt
🧰 Additional context used
🧬 Code graph analysis (3)
cmp-navigation/src/commonMain/kotlin/cmp/navigation/AppViewModel.kt (1)
core-base/ui/src/commonMain/kotlin/template/core/base/ui/BaseViewModel.kt (1)
  • trySendAction (83-85)
feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsDialog.kt (5)
feature/settings/src/desktopMain/kotlin/org/mifos/feature/settings/Platform.desktop.kt (1)
  • supportsDynamicTheming (13-13)
feature/settings/src/jsMain/kotlin/org/mifos/feature/settings/Platform.js.kt (1)
  • supportsDynamicTheming (13-13)
feature/settings/src/wasmJsMain/kotlin/org/mifos/feature/settings/Platform.wasmJs.kt (1)
  • supportsDynamicTheming (13-13)
feature/settings/src/nativeMain/kotlin/org/mifos/feature/settings/Platform.native.kt (1)
  • supportsDynamicTheming (13-13)
feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsScreen.kt (1)
  • TimeBasedThemeDialog (154-244)
feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsScreen.kt (1)
feature/home/src/commonMain/kotlin/org/mifos/feature/home/task/EditTaskScreen.kt (1)
  • TimePickerDialog (332-356)
⏰ 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: PR Checks / Static Analysis Check
🔇 Additional comments (11)
feature/settings/build.gradle.kts (1)

22-22: LGTM - Dependency addition aligns with time-based theming.

The addition of core.common dependency is necessary to access DateHelper utilities for time-based theme calculations.

cmp-android/dependencies/prodReleaseRuntimeClasspath.tree.txt (1)

2289-2289: Dependency tree correctly reflects core:common addition.

This generated dependency tree correctly shows the new core:common module in the runtime classpath, aligning with the build configuration changes.

core/model/src/commonMain/kotlin/org/mifos/core/model/DarkThemeConfig.kt (1)

16-16: LGTM - Enum value addition is well-formed.

The new BASED_ON_TIME enum constant follows the existing pattern and will be correctly handled by the fromString companion function.

feature/settings/src/commonMain/composeResources/values/strings.xml (1)

34-43: LGTM - String resources support new time-based theme UI.

The added string resources follow the existing naming conventions and provide necessary UI text for the time-based dark mode feature.

core/common/src/commonMain/kotlin/org/mifos/core/common/DateHelper.kt (2)

20-41: LGTM - Time-based dark mode logic is correct.

The function correctly handles both same-day ranges (e.g., 06:00 → 18:00) and cross-midnight ranges (e.g., 18:00 → 06:00). The cross-midnight logic using !in endMinutes..<startMinutes appropriately inverts the range to capture times spanning midnight.


43-59: LGTM - Time formatting functions are correct.

The formatTimeRange and format functions correctly handle 12-hour time formatting with AM/PM notation and proper handling of midnight/noon edge cases.

core/data/src/commonMain/kotlin/org/mifos/core/data/repositoryImpl/UserDataRepositoryImpl.kt (1)

40-41: LGTM - Repository implementation follows existing patterns.

The new observeTimeBasedThemeConfig and setTimeBasedThemeConfig implementations correctly delegate to the underlying preferences repository, consistent with other configuration properties in this class.

Also applies to: 56-57

core/data/src/commonMain/kotlin/org/mifos/core/data/repository/UserDataRepository.kt (1)

39-39: LGTM - Interface additions follow existing patterns.

The new observeTimeBasedThemeConfig and setTimeBasedThemeConfig interface methods are consistent with the existing API design for other configuration properties.

Also applies to: 51-51

core/model/src/commonMain/kotlin/org/mifos/core/model/UserData.kt (1)

29-29: LGTM!

The timeBasedTheme property is properly added to UserData with sensible default values (dark mode from 18:00 to 06:00). The structure integrates well with the existing data class.

Note: The enableScreenCapture default changed from false to true. Verify this is intentional as it affects the default security posture.

Also applies to: 45-51

feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsDialog.kt (1)

64-78: LGTM!

The SettingsDialog correctly wires the viewmodel to handle time-based theme updates. The separation of concerns between the overloaded composables is well-structured.

cmp-navigation/src/commonMain/kotlin/cmp/navigation/AppViewModel.kt (1)

130-136: LGTM!

The TimeBasedThemeUpdate action and handler are correctly implemented, properly updating state flow when time-based theme configuration changes.

Also applies to: 181-183

@niyajali niyajali marked this pull request as draft December 25, 2025 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants