2.9 KiB
OpenVinyl — Flutter (Android)
A free clone of the OpenVinyl turntable visualizer for Android.
AI Usage
Claude Sonnet 4.6, Claude Sonnet 4.5 and Github Copilot used when making this project.
Project Structure
lib/
main.dart ← App entry, permission check
models/
media_info.dart ← Data class for now-playing track
services/
media_service.dart ← Platform channel bridge (Flutter side)
screens/
player_screen.dart ← Main turntable screen
permission_screen.dart ← Shown if Notification Access not granted
widgets/
vinyl_record.dart ← Spinning record with album art + grooves
tonearm.dart ← Animated needle arm
android/app/src/main/
kotlin/pt/ruifpb/openvinyl/
MainActivity.kt ← Platform channel setup (MethodChannel + EventChannel)
MediaListenerService.kt ← NotificationListenerService reads now-playing data
res/xml/
notification_listener_service.xml
AndroidManifest.xml ← Service declaration with BIND_NOTIFICATION_LISTENER
Setup
1. Package name
By default the package is pt.ruifpb.openvinyl. If you want to change it:
- Update the
packageline in both.ktfiles - Update
applicationIdinandroid/app/build.gradle - Update the directory path under
kotlin/
2. Install dependencies
flutter pub get
3. Run
flutter run
On first launch the app will show a permission screen. Tap Open Settings, find OpenVinyl in the Notification Listener list, and enable it. Return to the app — it will detect the change automatically.
Adding Home Screen Widgets (later)
The code is pre-wired for this. When you're ready:
- Uncomment the
home_widgetimport and_pushToWidget()call inlib/services/media_service.dart - Create a Glance widget in Kotlin:
android/app/src/main/kotlin/pt/ruifpb/openvinyl/VinylWidgetReceiver.kt - Add the
<receiver>block inAndroidManifest.xml(stub already in the file) - Add widget info XML at
android/app/src/main/res/xml/vinyl_widget_info.xml
The home_widget package (already in pubspec.yaml) handles the Flutter ↔
widget data bridge via HomeWidget.saveWidgetData() and
HomeWidget.updateWidget().
How the Notification Listener Works
MediaListenerService extends Android's NotificationListenerService.
When any app posts a notification that carries a MediaSession.Token extra
(Spotify, YouTube Music, Podcast apps, etc.), the service:
- Creates a
MediaControllerfrom the token - Reads metadata (title, artist, album art bitmap) and playback state
- Serialises the bitmap to JPEG bytes
- Pushes a
Mapthrough theEventChannelto Flutter
Flutter's MediaService receives the map, deserialises it into a MediaInfo
object, and re-broadcasts it to any listener (currently PlayerScreen).
License
Apache 2.0 with Commons Clause - free for non-commercial use.