Browse Source

Fix buffering progress bar display

gradle-v8
Christophe Henry 12 months ago
parent
commit
31908b6175
  1. 4
      app/build.gradle.kts
  2. 16
      app/src/main/java/audio/funkwhale/ffa/fragments/NowPlayingFragment.kt
  3. 10
      app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt
  4. 40
      app/src/main/java/audio/funkwhale/ffa/viewmodel/NowPlayingViewModel.kt
  5. 24
      app/src/main/res/xml/fragment_now_playing_scene.xml

4
app/build.gradle.kts

@ -180,7 +180,9 @@ dependencies {
implementation("androidx.preference:preference-ktx:1.2.0") implementation("androidx.preference:preference-ktx:1.2.0")
implementation("androidx.recyclerview:recyclerview:1.2.1") implementation("androidx.recyclerview:recyclerview:1.2.1")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") 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("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("com.google.android.exoplayer:exoplayer-core:2.18.1") implementation("com.google.android.exoplayer:exoplayer-core:2.18.1")

16
app/src/main/java/audio/funkwhale/ffa/fragments/NowPlayingFragment.kt

@ -1,6 +1,7 @@
package audio.funkwhale.ffa.fragments package audio.funkwhale.ffa.fragments
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.Gravity import android.view.Gravity
import android.view.View import android.view.View
import android.widget.SeekBar import android.widget.SeekBar
@ -8,8 +9,13 @@ import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asLiveData
import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.liveData
import androidx.lifecycle.map
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import audio.funkwhale.ffa.MainNavDirections import audio.funkwhale.ffa.MainNavDirections
import audio.funkwhale.ffa.R import audio.funkwhale.ffa.R
@ -99,10 +105,6 @@ class NowPlayingFragment: Fragment(R.layout.fragment_now_playing) {
CommandBus.get().collect { onCommand(it) } CommandBus.get().collect { onCommand(it) }
} }
lifecycleScope.launch(Dispatchers.Main) {
EventBus.get().collect { onEvent(it) }
}
lifecycleScope.launch(Dispatchers.Main) { lifecycleScope.launch(Dispatchers.Main) {
ProgressBus.get().collect { onProgress(it) } ProgressBus.get().collect { onProgress(it) }
} }
@ -135,12 +137,6 @@ class NowPlayingFragment: Fragment(R.layout.fragment_now_playing) {
else -> {} 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() { private fun onFavorite() {
val currentTrack = viewModel.currentTrack.value ?: return val currentTrack = viewModel.currentTrack.value ?: return

10
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.Build
import android.os.IBinder import android.os.IBinder
import android.support.v4.media.MediaMetadataCompat import android.support.v4.media.MediaMetadataCompat
import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.media.session.MediaButtonReceiver import androidx.media.session.MediaButtonReceiver
@ -468,8 +469,11 @@ class PlayerService : Service() {
override fun onPlaybackStateChanged(playbackState: Int) { override fun onPlaybackStateChanged(playbackState: Int) {
super.onPlaybackStateChanged(playbackState) super.onPlaybackStateChanged(playbackState)
EventBus.send(Event.Buffering(playbackState == Player.STATE_BUFFERING))
when (playbackState) { when (playbackState) {
Player.STATE_BUFFERING -> {
EventBus.send(Event.Buffering(true))
}
Player.STATE_ENDED -> { Player.STATE_ENDED -> {
setPlaybackState(false) setPlaybackState(false)
@ -488,6 +492,10 @@ class PlayerService : Service() {
mediaControlsManager.remove() mediaControlsManager.remove()
} }
} }
Player.STATE_READY -> {
EventBus.send(Event.Buffering(false))
}
} }
} }

40
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.app.Application
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.util.Log
import android.graphics.drawable.Drawable
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.core.graphics.drawable.toDrawable
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asLiveData
import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.liveData
import androidx.lifecycle.map import androidx.lifecycle.map
import androidx.lifecycle.viewModelScope
import audio.funkwhale.ffa.FFA import audio.funkwhale.ffa.FFA
import audio.funkwhale.ffa.R import audio.funkwhale.ffa.R
import audio.funkwhale.ffa.model.Track import audio.funkwhale.ffa.model.Track
import audio.funkwhale.ffa.utils.CoverArt import audio.funkwhale.ffa.utils.Event
import audio.funkwhale.ffa.utils.maybeNormalizeUrl import audio.funkwhale.ffa.utils.EventBus
import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.Player
import com.squareup.picasso.Picasso import kotlinx.coroutines.FlowPreview
import com.squareup.picasso.Target 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) { class NowPlayingViewModel(app: Application) : AndroidViewModel(app) {
val isBuffering = MutableLiveData(false) val isBuffering = EventBus.get()
val isPlaying = MutableLiveData(false) .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 repeatMode = MutableLiveData(0)
val progress = MutableLiveData(0) val progress = MutableLiveData(0)
val currentTrack = MutableLiveData<Track?>(null) val currentTrack = MutableLiveData<Track?>(null)
@ -32,6 +53,7 @@ class NowPlayingViewModel(app: Application) : AndroidViewModel(app) {
// Calling distinctUntilChanged() prevents triggering an event when the track hasn't changed // Calling distinctUntilChanged() prevents triggering an event when the track hasn't changed
val currentTrackTitle = currentTrack.distinctUntilChanged().map { it?.title ?: "" } val currentTrackTitle = currentTrack.distinctUntilChanged().map { it?.title ?: "" }
val currentTrackArtist = currentTrack.distinctUntilChanged().map { it?.artist?.name ?: "" } val currentTrackArtist = currentTrack.distinctUntilChanged().map { it?.artist?.name ?: "" }
// Not calling distinctUntilChanged() here as we need to process every event // Not calling distinctUntilChanged() here as we need to process every event
val isCurrentTrackFavorite = currentTrack.map { val isCurrentTrackFavorite = currentTrack.map {
it?.favorite ?: false it?.favorite ?: false

24
app/src/main/res/xml/fragment_now_playing_scene.xml

@ -13,6 +13,14 @@
<Constraint android:id="@id/constraint_layout_placeholder"> <Constraint android:id="@id/constraint_layout_placeholder">
<PropertySet android:visibility="visible" /> <PropertySet android:visibility="visible" />
</Constraint> </Constraint>
<!--
I don't know why MotionLayout tries to control visibility for the buffer progress bar,
but it's messing with its display…
-->
<ConstraintOverride
android:id="@id/now_playing_buffering"
motion:visibilityMode="ignore"
/>
</ConstraintSet> </ConstraintSet>
<ConstraintSet android:id="@+id/end"> <ConstraintSet android:id="@+id/end">
@ -22,7 +30,14 @@
motion:layout_constraintStart_toStartOf="@id/detail_image_placeholder" motion:layout_constraintStart_toStartOf="@id/detail_image_placeholder"
motion:layout_constraintTop_toBottomOf="@id/detail_image_placeholder" motion:layout_constraintTop_toBottomOf="@id/detail_image_placeholder"
motion:layout_constraintTop_toTopOf="@id/detail_image_placeholder" motion:layout_constraintTop_toTopOf="@id/detail_image_placeholder"
motion:transitionEasing="accelerate" />
<!--
I don't know why MotionLayout tries to control visibility for the buffer progress bar,
but it's messing with its display…
-->
<ConstraintOverride
android:id="@id/now_playing_buffering"
motion:visibilityMode="ignore"
/> />
<Constraint android:id="@id/now_playing_progress"> <Constraint android:id="@id/now_playing_progress">
<PropertySet android:alpha="0" android:visibility="gone" /> <PropertySet android:alpha="0" android:visibility="gone" />
@ -53,6 +68,13 @@
motion:curveFit="spline" motion:curveFit="spline"
/> />
<KeyPosition
motion:percentX="1"
motion:framePosition="50"
motion:motionTarget="@id/now_playing_buffering"
motion:curveFit="spline"
/>
<KeyAttribute <KeyAttribute
android:alpha="0" android:alpha="0"
motion:framePosition="10" motion:framePosition="10"

Loading…
Cancel
Save