Repository navigation
fix: Android UI polish — safe-area, headers, review filter, log - #28
Merged
Merged
Conversation
The bottom FAB on the library home was hiding behind the Android navigation bar, and the native Stack header rendered under the status bar on first mount (corrected itself on app resume). - NewDeckFAB now reads useSafeAreaInsets().bottom for its offset; absolute positioning ignores SafeAreaView padding, so the inset must be applied directly. - LibraryScreen SafeAreaView now includes the 'bottom' edge so flow children sit above the nav bar. - RootLayout's SafeAreaProvider is now initialized with initialWindowMetrics so insets are available synchronously on first render — react-navigation's header reads insets at mount and was getting top=0 before the layout pass settled.
The custom ScreenHeader sat inside the screen body even though
the native Stack header was already rendered above it — a
"double header" smell that wasted vertical space and split title
ownership across two components.
- Set per-screen titles in _layout.tsx for deck/[id] ("Deck"),
export/[id] ("Export"), card/[deckId]/[isrc] ("Card preview"),
and import ("Import deck"). review/[id] uses an in-screen
<Stack.Screen options> because its headerTitle (subtitle is
dynamic) and headerRight (Export PDF) depend on local state.
- Brand-style the global headerTitleStyle: Nunito 900 Black 18px
in navy50, matching the prior ScreenHeader visual.
- Delete components/ui/screen-header.tsx and remove all imports.
The placeholder text duplicated the helper text below the field
(both showing the example URL), and on Android the long URL
wrapped at the path separator since the EditText hint doesn't
honor single-line by default.
- Drop the placeholder back to a short format hint ("https://...")
per Material/Baymard guidance: placeholders carry the shape of
the value, not the value itself.
- Add numberOfLines={1} so Android stops wrapping the hint.
- Helper text below the field continues to show the full example
URL — that's where elaboration belongs.
The pills above the review list were status-only — useful as a
glance but inert. Make them functional filter chips so the user
can isolate either bucket. Also unify wording.
- Wrap each pill in a Pressable that toggles a FilterKind state
('all' | 'kept' | 'dropped'). Tapping the active pill clears
the filter; tapping the other switches to it.
- Inactive pill fades to opacity 0.4 to signal the filter state.
- Add a red Dot to the skipped pill so both pills share the same
composition (Dot + label) — the green pill loses the inline ✓,
which was a third redundant green signal next to the lime tone
and lime Dot.
- Rename "dropped" → "skipped" in user-facing copy (header
subtitle + pill text). The domain term ("dropped"/DroppedTrack)
stays in code; the user-facing word is friendlier.
- accessibilityState={{ selected }} announces the active filter.
The log felt CLI-ish: mono font, arrows, checkmarks, and a second stats row that duplicated the first. - Drop the second stats row (the "X dropped" + "X%" line). The kept count is in the header subtitle and the bar already conveys percentage visually; explicit numbers were redundant. - Replace mono font (JetBrainsMono 11px) with display font (Nunito_600SemiBold 13px) so the ticker reads as polished UI rather than terminal output. - Drop the inline arrow + checkmark glyphs. The year is now joined by a middle-dot separator: "Artist — Title · 1975". Skipped tracks omit the year and use the red text color alone to signal state — no "skipped" label needed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SafeAreaViewpadding, soNewDeckFABnow readsuseSafeAreaInsets().bottomdirectly. Library SafeAreaView also gained the'bottom'edge.SafeAreaProvidernow initialized withinitialWindowMetricsso insets are available synchronously at mount instead of after the first layout pass.components/ui/screen-header.tsx— it duplicated the native Stack header above it (double-header smell). 5 screens migrated:deck/[id],import,export/[id],card/[deckId]/[isrc],review/[id]. Per-screen titles set in_layout.tsx; review uses a per-screen<Stack.Screen options>for its dynamic subtitle + Export PDF action.app/generate.tsxplaceholder back to a short format hint (https://...) — was duplicating the helper text below and wrapping at the path separator on Android. AddednumberOfLines={1}to suppress the EditText hint wrap.app/review/[id].tsxkept/skipped pills are now Pressable filter toggles (accessibilityState.selectedset). Inactive pill fades to opacity 0.4. Skipped pill gained a tinted Dot to match the kept pill's composition; the green pill lost the inline✓(third redundant green signal next to lime tone + lime Dot). User-facing copy unified:"dropped"→"skipped".app/resolving.tsxlive log: dropped the second stats row (X dropped+X%duplicated the first), swapped mono font for display font (Nunito_600SemiBold 13px), removed inline→arrow and✓/skippedtext. Year now joined by middle dot:Artist — Title · 1975. Skipped tracks render red without the explicit label.Test plan
npm run typecheckcleanArtist — Title · 1975(no arrows/checkmarks); skipped tracks in redhttps://..., single line on narrow phones