Skip to content

Commit

Permalink
initial media 3 work
Browse files Browse the repository at this point in the history
  • Loading branch information
brdunn committed Apr 8, 2023
1 parent deaf7f6 commit 168fb02
Show file tree
Hide file tree
Showing 20 changed files with 355 additions and 511 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/local.properties
/.idea
.DS_Store
/build
build
/app/release
/captures
.externalNativeBuild
Expand Down
8 changes: 3 additions & 5 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ dependencies {
implementation(libs.androidx.dataStore)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.preference.ktx)
implementation(libs.androidx.media)
implementation(libs.androidx.media3.exoplayer)
implementation(libs.androidx.media3.mediaSession)
implementation(libs.androidx.media3.ui)

implementation(libs.androidx.navigation.fragment)
implementation(libs.androidx.navigation.compose)
Expand All @@ -88,10 +90,6 @@ dependencies {

implementation(libs.material)

implementation(libs.exoplayer.core)
implementation(libs.exoplayer.ui)
implementation(libs.exoplayer.mediaSession)

implementation(libs.hilt.android)
kapt(libs.hilt.compiler)

Expand Down
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@

<service
android:name=".utils.MusicService"
android:foregroundServiceType="mediaPlayback"
android:exported="false">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
<action android:name="android.media.browse.MediaBrowserService"/>
<action android:name="androidx.media3.session.MediaSessionService" />
</intent-filter>
</service>
</application>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.devdunnapps.amplify.ui.album

import android.os.Bundle
import android.support.v4.media.session.PlaybackStateCompat
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
Expand All @@ -18,7 +16,6 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.io.Serializable
import javax.inject.Inject

@HiltViewModel
Expand Down Expand Up @@ -64,28 +61,21 @@ class AlbumViewModel @Inject constructor(
}

fun playSong(song: Song) {
val bundle = Bundle()
bundle.putSerializable("song", song)
musicServiceConnection.transportControls.sendCustomAction("play_song", bundle)
musicServiceConnection.playSong(song)
}

fun playAlbum(whenToPlay: WhenToPlay = WhenToPlay.NOW, shuffle: Boolean = false) {
val action = when (whenToPlay) {
WhenToPlay.NOW -> "play_songs_now"
WhenToPlay.NEXT -> "play_songs_next"
WhenToPlay.QUEUE -> "add_songs_to_queue"
}

val shuffleMode = if (shuffle) PlaybackStateCompat.SHUFFLE_MODE_ALL else PlaybackStateCompat.SHUFFLE_MODE_NONE
musicServiceConnection.transportControls.setShuffleMode(shuffleMode)
val songs = (_album.value as? Resource.Success)?.data?.songs ?: return

musicServiceConnection.transportControls.sendCustomAction(action, collectAlbumBundle())
}
if (shuffle)
musicServiceConnection.enableShuffleMode()
else
musicServiceConnection.disableShuffleMode()

private fun collectAlbumBundle(): Bundle {
return Bundle().apply {
val albumContent = _album.value as? Resource.Success<AlbumScreenUIModel> ?: return@apply
putSerializable("songs", albumContent.data.songs as Serializable)
when (whenToPlay) {
WhenToPlay.NOW -> musicServiceConnection.playSongs(songs)
WhenToPlay.NEXT -> musicServiceConnection.playSongsNext(songs)
WhenToPlay.QUEUE -> musicServiceConnection.addSongsToQueue(songs)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.devdunnapps.amplify.ui.artist

import android.os.Bundle
import android.support.v4.media.session.PlaybackStateCompat
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
Expand All @@ -19,7 +18,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.io.Serializable
import javax.inject.Inject

@HiltViewModel
Expand Down Expand Up @@ -85,18 +83,12 @@ class ArtistViewModel @Inject constructor(
fun playSong(song: Song) {
val bundle = Bundle()
bundle.putSerializable("song", song)
musicServiceConnection.transportControls.sendCustomAction("play_song", bundle)
musicServiceConnection.playSong(song)
}

fun shuffleArtist() {
musicServiceConnection.transportControls.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_ALL)
musicServiceConnection.transportControls.sendCustomAction("play_songs_now", collectAlbumBundle())
}

private fun collectAlbumBundle(): Bundle? {
val currentValue = _artistSongs.value as? Resource.Success ?: return null
return Bundle().apply {
putSerializable("songs", currentValue.data as Serializable)
}
val songs = (_artistSongs.value as? Resource.Success)?.data ?: return
musicServiceConnection.enableShuffleMode()
musicServiceConnection.playSongs(songs)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.devdunnapps.amplify.ui.artist.songs

import android.os.Bundle
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
Expand Down Expand Up @@ -42,8 +41,6 @@ class ArtistAllSongsViewModel @Inject constructor(
}

fun playSong(song: Song) {
val bundle = Bundle()
bundle.putSerializable("song", song)
musicServiceConnection.transportControls.sendCustomAction("play_song", bundle)
musicServiceConnection.playSong(song)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.devdunnapps.amplify.ui.main

import android.content.Intent
import android.media.session.PlaybackState
import android.os.Bundle
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.PlaybackStateCompat
import android.util.TypedValue
import android.view.View
import androidx.activity.viewModels
Expand Down Expand Up @@ -87,15 +86,13 @@ class MainActivity : AppCompatActivity() {

binding.nowPlayingBoxCollapsed.setContent {
Mdc3Theme {
val playbackState = viewModel.playbackState.collectAsState().value.state
val currentlyPlayingMetadata = viewModel.mediaMetadata.collectAsState().value

if (currentlyPlayingMetadata != NOTHING_PLAYING) {
NowPlayingCollapsed(
albumArtUrl = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI),
title = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE),
subtitle = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST),
isPlaying = playbackState == PlaybackStateCompat.STATE_PLAYING,
albumArtUrl = currentlyPlayingMetadata.artworkUri.toString(),
title = currentlyPlayingMetadata.title.toString(),
subtitle = currentlyPlayingMetadata.artist.toString(),
isPlaying = viewModel.isPlaying.collectAsState().value,
onPlayPauseClick = viewModel::togglePlaybackState,
onSkipClick = viewModel::skipToNext
)
Expand All @@ -118,7 +115,7 @@ class MainActivity : AppCompatActivity() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.playbackState.collect {
if (it.state == PlaybackStateCompat.STATE_PLAYING) {
if (it == PlaybackState.STATE_PLAYING) {
val marginInDp =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 64f, resources.displayMetrics).toInt()
(binding.navContentFrame.layoutParams as CoordinatorLayout.LayoutParams).setMargins(0, 0, 0, marginInDp)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.devdunnapps.amplify.ui.main

import android.support.v4.media.session.PlaybackStateCompat
import androidx.lifecycle.ViewModel
import com.devdunnapps.amplify.utils.MusicServiceConnection
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -10,19 +9,19 @@ import javax.inject.Inject
class MainActivityViewModel @Inject constructor(
private val musicServiceConnection: MusicServiceConnection
): ViewModel() {

var playbackState = musicServiceConnection.playbackState
var mediaMetadata = musicServiceConnection.nowPlaying
val isPlaying = musicServiceConnection.isPlaying
val playbackState = musicServiceConnection.playbackState
val mediaMetadata = musicServiceConnection.nowPlaying

fun togglePlaybackState() {
if (playbackState.value.state == PlaybackStateCompat.STATE_PLAYING) {
musicServiceConnection.transportControls.pause()
if (musicServiceConnection.isPlaying.value) {
musicServiceConnection.pause()
} else {
musicServiceConnection.transportControls.play()
musicServiceConnection.play()
}
}

fun skipToNext() {
musicServiceConnection.transportControls.skipToNext()
musicServiceConnection.skipToNext()
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.devdunnapps.amplify.ui.nowplaying

import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.PlaybackStateCompat
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
Expand Down Expand Up @@ -52,6 +50,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.media3.common.Player
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.devdunnapps.amplify.ui.utils.DynamicThemePrimaryColorsFromImage
Expand All @@ -73,20 +72,20 @@ fun NowPlayingScreen(
if (metadata == NOTHING_PLAYING)
return

val songDurationMillis = metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION)
val songDurationMillis = viewModel.duration.collectAsState().value
val mediaPosition = viewModel.mediaPosition.collectAsState().value
val playMode = viewModel.playbackState.collectAsState().value
val isPlaying = viewModel.isPlaying.collectAsState().value
val shuffleModel = viewModel.shuffleMode.collectAsState().value
val repeatMode = viewModel.repeatMode.collectAsState().value

NowPlayingHeader(
artworkUrl = metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI),
title = metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE),
subtitle = metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST),
artworkUrl = metadata.artworkUri.toString(),
title = metadata.title.toString(),
subtitle = metadata.artist.toString(),
onSeekToPosition = { viewModel.seekTo((it * 1000).toLong()) },
mediaPosition = mediaPosition,
songDurationMillis = songDurationMillis,
playMode = playMode,
isPlaying = isPlaying,
shuffleMode = shuffleModel,
repeatMode = repeatMode,
onToggleShuffleClick = viewModel::toggleShuffleState,
Expand All @@ -96,7 +95,7 @@ fun NowPlayingScreen(
onSkipNext = viewModel::skipToNext,
onCollapseNowPlaying = onCollapseNowPlaying,
onMenuClick = {
onNowPlayingMenuClick(viewModel.metadata.value.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID))
// onNowPlayingMenuClick(viewModel.metadata.value.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID))
}
)
}
Expand All @@ -109,8 +108,8 @@ private fun NowPlayingHeader(
onSeekToPosition: (Float) -> Unit,
mediaPosition: Long,
songDurationMillis: Long,
playMode: PlaybackStateCompat,
shuffleMode: Int,
isPlaying: Boolean,
shuffleMode: Boolean,
repeatMode: Int,
onToggleShuffleClick: () -> Unit,
onToggleRepeatClick: () -> Unit,
Expand Down Expand Up @@ -188,7 +187,7 @@ private fun NowPlayingHeader(
)

MediaButtonsRow(
playMode = playMode,
isPlaying = isPlaying,
shuffleMode = shuffleMode,
repeatMode = repeatMode,
onToggleShuffleClick = onToggleShuffleClick,
Expand Down Expand Up @@ -235,7 +234,6 @@ private fun NowPlayingProgressBar(
modifier: Modifier = Modifier
) {
Column(modifier = modifier) {

var sliderPosition by remember(mediaPosition) { mutableStateOf((mediaPosition / 1000).toFloat()) }
Slider(
value = sliderPosition,
Expand Down Expand Up @@ -278,8 +276,8 @@ private fun NowPlayingProgressBar(

@Composable
private fun MediaButtonsRow(
playMode: PlaybackStateCompat,
shuffleMode: Int,
isPlaying: Boolean,
shuffleMode: Boolean,
repeatMode: Int,
onToggleShuffleClick: () -> Unit,
onToggleRepeatClick: () -> Unit,
Expand All @@ -294,13 +292,9 @@ private fun MediaButtonsRow(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
) {
val shuffleModeIcon = when (shuffleMode) {
PlaybackStateCompat.SHUFFLE_MODE_ALL -> Icons.Filled.ShuffleOn
else -> Icons.Filled.Shuffle
}
IconButton(onClick = onToggleShuffleClick) {
Icon(
imageVector = shuffleModeIcon,
imageVector = if (shuffleMode) Icons.Filled.ShuffleOn else Icons.Filled.Shuffle,
contentDescription = null,
tint = MaterialTheme.colorScheme.onBackground
)
Expand All @@ -315,15 +309,13 @@ private fun MediaButtonsRow(
)
}

val playPauseIcon =
if (playMode.state == PlaybackStateCompat.STATE_PAUSED) Icons.Filled.PlayArrow else Icons.Filled.Pause
FloatingActionButton(
shape = CircleShape,
onClick = onTogglePlayPause,
modifier = Modifier.size(64.dp)
) {
Icon(
imageVector = playPauseIcon,
imageVector = if (isPlaying) Icons.Filled.Pause else Icons.Filled.PlayArrow,
contentDescription = null
)
}
Expand All @@ -338,8 +330,8 @@ private fun MediaButtonsRow(
}

val repeatModeIcon = when (repeatMode) {
PlaybackStateCompat.REPEAT_MODE_ONE -> Icons.Filled.RepeatOne
PlaybackStateCompat.REPEAT_MODE_ALL -> Icons.Filled.RepeatOn
Player.REPEAT_MODE_ONE -> Icons.Filled.RepeatOne
Player.REPEAT_MODE_ALL -> Icons.Filled.RepeatOn
else -> Icons.Filled.Repeat
}
IconButton(onClick = onToggleRepeatClick) {
Expand Down
Loading

0 comments on commit 168fb02

Please sign in to comment.