+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package me.vanpetegem.accentor.media
import android.app.Application
import android.content.ComponentName
import androidx.core.content.ContextCompat
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations.map
Expand All @@ -15,20 +14,20 @@ import androidx.media2.session.MediaController
import androidx.media2.session.SessionCommand
import androidx.media2.session.SessionCommandGroup
import androidx.media2.session.SessionToken
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.guava.await
import me.vanpetegem.accentor.data.albums.Album
import me.vanpetegem.accentor.data.albums.AlbumRepository
import me.vanpetegem.accentor.data.tracks.Track
import me.vanpetegem.accentor.data.tracks.TrackRepository

@HiltViewModel
@Singleton
class MediaSessionConnection @Inject constructor(
application: Application,
private val albumRepository: AlbumRepository,
private val trackRepository: TrackRepository,
) : AndroidViewModel(application) {
) {
private val mediaController: MediaController = MediaController.Builder(application)
.setSessionToken(SessionToken(application, ComponentName(application, MusicService::class.java)))
.setControllerCallback(
Expand Down Expand Up @@ -217,8 +216,5 @@ class MediaSessionConnection @Inject constructor(

suspend fun skipTo(position: Int) = mediaController.skipToPlaylistItem(position).await()

suspend fun move(oldPosition: Int, newPosition: Int) =
mediaController.movePlaylistItem(oldPosition, newPosition).await()

suspend fun removeFromQueue(position: Int) = mediaController.removePlaylistItem(position).await()
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import me.vanpetegem.accentor.R
import me.vanpetegem.accentor.data.albums.Album
import me.vanpetegem.accentor.media.MediaSessionConnection
import me.vanpetegem.accentor.ui.player.PlayerViewModel

@Composable
public fun AlbumCard(album: Album, navController: NavController, hideArtist: Int? = null, mediaSessionConnection: MediaSessionConnection = hiltViewModel()) {
public fun AlbumCard(album: Album, navController: NavController, hideArtist: Int? = null, playerViewModel: PlayerViewModel = hiltViewModel()) {
val scope = rememberCoroutineScope()
Card(modifier = Modifier.padding(8.dp).clickable { navController.navigate("albums/${album.id}") }) {
Column {
Expand Down Expand Up @@ -90,23 +90,23 @@ public fun AlbumCard(album: Album, navController: NavController, hideArtist: Int
DropdownMenuItem(
onClick = {
expanded = false
scope.launch(IO) { mediaSessionConnection.play(album) }
scope.launch(IO) { playerViewModel.play(album) }
}
) {
Text(stringResource(R.string.play_now))
}
DropdownMenuItem(
onClick = {
expanded = false
scope.launch(IO) { mediaSessionConnection.addTracksToQueue(album, maxOf(0, mediaSessionConnection.queuePosition.value ?: 0)) }
scope.launch(IO) { playerViewModel.addTracksToQueue(album, maxOf(0, playerViewModel.queuePosition.value ?: 0)) }
}
) {
Text(stringResource(R.string.play_next))
}
DropdownMenuItem(
onClick = {
expanded = false
scope.launch(IO) { mediaSessionConnection.addTracksToQueue(album) }
scope.launch(IO) { playerViewModel.addTracksToQueue(album) }
}
) {
Text(stringResource(R.string.play_last))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ import java.time.format.DateTimeFormatter
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import me.vanpetegem.accentor.R
import me.vanpetegem.accentor.media.MediaSessionConnection
import me.vanpetegem.accentor.ui.player.PlayerViewModel
import me.vanpetegem.accentor.ui.tracks.TrackRow

@Composable
fun AlbumView(
id: Int,
navController: NavController,
albumViewModel: AlbumViewModel = hiltViewModel(),
mediaSessionConnection: MediaSessionConnection = hiltViewModel()
playerViewModel: PlayerViewModel = hiltViewModel()
) {
val scope = rememberCoroutineScope()
val albumState by albumViewModel.getAlbum(id).observeAsState()
Expand Down Expand Up @@ -88,10 +88,10 @@ fun AlbumView(
overflow = TextOverflow.Ellipsis,
)
Row(modifier = Modifier.padding(8.dp)) {
IconButton(onClick = { scope.launch(IO) { mediaSessionConnection.play(album) } }) {
IconButton(onClick = { scope.launch(IO) { playerViewModel.play(album) } }) {
Icon(painterResource(R.drawable.ic_play), contentDescription = stringResource(R.string.play_now))
}
IconButton(onClick = { scope.launch(IO) { mediaSessionConnection.addTracksToQueue(album) } }) {
IconButton(onClick = { scope.launch(IO) { playerViewModel.addTracksToQueue(album) } }) {
Icon(painterResource(R.drawable.ic_queue_add), contentDescription = stringResource(R.string.play_last))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.navigation.NavType
Expand Down Expand Up @@ -123,7 +124,7 @@ fun Content(mainViewModel: MainViewModel = viewModel()) {
fun Base(
navController: NavController,
mainViewModel: MainViewModel = viewModel(),
playerViewModel: PlayerViewModel = viewModel(),
playerViewModel: PlayerViewModel = hiltViewModel(),
extraDropdownItems: @Composable ((() -> Unit) -> Unit)? = null,
mainContent: @Composable (() -> Unit)
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,13 @@ import coil.compose.rememberImagePainter
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import me.vanpetegem.accentor.R
import me.vanpetegem.accentor.media.MediaSessionConnection

@Composable
fun ControlBar(mediaSessionConnection: MediaSessionConnection = viewModel()) {
fun ControlBar(playerViewModel: PlayerViewModel = viewModel()) {
val scope = rememberCoroutineScope()
val currentTrack by mediaSessionConnection.currentTrack.observeAsState()
val currentAlbum by mediaSessionConnection.currentAlbum.observeAsState()
val isPlaying by mediaSessionConnection.playing.observeAsState()
val currentTrack by playerViewModel.currentTrack.observeAsState()
val currentAlbum by playerViewModel.currentAlbum.observeAsState()
val isPlaying by playerViewModel.playing.observeAsState()
BottomAppBar(contentPadding = PaddingValues(end = 8.dp)) {
Image(
painter = if (currentAlbum?.image500 != null) {
Expand Down Expand Up @@ -64,31 +63,31 @@ fun ControlBar(mediaSessionConnection: MediaSessionConnection = viewModel()) {
}
IconButton(
onClick = {
scope.launch(IO) { mediaSessionConnection.previous() }
scope.launch(IO) { playerViewModel.previous() }
},
) {
Icon(painterResource(R.drawable.ic_previous), contentDescription = stringResource(R.string.previous))
}
if (isPlaying ?: false) {
IconButton(
onClick = {
scope.launch(IO) { mediaSessionConnection.pause() }
scope.launch(IO) { playerViewModel.pause() }
},
) {
Icon(painterResource(R.drawable.ic_pause), contentDescription = stringResource(R.string.pause))
}
} else {
IconButton(
onClick = {
scope.launch(IO) { mediaSessionConnection.play() }
scope.launch(IO) { playerViewModel.play() }
},
) {
Icon(painterResource(R.drawable.ic_play), contentDescription = stringResource(R.string.play))
}
}
IconButton(
onClick = {
scope.launch(IO) { mediaSessionConnection.next() }
scope.launch(IO) { playerViewModel.next() }
},
) {
Icon(painterResource(R.drawable.ic_next), contentDescription = stringResource(R.string.next))
Expand Down
37 changes: 18 additions & 19 deletions app/src/main/java/me/vanpetegem/accentor/ui/player/Controls.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,20 @@ import androidx.media2.common.SessionPlayer
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import me.vanpetegem.accentor.R
import me.vanpetegem.accentor.media.MediaSessionConnection
import me.vanpetegem.accentor.ui.util.Timer
import me.vanpetegem.accentor.util.formatTrackLength

@Composable
fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
fun Controls(playerViewModel: PlayerViewModel = viewModel()) {
val scope = rememberCoroutineScope()
val isPlaying by mediaSessionConnection.playing.observeAsState()
val shuffleMode by mediaSessionConnection.shuffleMode.observeAsState()
val repeatMode by mediaSessionConnection.repeatMode.observeAsState()
val isPlaying by playerViewModel.playing.observeAsState()
val shuffleMode by playerViewModel.shuffleMode.observeAsState()
val repeatMode by playerViewModel.repeatMode.observeAsState()
Column {
Row(modifier = Modifier.padding(start = 24.dp, end = 24.dp, top = 12.dp)) {
when (repeatMode) {
SessionPlayer.REPEAT_MODE_ALL -> {
IconButton(onClick = { scope.launch(IO) { mediaSessionConnection.setRepeatMode(SessionPlayer.REPEAT_MODE_ONE) } }) {
IconButton(onClick = { scope.launch(IO) { playerViewModel.setRepeatMode(SessionPlayer.REPEAT_MODE_ONE) } }) {
Icon(
painterResource(R.drawable.ic_repeat_all),
contentDescription = stringResource(R.string.repeat_all),
Expand All @@ -54,7 +53,7 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
}
}
SessionPlayer.REPEAT_MODE_ONE -> {
IconButton(onClick = { scope.launch(IO) { mediaSessionConnection.setRepeatMode(SessionPlayer.REPEAT_MODE_NONE) } }) {
IconButton(onClick = { scope.launch(IO) { playerViewModel.setRepeatMode(SessionPlayer.REPEAT_MODE_NONE) } }) {
Icon(
painterResource(R.drawable.ic_repeat_one),
contentDescription = stringResource(R.string.repeat_one),
Expand All @@ -64,7 +63,7 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
}
}
else -> {
IconButton(onClick = { scope.launch(IO) { mediaSessionConnection.setRepeatMode(SessionPlayer.REPEAT_MODE_ALL) } }) {
IconButton(onClick = { scope.launch(IO) { playerViewModel.setRepeatMode(SessionPlayer.REPEAT_MODE_ALL) } }) {
Icon(
painterResource(R.drawable.ic_repeat_off),
contentDescription = stringResource(R.string.repeat_off),
Expand All @@ -76,7 +75,7 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
Spacer(Modifier.weight(1f))
IconButton(
onClick = {
scope.launch(IO) { mediaSessionConnection.previous() }
scope.launch(IO) { playerViewModel.previous() }
},
) {
Icon(
Expand All @@ -88,7 +87,7 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
if (isPlaying ?: false) {
IconButton(
onClick = {
scope.launch(IO) { mediaSessionConnection.pause() }
scope.launch(IO) { playerViewModel.pause() }
},
) {
Icon(
Expand All @@ -100,7 +99,7 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
} else {
IconButton(
onClick = {
scope.launch(IO) { mediaSessionConnection.play() }
scope.launch(IO) { playerViewModel.play() }
},
) {
Icon(
Expand All @@ -112,7 +111,7 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
}
IconButton(
onClick = {
scope.launch(IO) { mediaSessionConnection.next() }
scope.launch(IO) { playerViewModel.next() }
},
) {
Icon(
Expand All @@ -124,7 +123,7 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
Spacer(Modifier.weight(1f))
when (shuffleMode) {
SessionPlayer.SHUFFLE_MODE_ALL -> {
IconButton(onClick = { scope.launch(IO) { mediaSessionConnection.setShuffleMode(SessionPlayer.SHUFFLE_MODE_NONE) } }) {
IconButton(onClick = { scope.launch(IO) { playerViewModel.setShuffleMode(SessionPlayer.SHUFFLE_MODE_NONE) } }) {
Icon(
painterResource(R.drawable.ic_shuffle_all),
contentDescription = stringResource(R.string.shuffle_all),
Expand All @@ -134,7 +133,7 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
}
}
else -> {
IconButton(onClick = { scope.launch(IO) { mediaSessionConnection.setShuffleMode(SessionPlayer.SHUFFLE_MODE_ALL) } }) {
IconButton(onClick = { scope.launch(IO) { playerViewModel.setShuffleMode(SessionPlayer.SHUFFLE_MODE_ALL) } }) {
Icon(
painterResource(R.drawable.ic_shuffle_none),
contentDescription = stringResource(R.string.shuffle_none),
Expand All @@ -145,19 +144,19 @@ fun Controls(mediaSessionConnection: MediaSessionConnection = viewModel()) {
}
}
Row(modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp), verticalAlignment = Alignment.CenterVertically) {
val buffering by mediaSessionConnection.buffering.observeAsState(false)
val currentPosition by mediaSessionConnection.currentPosition.observeAsState()
val buffering by playerViewModel.buffering.observeAsState(false)
val currentPosition by playerViewModel.currentPosition.observeAsState()
var seekPosition by remember { mutableStateOf<Int?>(null) }
val currentTrack by mediaSessionConnection.currentTrack.observeAsState()
val currentTrack by playerViewModel.currentTrack.observeAsState()
val trackLength = currentTrack?.length ?: 1
Timer { mediaSessionConnection.updateCurrentPosition() }
Timer { playerViewModel.updateCurrentPosition() }
Text(if (seekPosition != null) seekPosition.formatTrackLength() else currentPosition.formatTrackLength())
Slider(
seekPosition?.toFloat() ?: (currentPosition?.toFloat() ?: 0f),
onValueChange = { seekPosition = it.toInt() },
onValueChangeFinished = {
val positionCopy = seekPosition!!
scope.launch(IO) { mediaSessionConnection.seekTo(positionCopy) }
scope.launch(IO) { playerViewModel.seekTo(positionCopy) }
seekPosition = null
},
enabled = !buffering,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.rememberImagePainter
import me.vanpetegem.accentor.R
import me.vanpetegem.accentor.media.MediaSessionConnection

@Composable
fun CurrentTrackInfo(mediaSessionConnection: MediaSessionConnection = viewModel()) {
val currentTrack by mediaSessionConnection.currentTrack.observeAsState()
val currentAlbum by mediaSessionConnection.currentAlbum.observeAsState()
fun CurrentTrackInfo(playerViewModel: PlayerViewModel = viewModel()) {
val currentTrack by playerViewModel.currentTrack.observeAsState()
val currentAlbum by playerViewModel.currentAlbum.observeAsState()
Column(modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally) {
Image(
painter = if (currentAlbum?.image500 != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,11 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import kotlinx.coroutines.launch
import me.vanpetegem.accentor.media.MediaSessionConnection

@Composable
fun PlayerOverlay(
navController: NavController,
playerViewModel: PlayerViewModel = viewModel(),
mediaSessionConnection: MediaSessionConnection = viewModel(),
content: @Composable (() -> Unit)
) {
val scope = rememberCoroutineScope()
Expand All @@ -54,7 +52,7 @@ fun PlayerOverlay(
}
val anchors = mapOf(0f to true, height to false)
val showQueue by playerViewModel.showQueue.observeAsState()
val queueLength by mediaSessionConnection.queueLength.observeAsState()
val queueLength by playerViewModel.queueLength.observeAsState()
val showPlayer = (queueLength ?: 0) > 0
val isLandscape = (LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE)
val isMultiWindow = (LocalContext.current as Activity).isInMultiWindowMode()
Expand Down
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载