Skip to content

Add dark mode display settings and settings access from login#256

Open
AndrewCheung360 wants to merge 4 commits intomainfrom
andrew/dark-mode-display-settings
Open

Add dark mode display settings and settings access from login#256
AndrewCheung360 wants to merge 4 commits intomainfrom
andrew/dark-mode-display-settings

Conversation

@AndrewCheung360
Copy link
Copy Markdown
Member

@AndrewCheung360 AndrewCheung360 commented Apr 28, 2026

Overview

Adds a Display settings option so users can choose Light, Dark, or Device Theme for the app's appearance. Also adds a settings gear icon to the login page so unauthenticated users can reach Settings without logging in first. Added spacing in upcoming menus between filter row and content.

Changes Made

New file — DisplayBottomSheet.kt

  • Modal bottom sheet with three radio-button options: Light (sun icon), Dark (moon icon), Device Theme (gear icon)
  • Local selection state committed only when the user taps "Done"
  • Fully themed via currentColors and EateryBlueTypography; supports light and dark preview via @DualModePreview

SettingsScreen.kt

  • Injects ThemeViewModel to collect isDarkMode and isLoggedIn state
  • New "Display" row (sun icon, "Choose a light or dark theme") inserted between Notifications and Privacy; opens DisplayBottomSheet
  • Settings list wrapped in a scrollable inner Column so all items remain accessible on smaller screens
  • Logout button now pinned at the bottom and conditionally hidden when the user is not logged in

ThemeViewModel.kt

  • Exposes isLoggedIn: StateFlow<Boolean> from UserPreferencesRepository.isLoggedInFlow

LoginPage.kt

  • Adds onSettingsClicked parameter (default no-op for backward compatibility)
  • Settings gear icon (system_setting drawable) added to the top-right of the nav row via Arrangement.SpaceBetween

ProfileScreen.kt

  • Passes onSettingsClicked through to LoginPage so navigation wires up correctly

UpcomingMenusScreen.kt

  • Adds spacer between filter row and content

strings.xml

  • Added settings_display_title, settings_display_description, settings_display_light, settings_display_dark, settings_display_system

Test Coverage

  • TODO: Manual test — tap Display → sheet opens; select each option → theme updates; tap Done → sheet dismisses; kill/relaunch → preference persists via DataStore
  • TODO: Manual test — toggle system dark mode with Device Theme selected → app follows system setting
  • TODO: Manual test — log out → logout button disappears from Settings; navigate to Profile tab → gear icon visible on login page; tap → Settings screen opens

Next Steps (optional)

TODO

Related PRs or Issues (optional)

Screenshots (optional)

Summary by CodeRabbit

  • New Features

    • Added a settings button on the login page.
    • New Display theme selector (Light / Dark / System) via a bottom sheet in Settings.
    • Theme preference model and app-wide theme setting support.
  • Improvements

    • Settings screen wired to show/hide logout based on login state and open the Display sheet.
    • Profile screen routes settings clicks into the app.
  • Other

    • Added user-facing strings and minor layout spacing tweaks.

…ogin

- Add DisplayBottomSheet with Light / Dark / Device Theme radio options
- Add Display row to SettingsScreen wired to ThemeViewModel
- Expose isLoggedIn from ThemeViewModel; hide logout button when not logged in
- Make settings list scrollable to prevent logout button from squishing
- Add settings icon to LoginPage header so unauthenticated users can access settings
- Add settings_display_* string resources

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db5171d2-70b6-4f8b-a57b-66e20a059cc5

📥 Commits

Reviewing files that changed from the base of the PR and between 48db39f and 9ac7644.

📒 Files selected for processing (8)
  • app/src/main/java/com/cornellappdev/android/eatery/data/models/ThemePreference.kt
  • app/src/main/java/com/cornellappdev/android/eatery/data/repositories/UserPreferencesRepository.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/components/settings/DisplayBottomSheet.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/screens/SettingsScreen.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/screens/UpcomingMenuScreen.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/theme/Theme.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/viewmodels/SettingsViewModel.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/viewmodels/ThemeViewModel.kt
✅ Files skipped from review due to trivial changes (2)
  • app/src/main/java/com/cornellappdev/android/eatery/ui/screens/UpcomingMenuScreen.kt
  • app/src/main/java/com/cornellappdev/android/eatery/data/models/ThemePreference.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/com/cornellappdev/android/eatery/ui/components/settings/DisplayBottomSheet.kt

