Commit Graph

58 Commits

Author SHA1 Message Date
cottongin
a4c0fa9a6e fix: resolve playback stop failure and Icecast stream disconnection
AudioEngine.stop() only called Thread.interrupt(), which doesn't
interrupt blocking InputStream.read() on OkHttp streams. This caused
audio to continue after stop and blocked subsequent play attempts
(old job never completed). Now closes timedStream to force the
blocking read to fail.

Removed LowLatencySocketFactory (16KB receive buffer) which triggered
Icecast slow-client disconnection on burst-on-connect. Force HTTP/1.1
to avoid HTTP/2 negotiation issues with Icecast servers.

Also fixed: awaitEngine() SharedFlow collector coroutine leak, and
added MAX_CATCHUP_FRAMES safety cap to prevent infinite frame skipping.

Made-with: Cursor
2026-03-11 18:14:13 -04:00
cottongin
8872b9de96 fix: resolve tab long-press context menu blocked by drag gesture
The detectDragGesturesAfterLongPress modifier was consuming the
long-press event before combinedClickable.onLongClick could fire.
Replace combinedClickable with movement-tracking inside the drag
handler — small movement on release shows the context menu, large
movement commits the reorder. Move tap handling into Tab.onClick.

Made-with: Cursor
2026-03-11 17:12:14 -04:00
cottongin
5f7cb050e5 fix: address code review issues — pinned on fresh install, reorder selection, stale rename, detached scopes, duplicate click
Made-with: Cursor
2026-03-11 16:32:33 -04:00
cottongin
5c87f821e0 feat: add drag-to-reorder for tabs within pinned/unpinned groups
Made-with: Cursor
2026-03-11 16:30:00 -04:00
cottongin
2d3b0cea7a feat: add tab rename and pin/unpin via long-press context menu
Made-with: Cursor
2026-03-11 16:27:13 -04:00
cottongin
973bb9e7fe feat: add playlist naming dialog on import
Made-with: Cursor
2026-03-11 16:25:58 -04:00
cottongin
eb111fce35 feat: add pinned column to Playlist with migration
Made-with: Cursor
2026-03-11 16:25:56 -04:00
cottongin
cf57d22dc5 feat: add per-station quality UI — context menu and dialog
- Create QualityOverrideDialog with radio selection for preferred quality
- Add Quality menu item to station long-press (only for stations with streams)
- Add setQualityOverride, getStreamsForStation, getQualityOverrideForStation to ViewModel
- Add getStationIdsWithStreams to StationStreamDao for hasStreams lookup

Made-with: Cursor
2026-03-11 16:22:59 -04:00
cottongin
92f3b35418 Task 8: Wire StationPreference into StreamResolver
- Add StationPreferenceDao to StreamResolver constructor
- Check station_preferences before station.qualityOverride / global prefs
- Mock stationPrefDao in StreamResolverTest, add precedence test

Made-with: Cursor
2026-03-11 16:20:21 -04:00
cottongin
2087b48e4e Task 7: Create StationPreference entity and DAO
- Add StationPreference entity with FK to Station, unique index on stationId
- Add StationPreferenceDao with getByStationId, upsert, deleteByStationId
- Add station_preferences table via MIGRATION_4_5

Made-with: Cursor
2026-03-11 16:20:14 -04:00
cottongin
d0443dfd85 Add StreamResolver unit tests for URL ordering logic
Made-with: Cursor
2026-03-11 16:16:48 -04:00
cottongin
98730959dd fix: add navigation bar padding to miniplayer
Made-with: Cursor
2026-03-11 16:16:09 -04:00
cottongin
3240db829f Refactor RadioPlaybackService: transition(), URL fallback, fixed finally
- Add transition() - all state changes route through it
- Add ConnectionFailedException for connection failures
- Refactor startEngine to accept urls: List<String>, iterate with Connecting state
- Extract awaitEngine() for event collection
- Set Connecting (not Playing) initially; Playing only on AudioEngineEvent.Started
- Fix handlePlay finally block: handle all states (Paused vs else)
- Update reconnectLoop to resolve URLs inside loop
- Add Service import for STOP_FOREGROUND_REMOVE

