84 lines
2.8 KiB
Markdown
84 lines
2.8 KiB
Markdown
# OpenVinyl — Flutter (Android)
|
|
|
|
A free clone of the OpenVinyl turntable visualizer for Android.
|
|
|
|
## 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 `package` line in both `.kt` files
|
|
- Update `applicationId` in `android/app/build.gradle`
|
|
- Update the directory path under `kotlin/`
|
|
|
|
### 2. Install dependencies
|
|
```bash
|
|
flutter pub get
|
|
```
|
|
|
|
### 3. Run
|
|
```bash
|
|
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:
|
|
|
|
1. **Uncomment** the `home_widget` import and `_pushToWidget()` call in
|
|
`lib/services/media_service.dart`
|
|
2. Create a Glance widget in Kotlin:
|
|
`android/app/src/main/kotlin/pt/ruifpb/openvinyl/VinylWidgetReceiver.kt`
|
|
3. Add the `<receiver>` block in `AndroidManifest.xml` (stub already in the file)
|
|
4. 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:
|
|
|
|
1. Creates a `MediaController` from the token
|
|
2. Reads metadata (title, artist, album art bitmap) and playback state
|
|
3. Serialises the bitmap to JPEG bytes
|
|
4. Pushes a `Map` through the `EventChannel` to Flutter
|
|
|
|
Flutter's `MediaService` receives the map, deserialises it into a `MediaInfo`
|
|
object, and re-broadcasts it to any listener (currently `PlayerScreen`).
|