mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
address review: keep the notification tap when the activity is recreated
This commit is contained in:
@@ -9,6 +9,7 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.subtracks.ui.NowPlayingLauncher
|
import com.subtracks.ui.NowPlayingLauncher
|
||||||
import com.subtracks.ui.SubtracksRoot
|
import com.subtracks.ui.SubtracksRoot
|
||||||
@@ -16,6 +17,7 @@ import com.subtracks.ui.theme.SubtracksTheme
|
|||||||
import org.koin.core.context.GlobalContext
|
import org.koin.core.context.GlobalContext
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
private val launchViewModel: NowPlayingLaunchViewModel by viewModels()
|
||||||
private val nowPlayingLauncher: NowPlayingLauncher by lazy { GlobalContext.get().get() }
|
private val nowPlayingLauncher: NowPlayingLauncher by lazy { GlobalContext.get().get() }
|
||||||
|
|
||||||
private val requestNotifications =
|
private val requestNotifications =
|
||||||
@@ -25,9 +27,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
requestNotificationPermission()
|
requestNotificationPermission()
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
if (shouldRecordNowPlayingLaunch(intent?.action, restoringState = savedInstanceState != null)) {
|
if (launchViewModel.claimLaunch(intent?.action)) nowPlayingLauncher.request()
|
||||||
nowPlayingLauncher.request()
|
|
||||||
}
|
|
||||||
setContent {
|
setContent {
|
||||||
SubtracksTheme {
|
SubtracksTheme {
|
||||||
SubtracksRoot()
|
SubtracksRoot()
|
||||||
@@ -38,7 +38,10 @@ class MainActivity : ComponentActivity() {
|
|||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
setIntent(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() {
|
private fun requestNotificationPermission() {
|
||||||
@@ -53,8 +56,3 @@ class MainActivity : ComponentActivity() {
|
|||||||
const val ACTION_OPEN_NOW_PLAYING = "com.subtracks.action.OPEN_NOW_PLAYING"
|
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
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -301,11 +301,10 @@ private fun MainNavigation() {
|
|||||||
settleJob?.cancel()
|
settleJob?.cancel()
|
||||||
nowPlayingOpen = false
|
nowPlayingOpen = false
|
||||||
nowPlayingProgress = 0f
|
nowPlayingProgress = 0f
|
||||||
|
return@LaunchedEffect
|
||||||
}
|
}
|
||||||
}
|
|
||||||
LaunchedEffect(playerVisible) {
|
|
||||||
if (!playerVisible) return@LaunchedEffect
|
|
||||||
nowPlayingLauncher.openNowPlaying.collect {
|
nowPlayingLauncher.openNowPlaying.collect {
|
||||||
|
showingQueue = false
|
||||||
if (navController.currentDestination?.route in DETAIL_ROUTES) {
|
if (navController.currentDestination?.route in DETAIL_ROUTES) {
|
||||||
navController.popBackStack(Routes.LIBRARY, inclusive = false)
|
navController.popBackStack(Routes.LIBRARY, inclusive = false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import kotlinx.coroutines.channels.Channel
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
|
|
||||||
class NowPlayingLauncher {
|
internal class NowPlayingLauncher {
|
||||||
private val requests = Channel<Unit>(Channel.CONFLATED)
|
private val requests = Channel<Unit>(Channel.CONFLATED)
|
||||||
|
|
||||||
val openNowPlaying: Flow<Unit> = requests.receiveAsFlow()
|
val openNowPlaying: Flow<Unit> = requests.receiveAsFlow()
|
||||||
|
|||||||
@@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user