Skip to content

Customizable nav bar, artwork toggles, and track-menu items (Tide-style UX) - #22

Open
KEZO555 wants to merge 4 commits into
jonathancaudill:feature/tidalfrom
KEZO555:feature/navbar-and-artwork
Open

Customizable nav bar, artwork toggles, and track-menu items (Tide-style UX)#22
KEZO555 wants to merge 4 commits into
jonathancaudill:feature/tidalfrom
KEZO555:feature/navbar-and-artwork

Conversation

@KEZO555

@KEZO555 KEZO555 commented Jul 26, 2026

Copy link
Copy Markdown

Three small, self-contained UI additions, plus follow-up fixes from on-device testing on the Light Phone III. All backend-agnostic (they apply to both Spotify and TIDAL).

1. Customizable navigation bar

Show/hide and reorder the bottom tabs, edited inline in Settings, persisted via a new NavBarPreferences (same SharedPreferences shape as ThemePreferences, republished as a process-wide StateFlow). PhonoTabBar is fed the persisted/filtered/ordered list; the selected tab re-homes if it becomes hidden. Settings stays pinned so you can't hide your way out. PhonoTab/PhonoTabBar/PhonoShellViewModel are untouched.

2. Artwork show/hide toggles

A new "Artwork" settings section with two toggles, backed by ArtworkPreferences:

  • List thumbnails — cover art in the Albums, Liked Songs and Playlists rows, gated by the preference inside PhonoMediaListItem. Rows pass their real art_url, and covers are decoded down to the ~50dp thumbnail slot so scrolling stays smooth.
  • Now playing artwork — the album cover on the now-playing screen (from the existing PlaybackUiState.artUrl), which previously showed none. Sized compactly so the transport controls stay on-screen on the LP3.

3. Track long-press menu items

Adds Add To Queue, Go To Album, and Go To Artist to the existing long-press track context menu. Each resolves what it needs from the track uri at action time via PlaybackController.trackMetadataForUri (which returns albumId + artistIds), so no per-screen call sites change and the items work uniformly across every track list. Navigation reuses the same one-shot ContextMenuUiState pattern already used for the playlist picker (new navigateToAlbumId/navigateToArtistId, consumed in ContextMenuHost, routed to the album/artist overlays in PhonoShell). The long-press now also fires a LongPress haptic for tactile feedback.

Performance

  • buildLibraryDateIndex no longer runs an allocating, exception-guarded Instant.parse per item on the main thread during composition; it parses the leading yyyy-MM of the ISO timestamp by substring instead. Removes the jank when switching to the Albums / Liked Songs tabs on-device.

Notes

  • Defaults preserve current behavior: all tabs shown, and both artwork toggles on.

Summary by CodeRabbit

  • New Features

    • Customize the bottom navigation bar by enabling, disabling, and reordering tabs.
    • Control artwork visibility for list thumbnails and the now-playing screen.
    • Track menus now support adding tracks to the queue and opening their album or artist.
    • Album, playlist, and liked-song lists can display artwork thumbnails.
    • Long-press actions now provide haptic feedback.
  • Bug Fixes

    • Improved date handling for supported library entries.
    • Navigation now selects an available tab when the current tab is hidden.

KEZO555 and others added 3 commits July 26, 2026 13:16
Let users choose which bottom-bar tabs appear and in what order, edited
inline from Settings and persisted across launches. Settings stays pinned
so you can't hide your way out of the app. The tabs are shared UI, so this
applies to both the Spotify and TIDAL backends.

- NavBarPreferences: persists tab order + visibility in plain
  SharedPreferences (phono_navbar), same shape as ThemePreferences, and
  publishes the order as a process-wide StateFlow so the shell and the
  Settings editor share one source of truth.
- PhonoShell: feeds PhonoTabBar the persisted, filtered, ordered list via
  NavBarPreferences.visibleTabs(...), and re-homes the selected tab if it
  becomes hidden.
- SettingsScreen: inline "Navigation bar" editor (toggle + up/down reorder),
  matching the existing inline-options pattern.