📝 Walkthrough

Walkthrough

Adds a theme selection flow (light/dark/system) and wiring: new ThemePreference model and flows, ThemeViewModel changes, DisplayBottomSheet UI, SettingsScreen integration, LoginPage settings button, and related string resources and repo mapping.

Changes

Cohort / File(s) Summary
Login & Profile wiring
app/src/main/java/.../login/LoginPage.kt, app/src/main/java/.../ProfileScreen.kt
LoginPage gains onSettingsClicked: () -> Unit = {} and a settings IconButton; ProfileScreenContent now forwards onSettingsClicked into LoginPage.
Display selection UI
app/src/main/java/.../settings/DisplayBottomSheet.kt, app/src/main/res/values/strings.xml
New DisplayBottomSheet composable with radio rows for LIGHT/DARK/SYSTEM and Done button; added display-related string resources.
Settings screen integration
app/src/main/java/.../screens/SettingsScreen.kt
SettingsScreen now accepts/injects ThemeViewModel, shows a "Display" option that opens DisplayBottomSheet, conditionally shows logout only when logged in, and forwards theme selection callbacks.
Theme state & model
app/src/main/java/.../viewmodels/ThemeViewModel.kt, app/src/main/java/.../data/models/ThemePreference.kt
Introduces ThemePreference enum; ThemeViewModel replaces nullable isDarkMode with themePreference: StateFlow<ThemePreference> and exposes explicit toggle methods.
Preferences repository mapping
app/src/main/java/.../data/repositories/UserPreferencesRepository.kt
Adds themePreferenceFlow that maps persisted isDarkMode to ThemePreference (SYSTEM when absent).
Theme resolution & minor UI tweak
app/src/main/java/.../ui/theme/Theme.kt, app/src/main/java/.../screens/UpcomingMenuScreen.kt
rememberResolvedDarkMode now maps ThemePreference to resolved dark boolean; added a vertical spacer in upcoming menu layout.
Settings viewmodel login state
app/src/main/java/.../viewmodels/SettingsViewModel.kt
SettingsViewModel now depends on UserPreferencesRepository and exposes isLoggedIn: StateFlow<Boolean>.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant SettingsScreen as SettingsScreen
    participant DisplayBottomSheet as DisplayBottomSheet
    participant ThemeViewModel as ThemeViewModel
    participant Repository as UserPreferencesRepository

    User->>SettingsScreen: Tap "Display" option
    SettingsScreen->>SettingsScreen: showDisplaySheet = true
    SettingsScreen->>DisplayBottomSheet: open(themePreference)
    User->>DisplayBottomSheet: Selects Light/Dark/System
    DisplayBottomSheet->>DisplayBottomSheet: update selected state
    User->>DisplayBottomSheet: Tap Done
    DisplayBottomSheet->>ThemeViewModel: call onLight/onDark/onSystem
    ThemeViewModel->>Repository: update persisted preference
    DisplayBottomSheet->>SettingsScreen: onDismiss
    SettingsScreen->>SettingsScreen: showDisplaySheet = false
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

