diff --git a/app/src/main/kotlin/com/subtracks/MainActivity.kt b/app/src/main/kotlin/com/subtracks/MainActivity.kt index 408efeb2..e94fddf1 100644 --- a/app/src/main/kotlin/com/subtracks/MainActivity.kt +++ b/app/src/main/kotlin/com/subtracks/MainActivity.kt @@ -9,6 +9,7 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels import androidx.core.content.ContextCompat import com.subtracks.ui.NowPlayingLauncher import com.subtracks.ui.SubtracksRoot @@ -16,6 +17,7 @@ import com.subtracks.ui.theme.SubtracksTheme import org.koin.core.context.GlobalContext class MainActivity : ComponentActivity() { + private val launchViewModel: NowPlayingLaunchViewModel by viewModels() private val nowPlayingLauncher: NowPlayingLauncher by lazy { GlobalContext.get().get() } private val requestNotifications = @@ -25,9 +27,7 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) requestNotificationPermission() enableEdgeToEdge() - if (shouldRecordNowPlayingLaunch(intent?.action, restoringState = savedInstanceState != null)) { - nowPlayingLauncher.request() - } + if (launchViewModel.claimLaunch(intent?.action)) nowPlayingLauncher.request() setContent { SubtracksTheme { SubtracksRoot() @@ -38,7 +38,10 @@ class MainActivity : ComponentActivity() { override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) - if (intent.action == ACTION_OPEN_NOW_PLAYING) nowPlayingLauncher.request() + if (intent.action == ACTION_OPEN_NOW_PLAYING) { + launchViewModel.markHandled() + nowPlayingLauncher.request() + } } private fun requestNotificationPermission() { @@ -53,8 +56,3 @@ class MainActivity : ComponentActivity() { const val ACTION_OPEN_NOW_PLAYING = "com.subtracks.action.OPEN_NOW_PLAYING" } } - -internal fun shouldRecordNowPlayingLaunch( - action: String?, - restoringState: Boolean, -): Boolean = action == MainActivity.ACTION_OPEN_NOW_PLAYING && !restoringState diff --git a/app/src/main/kotlin/com/subtracks/NowPlayingLaunchViewModel.kt b/app/src/main/kotlin/com/subtracks/NowPlayingLaunchViewModel.kt new file mode 100644 index 00000000..247cfeea --- /dev/null +++ b/app/src/main/kotlin/com/subtracks/NowPlayingLaunchViewModel.kt @@ -0,0 +1,17 @@ +package com.subtracks + +import androidx.lifecycle.ViewModel + +class NowPlayingLaunchViewModel : ViewModel() { + private var launchHandled = false + + fun claimLaunch(action: String?): Boolean { + if (action != MainActivity.ACTION_OPEN_NOW_PLAYING || launchHandled) return false + launchHandled = true + return true + } + + fun markHandled() { + launchHandled = true + } +} diff --git a/app/src/main/kotlin/com/subtracks/ui/AppRoot.kt b/app/src/main/kotlin/com/subtracks/ui/AppRoot.kt index 61d8c8b3..e71a9fcd 100644 --- a/app/src/main/kotlin/com/subtracks/ui/AppRoot.kt +++ b/app/src/main/kotlin/com/subtracks/ui/AppRoot.kt @@ -301,11 +301,10 @@ private fun MainNavigation() { settleJob?.cancel() nowPlayingOpen = false nowPlayingProgress = 0f + return@LaunchedEffect } - } - LaunchedEffect(playerVisible) { - if (!playerVisible) return@LaunchedEffect nowPlayingLauncher.openNowPlaying.collect { + showingQueue = false if (navController.currentDestination?.route in DETAIL_ROUTES) { navController.popBackStack(Routes.LIBRARY, inclusive = false) } diff --git a/app/src/main/kotlin/com/subtracks/ui/NowPlayingLauncher.kt b/app/src/main/kotlin/com/subtracks/ui/NowPlayingLauncher.kt index d3777514..00b111e6 100644 --- a/app/src/main/kotlin/com/subtracks/ui/NowPlayingLauncher.kt +++ b/app/src/main/kotlin/com/subtracks/ui/NowPlayingLauncher.kt @@ -4,7 +4,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.receiveAsFlow -class NowPlayingLauncher { +internal class NowPlayingLauncher { private val requests = Channel(Channel.CONFLATED) val openNowPlaying: Flow = requests.receiveAsFlow() diff --git a/app/src/test/kotlin/com/subtracks/NowPlayingLaunchTest.kt b/app/src/test/kotlin/com/subtracks/NowPlayingLaunchTest.kt deleted file mode 100644 index 90a4c9fa..00000000 --- a/app/src/test/kotlin/com/subtracks/NowPlayingLaunchTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.subtracks - -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Test - -class NowPlayingLaunchTest { - @Test - fun aFreshLaunchFromTheNotificationIsRecorded() { - assertTrue( - shouldRecordNowPlayingLaunch( - action = MainActivity.ACTION_OPEN_NOW_PLAYING, - restoringState = false, - ), - ) - } - - @Test - fun recreatingTheActivityDoesNotReRecordTheLaunch() { - assertFalse( - shouldRecordNowPlayingLaunch( - action = MainActivity.ACTION_OPEN_NOW_PLAYING, - restoringState = true, - ), - ) - } - - @Test - fun aNormalLaunchIsNotRecorded() { - assertFalse(shouldRecordNowPlayingLaunch(action = "android.intent.action.MAIN", restoringState = false)) - } - - @Test - fun aLaunchWithoutAnActionIsNotRecorded() { - assertFalse(shouldRecordNowPlayingLaunch(action = null, restoringState = false)) - } -} diff --git a/app/src/test/kotlin/com/subtracks/NowPlayingLaunchViewModelTest.kt b/app/src/test/kotlin/com/subtracks/NowPlayingLaunchViewModelTest.kt new file mode 100644 index 00000000..6418c02a --- /dev/null +++ b/app/src/test/kotlin/com/subtracks/NowPlayingLaunchViewModelTest.kt @@ -0,0 +1,36 @@ +package com.subtracks + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class NowPlayingLaunchViewModelTest { + @Test + fun aFreshLaunchFromTheNotificationIsClaimed() { + assertTrue(NowPlayingLaunchViewModel().claimLaunch(MainActivity.ACTION_OPEN_NOW_PLAYING)) + } + + @Test + fun recreatingTheActivityDoesNotReClaimTheLaunch() { + val viewModel = NowPlayingLaunchViewModel() + assertTrue(viewModel.claimLaunch(MainActivity.ACTION_OPEN_NOW_PLAYING)) + assertFalse(viewModel.claimLaunch(MainActivity.ACTION_OPEN_NOW_PLAYING)) + } + + @Test + fun aWarmTapMarksTheLaunchHandled() { + val viewModel = NowPlayingLaunchViewModel() + viewModel.markHandled() + assertFalse(viewModel.claimLaunch(MainActivity.ACTION_OPEN_NOW_PLAYING)) + } + + @Test + fun aNormalLaunchIsNotClaimed() { + assertFalse(NowPlayingLaunchViewModel().claimLaunch("android.intent.action.MAIN")) + } + + @Test + fun aLaunchWithoutAnActionIsNotClaimed() { + assertFalse(NowPlayingLaunchViewModel().claimLaunch(null)) + } +}