Made-with: Cursor
2026-03-11 16:14:27 -04:00
cottongin
0d5992f4a3 test(PlaybackState): add state machine transition tests
- Idle → Connecting, Connecting → Playing/Paused/Reconnecting/Idle
- Playing → Paused/Reconnecting/Idle
- Paused → Connecting
- Reconnecting → Connecting/Idle
- Stop from any state returns to Idle

Made-with: Cursor
2026-03-11 16:11:14 -04:00
cottongin
f3d28f1a52 refactor(PlaybackState): add URL context to Connecting state
- Add urls: List<String> = emptyList() for URL fallback list
- Add currentUrlIndex: Int = 0 for tracking fallback progress
- Defaults preserve backward compatibility (Connecting(station) still works)

Made-with: Cursor
2026-03-11 16:11:12 -04:00
cottongin
7da9fe9b5b fix: enable cleartext HTTP for radio streams
Made-with: Cursor
2026-03-11 16:09:54 -04:00
cottongin
e1286911cc fix: disable NullSafeMutableLiveData lint check crashing release builds
The lintVitalAnalyzeRelease task fails with an IncompatibleClassChangeError
in NonNullableMutableLiveDataDetector, which is a known bug in the lint
library. Disabling this specific check unblocks release APK builds.

Made-with: Cursor
2026-03-11 16:09:22 -04:00
cottongin
a3a00582a0 docs: add playback and UI fixes implementation plan
14 tasks covering cleartext HTTP, state machine refactor, URL
fallback, miniplayer insets, per-station quality, and playlist
management (import naming, rename, pin/unpin, drag reorder).

Made-with: Cursor
2026-03-11 16:08:00 -04:00
cottongin
0705e6a2bc docs: add playback and UI fixes design
State machine refactor of RadioPlaybackService, cleartext HTTP,
URL fallback, miniplayer insets, per-station quality prefs,
and playlist management (import naming, rename, pin/unpin, reorder).

Made-with: Cursor
2026-03-11 16:03:59 -04:00
cottongin
eac81df4b0 fix: show last 20 lines on build failure and unhide clean errors
Build failures now display a colored error banner with the last 20
lines of Gradle output. Removed stderr suppression from clean_build
so Gradle errors are visible.

Made-with: Cursor
2026-03-11 04:38:28 -04:00
cottongin
741b8cb30a feat: add debug build and clean commands
Made-with: Cursor
2026-03-11 04:32:54 -04:00
cottongin
1e5ba4e4fa feat: add release build with signing
Made-with: Cursor
2026-03-11 04:30:50 -04:00
cottongin
ec21256ca5 fix: surface keytool errors and add keytool preflight check
Made-with: Cursor
2026-03-11 04:29:45 -04:00
cottongin
b8a4ddf4a0 feat: add keystore creation and management
Made-with: Cursor
2026-03-11 04:26:58 -04:00
cottongin
1825b7930e fix: harden get_version_name against missing file and extraction failures
Made-with: Cursor
2026-03-11 04:25:48 -04:00
cottongin
9b3e943eea feat: add preflight checks and version extraction
Made-with: Cursor
2026-03-11 04:15:37 -04:00
cottongin
2cb901b77c feat: add build.sh scaffold with menu
Made-with: Cursor
2026-03-11 04:15:31 -04:00
cottongin
ba7282ec13 chore: gitignore dist/ and keystore/ directories
Made-with: Cursor
2026-03-11 04:15:29 -04:00
cottongin
f9bc92e766 docs: add build script implementation plan
7 tasks covering gitignore updates, script scaffold, helpers,
keystore management, release/debug builds, clean, and e2e testing.

Made-with: Cursor
2026-03-11 04:12:50 -04:00
cottongin
327c5fffab docs: add build script design document
Captures the design for an interactive bash build script that
handles release signing, keystore management, and APK output.

Made-with: Cursor
2026-03-11 04:10:53 -04:00
cottongin
d381e80828 fix: polish pass — dark mode, notifications, icons, edge-to-edge
- Wrap SettingsScreen in Scaffold to fix invisible text in dark mode
- Fix notification showing raw ICY metadata instead of parsed track info
- Add proper white-on-transparent notification icon
- Create branded adaptive launcher icon (amber tower on BlueGray900)
- Add edge-to-edge support with proper window inset handling
- Add About section to Settings with version and app info
- Enable BuildConfig generation for version display