🐇🌤️ I hopped into Settings with a twitchy nose,
Three modes to pick from in tidy little rows.
A button appeared where headers once sat,
Now light, dark, or system — choose this or that!
Hooray for themes, I hop, clap, and pose.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add dark mode display settings and settings access from login' accurately summarizes the main changes: introducing display settings and login page settings access.
Description check ✅ Passed The description covers the Overview, Changes Made, and Test Coverage sections as per the template, though Test Coverage items are marked TODO rather than completed.
Linked Issues check ✅ Passed All coding requirements from issue #253 are met: light/dark/system theme selection via DisplayBottomSheet, theme state management via ThemeViewModel and UserPreferencesRepository, persistence via DataStore flow, and settings access from login page.
Out of Scope Changes check ✅ Passed All changes directly support the linked issue objectives. Minor unrelated additions (UpcomingMenusScreen spacer, isLoggedIn state, logout button reorganization) are reasonable supporting enhancements with clear UX benefits.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch andrew/dark-mode-display-settings

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.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/cornellappdev/android/eatery/ui/screens/SettingsScreen.kt`:
- Around line 365-367: The Logout icon currently uses
Icons.AutoMirrored.Filled.Logout.name as its contentDescription which exposes
non-localized, noisy text to accessibility services; update the Icon usage
associated with the logout action (the Icon instantiation referencing
Icons.AutoMirrored.Filled.Logout and contentDescription) to use
contentDescription = null (or a localized stringResource if you intend a spoken
label), so TalkBack will not read the redundant icon label next to the visible
"Log out" text.
- Line 32: Replace the direct Flow collection call using collectAsState() in
SettingsScreen (where the ViewModel/state flows are converted to Compose state)
with the lifecycle-aware collectAsStateWithLifecycle() to match the module
pattern; update the usages that reference the ViewModel's flows (e.g.,
settingsViewModel.someStateFlow -> collectAsStateWithLifecycle()) so the
composable observes state with the lifecycle-aware API (ensure you import
collectAsStateWithLifecycle and adjust any nullable/default parameters
accordingly).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1a56e8de-539d-4522-b11a-0a357519eeb0

📥 Commits

Reviewing files that changed from the base of the PR and between 2be3fc6 and 48db39f.

📒 Files selected for processing (6)
  • app/src/main/java/com/cornellappdev/android/eatery/ui/components/login/LoginPage.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/components/settings/DisplayBottomSheet.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/screens/ProfileScreen.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/screens/SettingsScreen.kt
  • app/src/main/java/com/cornellappdev/android/eatery/ui/viewmodels/ThemeViewModel.kt
  • app/src/main/res/values/strings.xml

Comment thread app/src/main/java/com/cornellappdev/android/eatery/ui/screens/SettingsScreen.kt Outdated
- Use collectAsStateWithLifecycle() instead of collectAsState() for lifecycle-aware state collection
- Set logout icon contentDescription to null to avoid TalkBack reading redundant icon label alongside visible "Log out" text

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@caleb-bit caleb-bit left a comment

Choose a reason for hiding this comment

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

I think UI looks good, but we should probably review the way that we're handling how the color scheme state is being represented (currently a Boolean?).

initialValue = null
)

val isLoggedIn: StateFlow<Boolean> = repository.isLoggedInFlow.stateIn(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does this state belong here? Why not have this in SettingsViewModel?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

good point, should only be used for determining whether the logout button should appear in settings

private val repository: UserPreferencesRepository): ViewModel()
{
val isDarkMode : StateFlow<Boolean?> = repository.isDarkModeFlow.stateIn(
val isDarkMode: StateFlow<Boolean?> = repository.isDarkModeFlow.stateIn(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it would be clearer semantically to deal with enums rather than nullable booleans. Keeping optional bool as the way the field is stored in protobufs, maybe UserPreferencesRepository should expose the state as an enum instead of handling that down in the UI in DisplayBottomSheet.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

makes sense

<string name="settings_display_description">Choose a light or dark theme</string>
<string name="settings_display_light">Light</string>
<string name="settings_display_dark">Dark</string>
<string name="settings_display_system">Device Theme</string>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: Maybe just Device for consistency. Figma doesn't seem to specify, so it shouldn't matter too much. How does it look on iOS?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think it's the same on iOS, but we can change.

<string name="settings_notifications_title">Notifications</string>
<string name="settings_notifications_description">Manage item and promotional notifications</string>
<string name="settings_display_title">Display</string>
<string name="settings_display_description">Choose a light or dark theme</string>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe "Choose color scheme"? The wording seems a little awkward here. Is it the same on iOS?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think it's the same on iOS, but we can change.

…ingsViewModel

- Add ThemePreference enum (LIGHT/DARK/SYSTEM) to data/models
- Expose themePreferenceFlow from UserPreferencesRepository instead of nullable Boolean
- Replace isDarkMode: StateFlow<Boolean?> with themePreference: StateFlow<ThemePreference> in ThemeViewModel; drop isLoggedIn
- Add isLoggedIn: StateFlow<Boolean> to SettingsViewModel (injecting UserPreferencesRepository)
- Update rememberResolvedDarkMode in Theme.kt to switch on ThemePreference enum
- Update DisplayBottomSheet to accept ThemePreference param directly, removing private DisplayTheme enum
- Update SettingsScreen to use ThemePreference and collect isLoggedIn from settingsViewModel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No light/dark mode toggle

2 participants