Skip to content

Commit 09ff388

Browse files
committed
feat: update reconnecting banner
1 parent db8f791 commit 09ff388

File tree

1 file changed

+55
-11
lines changed

1 file changed

+55
-11
lines changed

app/src/main/java/com/mixtapeo/lyrisync/MainActivity.kt

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,12 @@ class MainActivity : AppCompatActivity() {
356356

357357
// --- CUSTOM CENTERING LOGIC ---
358358
val recyclerView = findViewById<RecyclerView>(R.id.lyricRecyclerView)
359-
val layoutManager = recyclerView.layoutManager as androidx.recyclerview.widget.LinearLayoutManager
359+
val layoutManager =
360+
recyclerView.layoutManager as androidx.recyclerview.widget.LinearLayoutManager
360361

361362
// Calculate the middle of the RecyclerView
362-
val offset = recyclerView.height / 2 - 100 // Subtracting 100px for the approximate height of one lyric row
363+
val offset =
364+
recyclerView.height / 2 - 100 // Subtracting 100px for the approximate height of one lyric row
363365

364366
// This force-scrolls the index to the top, then applies the 'offset'
365367
// to push it down to the middle.
@@ -675,7 +677,7 @@ class MainActivity : AppCompatActivity() {
675677
syncLyricsToPosition(playerState.playbackPosition)
676678
}
677679
}
678-
delay(32)
680+
delay(100)
679681
}
680682
}
681683
}
@@ -708,37 +710,79 @@ class MainActivity : AppCompatActivity() {
708710
}
709711
}
710712

713+
private var lastPlaybackPosition: Long = -1L
714+
711715
private fun startConnectionMonitor() {
712-
connectionMonitorJob?.cancel() // Cancel any existing job just in case
716+
connectionMonitorJob?.cancel()
713717
Log.d("Lyrisync", "Heartbeat start")
718+
714719
connectionMonitorJob = lifecycleScope.launch(Dispatchers.Main) {
715720
while (isActive) {
716721
val banner = findViewById<TextView>(R.id.spotifyOfflineBanner)
717-
// Check if the remote exists and is actively connected
718722
val isConnected = spotifyAppRemote?.isConnected == true
719-
Log.d("Lyrisync", "Heartbeat active: $isConnected")
723+
720724
if (isConnected) {
721-
if (banner.visibility == View.VISIBLE) {
722-
banner.visibility = View.GONE
725+
// Fetch the player state to verify the timestamp is actually moving
726+
spotifyAppRemote?.playerApi?.playerState?.setResultCallback { playerState ->
727+
val isPlaying = !playerState.isPaused
728+
val currentPos = playerState.playbackPosition
729+
Log.d("Lyrisync", "pos: $currentPos, isPlaying: $isPlaying")
730+
731+
// If it claims to be playing, but the position hasn't moved since our last 2-second check, it's frozen.
732+
val isStale = isPlaying && currentPos == lastPlaybackPosition && currentPos > 0
733+
734+
lastPlaybackPosition = currentPos
735+
736+
if (isStale) {
737+
if (banner.visibility == View.GONE) {
738+
banner.text = "Spotify is sleeping. Tap to sync."
739+
banner.visibility = View.VISIBLE
740+
741+
// Let the user tap the banner to instantly fix the issue
742+
banner.setOnClickListener { wakeUpSpotify() }
743+
}
744+
} else {
745+
// Everything is normal and playing properly
746+
if (banner.visibility == View.VISIBLE) {
747+
banner.visibility = View.GONE
748+
}
749+
}
723750
}
724751
} else {
752+
// Completely disconnected from the local App Remote
725753
if (banner.visibility == View.GONE) {
754+
banner.text = "Spotify disconnected. Attempting to reconnect..."
726755
banner.visibility = View.VISIBLE
756+
banner.setOnClickListener(null) // Remove click listener
727757
}
728758

729-
// If we disconnected but aren't currently trying to connect, trigger a silent reconnect
730759
if (!isConnecting) {
731760
Log.d("Lyrisync", "Heartbeat missed: Attempting background reconnect")
732761
reconnectToSpotify(forceAuthView = false)
733762
}
734763
}
735764

736-
// Wait 5 seconds before checking again
737-
delay(5000)
765+
// Check every 2 seconds. This guarantees enough time has passed to see if the
766+
// playback position naturally advanced.
767+
delay(2000)
738768
}
739769
}
740770
}
741771

772+
private fun wakeUpSpotify() {
773+
val spotifyPackage = "com.spotify.music"
774+
val launchIntent = packageManager.getLaunchIntentForPackage(spotifyPackage)
775+
776+
if (launchIntent != null) {
777+
Toast.makeText(this, "Waking Spotify to sync...", Toast.LENGTH_SHORT).show()
778+
// Brings Spotify to the foreground briefly to restore its network privileges
779+
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
780+
startActivity(launchIntent)
781+
} else {
782+
Toast.makeText(this, "Spotify not installed.", Toast.LENGTH_SHORT).show()
783+
}
784+
}
785+
742786
// <------- support funcs ------->
743787
// Setup Coil ImageLoader with GIF support
744788
private fun showFirstStartDialog(prefs: android.content.SharedPreferences) {

0 commit comments

Comments
 (0)