Made-with: Cursor
2026-03-10 21:18:48 -04:00
cottongin
5a59b3a86b chore: gitignore .cursor directory
Made-with: Cursor
2026-03-10 20:48:53 -04:00
cottongin
c9b1673e95 chore: gitignore chat-summaries and remove from tracking
Made-with: Cursor
2026-03-10 20:45:20 -04:00
cottongin
fdecf053db docs: add chat summaries and plan documents
Made-with: Cursor
2026-03-10 20:17:03 -04:00
cottongin
c0ba23b208 feat: now playing UX overhaul with stream quality and audio improvements
Redesign Now Playing screen with blurred album art background, dominant
color extraction, bounce marquee for long text, cross-fade artwork
transitions, icon-labeled timers, and stream quality badge (bitrate,
codec, SSL). Add StreamInfo propagation from connection through to UI.
Fix MediaCodec PTS spam by providing incrementing presentation timestamps.

Made-with: Cursor
2026-03-10 20:16:43 -04:00
cottongin
6481d74d95 feat: tabbed station libraries, SomaFM integration, and settings panel
Add tabbed playlist UI with SomaFM as a built-in library including live
listener counts, station hiding, and stream quality selection. Implement
settings panel with quality preferences, listening history, and playlist
import/export improvements. Includes DB migrations 1-4, SomaFM seed
data, stream resolver, and now-playing history logging.

Made-with: Cursor
2026-03-10 20:16:09 -04:00
cottongin
5dd7a411ed fix: refactor player state machine to eliminate race conditions
Introduce a Connecting state so the UI reflects user intent immediately,
centralize navigation in MainActivity via state transitions, and replace
the pauseRequested volatile flag with controller state as single source
of truth.

Made-with: Cursor
2026-03-10 05:15:31 -04:00
cottongin
49bbb54bb9 fix: star visibility, station switching, skip-ahead, and latency optimizations
- Star icons now use distinct tint colors (primary vs faded) for clear state
- Station switching no longer races — old playback job is cancelled before new
- Skip-ahead drops ~1s of buffered audio per tap via atomic counter
- Custom SocketFactory with SO_RCVBUF=16KB and TCP_NODELAY for minimal TCP buffering
- Catch-up drain: discards pre-buffered frames until network reads block (live edge)
- AudioTrack PERFORMANCE_MODE_LOW_LATENCY for smallest hardware buffer

Made-with: Cursor
2026-03-10 04:41:40 -04:00
cottongin
6144de6b08 docs: add README
Made-with: Cursor
2026-03-10 03:11:24 -04:00
cottongin
c143483f33 feat: wire album art to UI and handle Android 13+ notification permission
Made-with: Cursor
2026-03-10 03:11:09 -04:00
cottongin
89b58477c9 feat: add album art resolution with MusicBrainz and fallback chain
Made-with: Cursor
2026-03-10 03:07:32 -04:00
cottongin
20daa86b52 feat: add Settings screen with export, history, and track search
Made-with: Cursor
2026-03-10 02:49:38 -04:00
cottongin
7678b2b12a feat: add Now Playing screen with dual timers and latency indicator
Made-with: Cursor
2026-03-10 02:48:26 -04:00
cottongin
30b4bc9814 feat: add Station List screen with playlists, starring, and import
Made-with: Cursor
2026-03-10 02:42:25 -04:00
cottongin
cacbb0d98d feat: add Material 3 theme and screen navigation
Made-with: Cursor
2026-03-10 02:37:26 -04:00
cottongin
ca7b757812 feat: add foreground playback service with Stay Connected reconnection
Made-with: Cursor
2026-03-10 02:30:48 -04:00
cottongin
cfb04d3200 feat: integrate audio engine pipeline with MediaCodec and AudioTrack
Made-with: Cursor
2026-03-10 02:18:36 -04:00
cottongin
7814d682f6 feat: add HTTP stream connection with ICY header support
Made-with: Cursor
2026-03-10 02:14:46 -04:00
cottongin
fd73caf181 fix: correct MP3 frame header values in tests
Made-with: Cursor
2026-03-10 02:01:46 -04:00
cottongin
3d4d163508 feat: add MP3 frame synchronizer with re-sync and validation
Made-with: Cursor
2026-03-10 01:51:24 -04:00