diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d8156e0..894d3be 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -180,7 +180,9 @@ dependencies { implementation("androidx.preference:preference-ktx:1.2.0") implementation("androidx.recyclerview:recyclerview:1.2.1") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") - implementation("com.google.android.material:material:1.8.0") + implementation("com.google.android.material:material:1.9.0") { + exclude("androidx.constraintlayout") + } implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("com.google.android.exoplayer:exoplayer-core:2.18.1") diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/NowPlayingFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/NowPlayingFragment.kt index 8973a9a..23d4211 100644 --- a/app/src/main/java/audio/funkwhale/ffa/fragments/NowPlayingFragment.kt +++ b/app/src/main/java/audio/funkwhale/ffa/fragments/NowPlayingFragment.kt @@ -1,6 +1,7 @@ package audio.funkwhale.ffa.fragments import android.os.Bundle +import android.util.Log import android.view.Gravity import android.view.View import android.widget.SeekBar @@ -8,8 +9,13 @@ import android.widget.SeekBar.OnSeekBarChangeListener import androidx.appcompat.widget.PopupMenu import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.asLiveData import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.liveData +import androidx.lifecycle.map import androidx.navigation.fragment.findNavController import audio.funkwhale.ffa.MainNavDirections import audio.funkwhale.ffa.R @@ -99,10 +105,6 @@ class NowPlayingFragment: Fragment(R.layout.fragment_now_playing) { CommandBus.get().collect { onCommand(it) } } - lifecycleScope.launch(Dispatchers.Main) { - EventBus.get().collect { onEvent(it) } - } - lifecycleScope.launch(Dispatchers.Main) { ProgressBus.get().collect { onProgress(it) } } @@ -135,12 +137,6 @@ class NowPlayingFragment: Fragment(R.layout.fragment_now_playing) { else -> {} } - private fun onEvent(event: Event): Unit = when (event) { - is Event.Buffering -> viewModel.isBuffering.postValue(event.value) - is Event.StateChanged -> viewModel.isPlaying.postValue(event.playing) - else -> {} - } - private fun onFavorite() { val currentTrack = viewModel.currentTrack.value ?: return diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt b/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt index 0dc544e..60ff098 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt @@ -12,6 +12,7 @@ import android.media.MediaMetadata import android.os.Build import android.os.IBinder import android.support.v4.media.MediaMetadataCompat +import android.util.Log import android.view.KeyEvent import androidx.core.app.NotificationManagerCompat import androidx.media.session.MediaButtonReceiver @@ -468,8 +469,11 @@ class PlayerService : Service() { override fun onPlaybackStateChanged(playbackState: Int) { super.onPlaybackStateChanged(playbackState) - EventBus.send(Event.Buffering(playbackState == Player.STATE_BUFFERING)) + when (playbackState) { + Player.STATE_BUFFERING -> { + EventBus.send(Event.Buffering(true)) + } Player.STATE_ENDED -> { setPlaybackState(false) @@ -488,6 +492,10 @@ class PlayerService : Service() { mediaControlsManager.remove() } } + + Player.STATE_READY -> { + EventBus.send(Event.Buffering(false)) + } } } diff --git a/app/src/main/java/audio/funkwhale/ffa/viewmodel/NowPlayingViewModel.kt b/app/src/main/java/audio/funkwhale/ffa/viewmodel/NowPlayingViewModel.kt index 4a972ae..f834949 100644 --- a/app/src/main/java/audio/funkwhale/ffa/viewmodel/NowPlayingViewModel.kt +++ b/app/src/main/java/audio/funkwhale/ffa/viewmodel/NowPlayingViewModel.kt @@ -2,27 +2,48 @@ package audio.funkwhale.ffa.viewmodel import android.app.Application import android.content.Context -import android.graphics.Bitmap -import android.graphics.drawable.Drawable +import android.util.Log import androidx.appcompat.content.res.AppCompatResources -import androidx.core.graphics.drawable.toDrawable import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.asLiveData import androidx.lifecycle.distinctUntilChanged +import androidx.lifecycle.liveData import androidx.lifecycle.map +import androidx.lifecycle.viewModelScope import audio.funkwhale.ffa.FFA import audio.funkwhale.ffa.R import audio.funkwhale.ffa.model.Track -import audio.funkwhale.ffa.utils.CoverArt -import audio.funkwhale.ffa.utils.maybeNormalizeUrl +import audio.funkwhale.ffa.utils.Event +import audio.funkwhale.ffa.utils.EventBus import com.google.android.exoplayer2.Player -import com.squareup.picasso.Picasso -import com.squareup.picasso.Target +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds class NowPlayingViewModel(app: Application) : AndroidViewModel(app) { - val isBuffering = MutableLiveData(false) - val isPlaying = MutableLiveData(false) + val isBuffering = EventBus.get() + .filter { it is Event.Buffering } + .map { (it as Event.Buffering).value } + .stateIn(viewModelScope, SharingStarted.Lazily, false) + .asLiveData(viewModelScope.coroutineContext) + .distinctUntilChanged() + + val isPlaying = EventBus.get() + .filter { it is Event.StateChanged } + .map { (it as Event.StateChanged).playing } + .stateIn(viewModelScope, SharingStarted.Lazily, false) + .asLiveData(viewModelScope.coroutineContext) + .distinctUntilChanged() + val repeatMode = MutableLiveData(0) val progress = MutableLiveData(0) val currentTrack = MutableLiveData(null) @@ -32,6 +53,7 @@ class NowPlayingViewModel(app: Application) : AndroidViewModel(app) { // Calling distinctUntilChanged() prevents triggering an event when the track hasn't changed val currentTrackTitle = currentTrack.distinctUntilChanged().map { it?.title ?: "" } val currentTrackArtist = currentTrack.distinctUntilChanged().map { it?.artist?.name ?: "" } + // Not calling distinctUntilChanged() here as we need to process every event val isCurrentTrackFavorite = currentTrack.map { it?.favorite ?: false diff --git a/app/src/main/res/xml/fragment_now_playing_scene.xml b/app/src/main/res/xml/fragment_now_playing_scene.xml index 8044949..7a4ae03 100644 --- a/app/src/main/res/xml/fragment_now_playing_scene.xml +++ b/app/src/main/res/xml/fragment_now_playing_scene.xml @@ -13,6 +13,14 @@ + + @@ -22,7 +30,14 @@ motion:layout_constraintStart_toStartOf="@id/detail_image_placeholder" motion:layout_constraintTop_toBottomOf="@id/detail_image_placeholder" motion:layout_constraintTop_toTopOf="@id/detail_image_placeholder" - motion:transitionEasing="accelerate" + /> + + @@ -53,6 +68,13 @@ motion:curveFit="spline" /> + +