mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
address review: signal now playing with an event flow, not an int
This commit is contained in:
@@ -9,13 +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.NowPlayingLauncher
|
||||
import com.subtracks.ui.SubtracksRoot
|
||||
import com.subtracks.ui.theme.SubtracksTheme
|
||||
import org.koin.core.context.GlobalContext
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private val nowPlayingRequest = mutableIntStateOf(0)
|
||||
private val nowPlayingLauncher: NowPlayingLauncher by lazy { GlobalContext.get().get() }
|
||||
|
||||
private val requestNotifications =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { }
|
||||
@@ -25,11 +26,11 @@ class MainActivity : ComponentActivity() {
|
||||
requestNotificationPermission()
|
||||
enableEdgeToEdge()
|
||||
if (shouldRecordNowPlayingLaunch(intent?.action, restoringState = savedInstanceState != null)) {
|
||||
nowPlayingRequest.intValue++
|
||||
nowPlayingLauncher.request()
|
||||
}
|
||||
setContent {
|
||||
SubtracksTheme {
|
||||
SubtracksRoot(nowPlayingRequest = nowPlayingRequest.intValue)
|
||||
SubtracksRoot()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +38,7 @@ class MainActivity : ComponentActivity() {
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
setIntent(intent)
|
||||
if (intent.action == ACTION_OPEN_NOW_PLAYING) nowPlayingRequest.intValue++
|
||||
if (intent.action == ACTION_OPEN_NOW_PLAYING) nowPlayingLauncher.request()
|
||||
}
|
||||
|
||||
private fun requestNotificationPermission() {
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.subtracks.playback.MediaSessionConnection
|
||||
import com.subtracks.playback.PlaybackController
|
||||
import com.subtracks.playback.PlayerConnection
|
||||
import com.subtracks.playback.Scrobbler
|
||||
import com.subtracks.ui.NowPlayingLauncher
|
||||
import com.subtracks.ui.RootViewModel
|
||||
import com.subtracks.ui.downloads.DownloadsViewModel
|
||||
import com.subtracks.ui.home.HomeListViewModel
|
||||
@@ -108,6 +109,7 @@ fun appModule(
|
||||
it.attach(playback.state, playback.positionMs)
|
||||
}
|
||||
}
|
||||
single { NowPlayingLauncher() }
|
||||
viewModel { RootViewModel(get()) }
|
||||
viewModel { LibraryViewModel(get(), get(), get(), get(), get(), get()) }
|
||||
viewModel { HomeViewModel(get(), get(), get(), get()) }
|
||||
|
||||
@@ -181,10 +181,7 @@ internal fun focusPops(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SubtracksRoot(
|
||||
root: RootViewModel = koinViewModel(),
|
||||
nowPlayingRequest: Int = 0,
|
||||
) {
|
||||
fun SubtracksRoot(root: RootViewModel = koinViewModel()) {
|
||||
when (val hasSource = root.hasSource.collectAsStateWithLifecycle().value) {
|
||||
null -> {
|
||||
LoadingState()
|
||||
@@ -198,14 +195,14 @@ fun SubtracksRoot(
|
||||
val playbackController = koinInject<PlaybackController>()
|
||||
LaunchedEffect(Unit) { playbackController.connect() }
|
||||
val playbackReady by playbackController.ready.collectAsStateWithLifecycle()
|
||||
if (playbackReady) MainNavigation(nowPlayingRequest) else LoadingState()
|
||||
if (playbackReady) MainNavigation() else LoadingState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun MainNavigation(nowPlayingRequest: Int) {
|
||||
private fun MainNavigation() {
|
||||
val navController = rememberNavController()
|
||||
val currentRoute =
|
||||
navController
|
||||
@@ -215,13 +212,13 @@ private fun MainNavigation(nowPlayingRequest: Int) {
|
||||
?.route
|
||||
val tabBarVisible = currentRoute == Routes.LIBRARY
|
||||
val playbackController = koinInject<PlaybackController>()
|
||||
val nowPlayingLauncher = koinInject<NowPlayingLauncher>()
|
||||
val libraryRepository = koinInject<LibraryRepository>()
|
||||
val downloadRepository = koinInject<DownloadRepository>()
|
||||
val playback by playbackController.state.collectAsStateWithLifecycle()
|
||||
val downloads by downloadRepository.states().collectAsStateWithLifecycle()
|
||||
var showingQueue by rememberSaveable { mutableStateOf(false) }
|
||||
var nowPlayingOpen by rememberSaveable { mutableStateOf(false) }
|
||||
var handledNowPlayingRequest by remember { mutableStateOf(0) }
|
||||
var nowPlayingProgress by remember { mutableFloatStateOf(0f) }
|
||||
var miniPlayerTopPx by remember { mutableFloatStateOf(0f) }
|
||||
var nowPlayingFadeOut by remember { mutableStateOf(false) }
|
||||
@@ -306,9 +303,9 @@ private fun MainNavigation(nowPlayingRequest: Int) {
|
||||
nowPlayingProgress = 0f
|
||||
}
|
||||
}
|
||||
LaunchedEffect(nowPlayingRequest, playerVisible) {
|
||||
if (playerVisible && nowPlayingRequest > handledNowPlayingRequest) {
|
||||
handledNowPlayingRequest = nowPlayingRequest
|
||||
LaunchedEffect(playerVisible) {
|
||||
if (!playerVisible) return@LaunchedEffect
|
||||
nowPlayingLauncher.openNowPlaying.collect {
|
||||
if (navController.currentDestination?.route in DETAIL_ROUTES) {
|
||||
navController.popBackStack(Routes.LIBRARY, inclusive = false)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.subtracks.ui
|
||||
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
|
||||
class NowPlayingLauncher {
|
||||
private val requests = Channel<Unit>(Channel.CONFLATED)
|
||||
|
||||
val openNowPlaying: Flow<Unit> = requests.receiveAsFlow()
|
||||
|
||||
fun request() {
|
||||
requests.trySend(Unit)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.subtracks.ui
|
||||
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
|
||||
class NowPlayingLauncherTest {
|
||||
@Test
|
||||
fun aRequestMadeBeforeCollectionIsDelivered() =
|
||||
runTest {
|
||||
val launcher = NowPlayingLauncher()
|
||||
launcher.request()
|
||||
assertEquals(Unit, launcher.openNowPlaying.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun repeatedRequestsCollapseToTheLatest() =
|
||||
runTest {
|
||||
val launcher = NowPlayingLauncher()
|
||||
repeat(3) { launcher.request() }
|
||||
assertEquals(Unit, launcher.openNowPlaying.first())
|
||||
assertNull(withTimeoutOrNull(100) { launcher.openNowPlaying.first() })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user