mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
open now playing when the media notification is tapped
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.subtracks
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -8,11 +9,14 @@ import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.subtracks.ui.SubtracksRoot
|
||||
import com.subtracks.ui.theme.SubtracksTheme
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private val nowPlayingRequest = mutableIntStateOf(0)
|
||||
|
||||
private val requestNotifications =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { }
|
||||
|
||||
@@ -20,13 +24,20 @@ class MainActivity : ComponentActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
requestNotificationPermission()
|
||||
enableEdgeToEdge()
|
||||
if (intent?.action == ACTION_OPEN_NOW_PLAYING) nowPlayingRequest.intValue++
|
||||
setContent {
|
||||
SubtracksTheme {
|
||||
SubtracksRoot()
|
||||
SubtracksRoot(nowPlayingRequest = nowPlayingRequest.intValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
setIntent(intent)
|
||||
if (intent.action == ACTION_OPEN_NOW_PLAYING) nowPlayingRequest.intValue++
|
||||
}
|
||||
|
||||
private fun requestNotificationPermission() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
|
||||
val granted =
|
||||
@@ -34,4 +45,8 @@ class MainActivity : ComponentActivity() {
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
if (!granted) requestNotifications.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ACTION_OPEN_NOW_PLAYING = "com.subtracks.action.OPEN_NOW_PLAYING"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,8 @@ class PlaybackService : MediaSessionService() {
|
||||
PendingIntent.getActivity(
|
||||
this,
|
||||
0,
|
||||
Intent(this, MainActivity::class.java),
|
||||
Intent(this, MainActivity::class.java)
|
||||
.setAction(MainActivity.ACTION_OPEN_NOW_PLAYING),
|
||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
|
||||
),
|
||||
).setBitmapLoader(loader)
|
||||
|
||||
@@ -166,6 +166,12 @@ internal fun resetOnSourceSwitch(
|
||||
if (route in DETAIL_ROUTES) popDetail()
|
||||
}
|
||||
|
||||
internal fun shouldOpenNowPlaying(
|
||||
request: Int,
|
||||
handled: Int,
|
||||
playerVisible: Boolean,
|
||||
): Boolean = playerVisible && request > handled
|
||||
|
||||
internal data class BackStackKey(
|
||||
val route: String?,
|
||||
val argument: String?,
|
||||
@@ -181,7 +187,10 @@ internal fun focusPops(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SubtracksRoot(root: RootViewModel = koinViewModel()) {
|
||||
fun SubtracksRoot(
|
||||
root: RootViewModel = koinViewModel(),
|
||||
nowPlayingRequest: Int = 0,
|
||||
) {
|
||||
when (val hasSource = root.hasSource.collectAsStateWithLifecycle().value) {
|
||||
null -> {
|
||||
LoadingState()
|
||||
@@ -195,14 +204,14 @@ fun SubtracksRoot(root: RootViewModel = koinViewModel()) {
|
||||
val playbackController = koinInject<PlaybackController>()
|
||||
LaunchedEffect(Unit) { playbackController.connect() }
|
||||
val playbackReady by playbackController.ready.collectAsStateWithLifecycle()
|
||||
if (playbackReady) MainNavigation() else LoadingState()
|
||||
if (playbackReady) MainNavigation(nowPlayingRequest) else LoadingState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun MainNavigation() {
|
||||
private fun MainNavigation(nowPlayingRequest: Int) {
|
||||
val navController = rememberNavController()
|
||||
val currentRoute =
|
||||
navController
|
||||
@@ -218,6 +227,7 @@ private fun MainNavigation() {
|
||||
val downloads by downloadRepository.states().collectAsStateWithLifecycle()
|
||||
var showingQueue by rememberSaveable { mutableStateOf(false) }
|
||||
var nowPlayingOpen by rememberSaveable { mutableStateOf(false) }
|
||||
var handledNowPlayingRequest by rememberSaveable { mutableStateOf(0) }
|
||||
var nowPlayingProgress by remember { mutableFloatStateOf(0f) }
|
||||
var miniPlayerTopPx by remember { mutableFloatStateOf(0f) }
|
||||
var nowPlayingFadeOut by remember { mutableStateOf(false) }
|
||||
@@ -302,6 +312,12 @@ private fun MainNavigation() {
|
||||
nowPlayingProgress = 0f
|
||||
}
|
||||
}
|
||||
LaunchedEffect(nowPlayingRequest, playerVisible) {
|
||||
if (shouldOpenNowPlaying(nowPlayingRequest, handledNowPlayingRequest, playerVisible)) {
|
||||
handledNowPlayingRequest = nowPlayingRequest
|
||||
settleNowPlaying(true)
|
||||
}
|
||||
}
|
||||
val density = LocalDensity.current
|
||||
val navBarInset = with(density) { WindowInsets.navigationBars.getBottom(this).toDp() }
|
||||
val keyboardUp = WindowInsets.imeAnimationTarget.getBottom(density) > 0
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.subtracks.ui
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class NowPlayingRequestTest {
|
||||
@Test
|
||||
fun aNotificationWithNothingPlayingDoesNotOpen() {
|
||||
assertFalse(shouldOpenNowPlaying(request = 1, handled = 0, playerVisible = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aNotificationWithSomethingPlayingOpens() {
|
||||
assertTrue(shouldOpenNowPlaying(request = 1, handled = 0, playerVisible = true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun anAlreadyHandledRequestDoesNotReopen() {
|
||||
assertFalse(shouldOpenNowPlaying(request = 1, handled = 1, playerVisible = true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aNewerRequestOpensAgain() {
|
||||
assertTrue(shouldOpenNowPlaying(request = 2, handled = 1, playerVisible = true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun anOldRequestWaitsUntilSomethingIsPlaying() {
|
||||
assertFalse(shouldOpenNowPlaying(request = 1, handled = 0, playerVisible = false))
|
||||
assertTrue(shouldOpenNowPlaying(request = 1, handled = 0, playerVisible = true))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user