Existing installs default to today's exact bar. Downloads gating is
preserved (never shown on builds that don't support it). UI-only: no Room
migration, no Rust/engine/auth changes.

Co-Authored-By: Claude <noreply@anthropic.com>
Two UI-only, backend-agnostic settings under a new "Artwork" section:

- "List thumbnails" hides the cover thumbnails in track/album/playlist
  rows. Gated inside PhonoMediaListItem, so it applies everywhere at once
  while still honoring callers that explicitly pass showImage = false.
- "Now playing artwork" shows the album cover on the now-playing screen
  (from the existing PlaybackUiState.artUrl), which previously had no art.

Backed by ArtworkPreferences — plain SharedPreferences like ThemePreferences,
republished as process-wide StateFlows so lists and now-playing react live to
changes in Settings. Defaults to on, so current behavior is unchanged (except
now-playing, which gains art). No Rust/engine/auth changes.

Co-Authored-By: Claude <noreply@anthropic.com>
Extends the existing track long-press menu with three items from Tide.
All three resolve what they need from the track uri at action time via
PlaybackController.trackMetadataForUri (which returns albumId + artistIds),
so no per-screen call sites change and the items work uniformly across
every track list, for both Spotify and TIDAL:

- Add To Queue -> resolves metadata, then addTrackToQueue.
- Go To Album / Go To Artist -> resolve the id, then navigate via the same
  one-shot ContextMenuUiState pattern already used for the playlist picker
  (new navigateToAlbumId / navigateToArtistId, consumed in ContextMenuHost
  and routed to the album/artist overlays in PhonoShell).

No engine/auth changes.

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The application now persists configurable navigation and artwork preferences, applies those settings across navigation and media displays, adds track context-menu actions for queueing and album/artist navigation, provides long-press haptics, and optimizes library date parsing.

Changes

UI navigation and media preferences

Layer / File(s) Summary
Persisted navigation and artwork preferences
app/src/main/java/com/lightphone/spotify/ui/navigation/NavBarPreferences.kt, app/src/main/java/com/lightphone/spotify/ui/light/ArtworkPreferences.kt, app/src/main/java/com/lightphone/spotify/ui/screens/SettingsScreen.kt, app/src/main/java/com/lightphone/spotify/App.kt
Navigation-tab ordering and artwork visibility are persisted, exposed as state flows, edited in SettingsScreen, and initialized during application startup.
Navigation and artwork consumption
app/src/main/java/com/lightphone/spotify/ui/navigation/PhonoShell.kt, app/src/main/java/com/lightphone/spotify/ui/components/PhonoComponents.kt, app/src/main/java/com/lightphone/spotify/ui/screens/{AlbumsScreen,LikedSongsScreen,PlaylistsScreen,PlayingScreen}.kt
Visible tabs respond to saved ordering, list thumbnails respond to the artwork preference, and album, track, playlist, and now-playing artwork sources are rendered conditionally.

Track context-menu actions

Layer / File(s) Summary
Track actions and navigation callbacks
app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt, app/src/main/java/com/lightphone/spotify/ui/components/ContextMenuHost.kt, app/src/main/java/com/lightphone/spotify/ui/navigation/PhonoShell.kt
Track menus add queue, album, and artist actions; resolved navigation targets are consumed by ContextMenuHost and routed to overlay destinations.

Supporting UI behavior

Layer / File(s) Summary
Interaction feedback and date parsing
app/src/main/java/com/lightphone/spotify/ui/components/PhonoComponents.kt, app/src/main/java/com/lightphone/spotify/ui/components/LibraryDateIndex.kt
Long presses trigger haptic feedback, and ISO year-month timestamps use a validated fast path before the existing fallback parser.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AppViewModel
  participant ContextMenuHost
  participant PhonoShell
  User->>AppViewModel: choose album or artist action
  AppViewModel->>AppViewModel: resolve track metadata
  AppViewModel-->>ContextMenuHost: publish navigation target
  ContextMenuHost->>PhonoShell: invoke navigation callback
  PhonoShell->>PhonoShell: open album or artist overlay
Loading

Possibly related PRs

Suggested reviewers: jonathancaudill

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.69% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main additions: customizable navigation, artwork preferences, and new track menu actions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with 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.

❤️ Share

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

- List thumbnails: Albums, Liked Songs and Playlists rows now pass the
  real cover art_url (they hard-coded showImage=false before, so the
  List thumbnails toggle could never show anything). Cover art is now
  downsampled to the ~50dp thumbnail slot so scrolling stays smooth.
- Now-playing: shrink the optional cover from 70% to 40% width so the
  play/skip transport controls always stay on screen on the LP3.
- Performance: replace the per-item Instant.parse in buildLibraryDateIndex
  with a cheap yyyy-MM substring parse, removing the main-thread jank when
  switching to the Albums / Liked Songs tabs.
- Long-press menu: add a LongPress haptic to tapWithLongPress so the
  context menu long-press has tactile feedback like Tide.
@jonathancaudill

Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt`:
- Around line 2104-2133: Update onContextMenuAction and the context-menu state
flow to capture a context/session generation before dismissing the menu, pass it
into each asynchronous metadata lookup, and verify it still matches before
applying navigation or queue side effects. Increment or replace the generation
when dismissContextMenu or resetSessionUiState clears the context, and cancel
any tracked context-menu jobs from the session reset path so stale actions
cannot complete.

In `@app/src/main/java/com/lightphone/spotify/ui/components/LibraryDateIndex.kt`:
- Around line 66-70: Update the fast-path parsing in the date-index function
containing the iso prefix check so it only handles fully validated dates whose
UTC grouping matches the existing Instant.parse normalization. Route
offset-bearing timestamps, malformed dates, and inputs that could shift across a
month boundary through the existing UTC fallback instead; add regression
coverage for the offset example and invalid-date cases.

In `@app/src/main/java/com/lightphone/spotify/ui/screens/SettingsScreen.kt`:
- Around line 220-254: Update NavBarOptions to accept the downloads capability
and skip the Downloads entry when downloads are unsupported, matching
PhonoShell’s visibleTabs behavior. Thread the existing caps.downloads value from
SettingsScreen into NavBarOptions, and filter or omit the unsupported route
before rendering and reordering so users cannot toggle an unavailable tab.
🪄 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 Plus

Run ID: a09cab3c-1ce1-42c0-aa3e-fcb870c41760

📥 Commits

Reviewing files that changed from the base of the PR and between bf222e6 and 8b01571.

📒 Files selected for processing (13)
  • app/src/main/java/com/lightphone/spotify/App.kt
  • app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt
  • app/src/main/java/com/lightphone/spotify/ui/components/ContextMenuHost.kt
  • app/src/main/java/com/lightphone/spotify/ui/components/LibraryDateIndex.kt
  • app/src/main/java/com/lightphone/spotify/ui/components/PhonoComponents.kt
  • app/src/main/java/com/lightphone/spotify/ui/light/ArtworkPreferences.kt
  • app/src/main/java/com/lightphone/spotify/ui/navigation/NavBarPreferences.kt
  • app/src/main/java/com/lightphone/spotify/ui/navigation/PhonoShell.kt
  • app/src/main/java/com/lightphone/spotify/ui/screens/AlbumsScreen.kt
  • app/src/main/java/com/lightphone/spotify/ui/screens/LikedSongsScreen.kt
  • app/src/main/java/com/lightphone/spotify/ui/screens/PlayingScreen.kt
  • app/src/main/java/com/lightphone/spotify/ui/screens/PlaylistsScreen.kt
  • app/src/main/java/com/lightphone/spotify/ui/screens/SettingsScreen.kt

Comment on lines +2104 to +2133
ContextMenuAction.AddToQueue -> {
if (target !is ContextMenuTarget.Track) return
dismissContextMenu()
viewModelScope.launch {
val meta = controller.trackMetadataForUri(target.uri) ?: return@launch
addTrackToQueue(meta)
}
}
ContextMenuAction.AddToPlaylists -> {
if (target !is ContextMenuTarget.Track) return
dismissContextMenu()
_contextMenu.update { it.copy(navigateToPlaylistPickerUri = target.uri) }
}
ContextMenuAction.GoToAlbum -> {
if (target !is ContextMenuTarget.Track) return
dismissContextMenu()
viewModelScope.launch {
val albumId = controller.trackMetadataForUri(target.uri)?.albumId ?: return@launch
_contextMenu.update { it.copy(navigateToAlbumId = albumId) }
}
}
ContextMenuAction.GoToArtist -> {
if (target !is ContextMenuTarget.Track) return
dismissContextMenu()
viewModelScope.launch {
val artistId = controller.trackMetadataForUri(target.uri)
?.artistIds?.firstOrNull() ?: return@launch
_contextMenu.update { it.copy(navigateToArtistId = artistId) }
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the file and inspect the relevant section plus surrounding context.
if [ -f app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt ]; then
  wc -l app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt
  sed -n '2060,2155p' app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt | nl -ba -v2060
else
  echo "File not found"
  fd -a AppViewModel.kt .
fi

Repository: jonathancaudill/phono

Length of output: 264


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate relevant symbols: dismissContextMenu, contextMenu state, session/reset/job cancellation, contextMenu actions.
rg -n "dismissContextMenu|_contextMenu|contextMenu|navigateToPlaylistPickerUri|navigateToAlbumId|navigateToArtistId|addTrackToQueue|onSessionReset|cancelJobs|cancel.*job|CoroutineScope|addTrackToQueue|tracksMetadata|trackMetadataForUri|currentGeneration|sessionGeneration" app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt app/src/main/java/com/lightphone/spotify 2>/dev/null | head -n 200

Repository: jonathancaudill/phono

Length of output: 24278


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the UI actions handler and reset logic around the reported menu actions.
sed -n '85,520p' app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt | sed -n '1,220p'
printf '\n--- contextMenu action handler ---\n'
sed -n '2090,2160p' app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt

Repository: jonathancaudill/phono

Length of output: 11671


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- session reset and cancellation helpers ---'
sed -n '450,660p' app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt

printf '\n%s\n' '--- current session generation guards in AppViewModel ---'
python3 - <<'PY'
from pathlib import Path
p = Path('app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt')
lines = p.read_text().splitlines()
for i,l in enumerate(lines, 1):
    if 'sessionGeneration' in l or 'viewModelScope.launch' in l or 'tryCancel' in l or 'jobs' in l or 'jobCollection' in l or 'cancelChildren' in l or 'cancel' in l:
        if 200 <= i <= 2160 or 440 <= i <= 650:
            print(f'{i}: {l}')
PY

Repository: jonathancaudill/phono

Length of output: 14794


Guard asynchronous context menu actions against stale targets.

onContextMenuAction(...) captures _contextMenu.value.target and launch async metadata lookups that still run after dismissContextMenu() or after resetSessionUiState() clears the UI. Capture a context/session generation at action start, include it in each launch, reject the side effect when it mismatches, and cancel context menu jobs from the session reset path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/com/lightphone/spotify/ui/AppViewModel.kt` around lines
2104 - 2133, Update onContextMenuAction and the context-menu state flow to
capture a context/session generation before dismissing the menu, pass it into
each asynchronous metadata lookup, and verify it still matches before applying
navigation or queue side effects. Increment or replace the generation when
dismissContextMenu or resetSessionUiState clears the context, and cancel any
tracked context-menu jobs from the session reset path so stale actions cannot
complete.

Comment on lines +66 to +70
if (iso.length >= 10 && iso[4] == '-' && iso[7] == '-') {
val year = iso.substring(0, 4).toIntOrNull()
val month = iso.substring(5, 7).toIntOrNull()
if (year != null && month != null && month in 1..12) {
return YearMonth.of(year, month)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve full date validation and UTC semantics in the fast path.

Lines [66-70] accept any yyyy-MM-shaped prefix, including invalid dates, and bypass UTC normalization. For example, 2023-05-01T00:30:00+02:00 previously grouped as April after conversion to UTC, but now returns May. Restrict the optimization to fully validated UTC timestamps, or retain the Instant.parse fallback for offset formats and malformed dates; add regression tests for both cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/com/lightphone/spotify/ui/components/LibraryDateIndex.kt`
around lines 66 - 70, Update the fast-path parsing in the date-index function
containing the iso prefix check so it only handles fully validated dates whose
UTC grouping matches the existing Instant.parse normalization. Route
offset-bearing timestamps, malformed dates, and inputs that could shift across a
month boundary through the existing UTC fallback instead; add regression
coverage for the offset example and invalid-date cases.

Comment on lines +220 to +254
@Composable
private fun NavBarOptions() {
val context = LocalContext.current
val prefs = remember(context) { NavBarPreferences(context) }
val order by NavBarPreferences.order.collectAsState()
order.forEachIndexed { i, pref ->
val tab = PhonoTab.entries.firstOrNull { it.route == pref.route }
?: return@forEachIndexed
val locked = pref.route in NavBarPreferences.LOCKED
NavBarEditorRow(
label = tab.label,
enabled = pref.enabled,
locked = locked,
canMoveUp = i > 0,
canMoveDown = i < order.lastIndex,
onToggle = {
if (!locked) {
prefs.setOrder(
order.map {
if (it.route == pref.route) it.copy(enabled = !it.enabled) else it
},
)
}
},
onMove = { delta ->
val to = i + delta
if (to in order.indices) {
val reordered = order.toMutableList()
reordered.add(to, reordered.removeAt(i))
prefs.setOrder(reordered)
}
},
)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Nav-bar editor exposes "Downloads" toggle even when the build/backend doesn't support downloads.

order always includes the Downloads route because NavBarPreferences.DEFAULT is built with includeDownloads = true. NavBarOptions() renders every entry unconditionally, but PhonoShell computes tabs via NavBarPreferences.visibleTabs(phonoTabs(includeDownloads = vm.downloadsSupported)), which silently drops Downloads for unsupported builds. Users on such builds/backends can see and toggle a "Downloads" nav entry that never actually appears — a confusing dead control. SettingsScreen already has caps.downloads in scope a few lines below (used for "Download quality"), so it can be threaded through here.

🐛 Proposed fix to filter unsupported tabs from the editor
-                SectionLabel("Navigation bar")
-                NavBarOptions()
+                SectionLabel("Navigation bar")
+                NavBarOptions(downloadsSupported = caps.downloads)
 `@Composable`
-private fun NavBarOptions() {
+private fun NavBarOptions(downloadsSupported: Boolean) {
     val context = LocalContext.current
     val prefs = remember(context) { NavBarPreferences(context) }
     val order by NavBarPreferences.order.collectAsState()
     order.forEachIndexed { i, pref ->
+        if (pref.route == PhonoTab.Downloads.route && !downloadsSupported) return@forEachIndexed
         val tab = PhonoTab.entries.firstOrNull { it.route == pref.route }
             ?: return@forEachIndexed
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Composable
private fun NavBarOptions() {
val context = LocalContext.current
val prefs = remember(context) { NavBarPreferences(context) }
val order by NavBarPreferences.order.collectAsState()
order.forEachIndexed { i, pref ->
val tab = PhonoTab.entries.firstOrNull { it.route == pref.route }
?: return@forEachIndexed
val locked = pref.route in NavBarPreferences.LOCKED
NavBarEditorRow(
label = tab.label,
enabled = pref.enabled,
locked = locked,
canMoveUp = i > 0,
canMoveDown = i < order.lastIndex,
onToggle = {
if (!locked) {
prefs.setOrder(
order.map {
if (it.route == pref.route) it.copy(enabled = !it.enabled) else it
},
)
}
},
onMove = { delta ->
val to = i + delta
if (to in order.indices) {
val reordered = order.toMutableList()
reordered.add(to, reordered.removeAt(i))
prefs.setOrder(reordered)
}
},
)
}
}
`@Composable`
private fun NavBarOptions(downloadsSupported: Boolean) {
val context = LocalContext.current
val prefs = remember(context) { NavBarPreferences(context) }
val order by NavBarPreferences.order.collectAsState()
order.forEachIndexed { i, pref ->
if (pref.route == PhonoTab.Downloads.route && !downloadsSupported) return@forEachIndexed
val tab = PhonoTab.entries.firstOrNull { it.route == pref.route }
?: return@forEachIndexed
val locked = pref.route in NavBarPreferences.LOCKED
NavBarEditorRow(
label = tab.label,
enabled = pref.enabled,
locked = locked,
canMoveUp = i > 0,
canMoveDown = i < order.lastIndex,
onToggle = {
if (!locked) {
prefs.setOrder(
order.map {
if (it.route == pref.route) it.copy(enabled = !it.enabled) else it
},
)
}
},
onMove = { delta ->
val to = i + delta
if (to in order.indices) {
val reordered = order.toMutableList()
reordered.add(to, reordered.removeAt(i))
prefs.setOrder(reordered)
}
},
)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/com/lightphone/spotify/ui/screens/SettingsScreen.kt` around
lines 220 - 254, Update NavBarOptions to accept the downloads capability and
skip the Downloads entry when downloads are unsupported, matching PhonoShell’s
visibleTabs behavior. Thread the existing caps.downloads value from
SettingsScreen into NavBarOptions, and filter or omit the unsupported route
before rendering and reordering so users cannot toggle an unavailable tab.

@jonathancaudill

Copy link
Copy Markdown
Owner

I need to take a look at the customizable navbar. I think technically speaking the current app is not compliant with the SDK's nav bar requirements? This will require some creative rethinking. Customizability isn't a bad idea though.

@jonathancaudill

Copy link
Copy Markdown
Owner

One thing to note is that the current path being used for customizable navbar AND artwork is LocalContext, and I'm fairly sure the SDK blocks that as well (unless they've added it since I last checked)

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.

2 participants