fix: cover art caching, skip desync, notification tap opens now playing

- api.js: cache coverUrl() per id+size so WebView HTTP cache can work;
  previously each call generated a new random salt/token → unique URL →
  no cache hits → images re-fetched on every render

- player.js: replace _nsBridge('next')/'prev' with explicit seekToIndex
  in nextSong/prevSong so native always jumps to the exact same index JS
  computed; 'next'/'prev' relied on native's internal pointer being in sync
  which caused 'UI shows new song but audio plays old one' when they drifted

- MusicService: set setSessionActivity PendingIntent on MediaSession so
  tapping the playback notification opens the app

- MainActivity: handle open_now_playing extra in onCreate (cold start)
  and onNewIntent (app already running) to show the Now Playing screen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-05-18 22:12:29 +02:00
1 parent 66099c12f0
commit ba382aa6d9
4 files changed
+58 -5

No files matched your search

@@ -29,6 +29,7 @@ class MainActivity : AppCompatActivity(), MusicService.StateListener {
private lateinit var webBridge: WebBridge
private var controllerFuture: ListenableFuture<MediaController>? = null
private var mediaController: MediaController? = null
private var pendingOpenNowPlaying = false
// ─── Back-press handling ──────────────────────────────────────────────────
@@ -73,6 +74,19 @@ class MainActivity : AppCompatActivity(), MusicService.StateListener {
val url = BuildConfig.NOVASONIC_URL.ifEmpty { "https://demo.navidrome.org" }
webView.loadUrl(url)
// Notification tap while app was not running — defer until page is loaded.
if (intent?.getBooleanExtra("open_now_playing", false) == true) {
pendingOpenNowPlaying = true
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
// Notification tap while app is already running — WebView is ready immediately.
if (intent.getBooleanExtra("open_now_playing", false)) {
webView.post { webView.evaluateJavascript("if(window.openNowPlaying)window.openNowPlaying()", null) }
}
}
override fun onResume() { super.onResume(); webView.onResume() }
@@ -128,6 +142,10 @@ class MainActivity : AppCompatActivity(), MusicService.StateListener {
updateStateSnapshot()
callJs("onReady")
}
if (pendingOpenNowPlaying) {
pendingOpenNowPlaying = false
webView.post { webView.evaluateJavascript("if(window.openNowPlaying)window.openNowPlaying()", null) }
}
}
}
webView.webChromeClient = WebChromeClient()
@@ -1,5 +1,6 @@
package com.novasonic.app
import android.app.PendingIntent
import android.content.Intent
import android.os.Handler
import android.os.Looper
@@ -91,8 +92,19 @@ class MusicService : MediaSessionService() {
.setWakeMode(C.WAKE_MODE_NETWORK) // holds WakeLock + WifiLock through Doze
.build()
// Tapping the notification opens the app directly to the Now Playing screen.
val notifTapIntent = Intent(this, MainActivity::class.java).apply {
putExtra("open_now_playing", true)
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
}
val notifTapPending = PendingIntent.getActivity(
this, 0, notifTapIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
mediaSession = MediaSession.Builder(this, player)
.setBitmapLoader(bitmapLoader) // use cached loader for notification artwork
.setSessionActivity(notifTapPending)
.build()
player.addListener(PlayerListener())