Skip to content

Commit fafc24f

Browse files
committed
Support predictive back, closes #10
1 parent 48572ec commit fafc24f

3 files changed

Lines changed: 35 additions & 12 deletions

File tree

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,14 @@
4545
android:maxSdkVersion="30" />
4646
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
4747

48-
<!-- TODO now that google fixed androidx, for enableOnBackInvokedCallback we need to fix
49-
1. bottom sheet hide/show (eg settings)
50-
2. bottom sheet -> home
51-
3. lyrics -> bottom sheet -->
5248
<application
5349
android:name=".logic.GramophoneApplication"
5450
android:allowBackup="true"
5551
android:appCategory="audio"
5652
android:dataExtractionRules="@xml/data_extraction_rules"
5753
android:fullBackupContent="@xml/backup_rules"
5854
android:icon="@mipmap/ic_launcher"
59-
android:enableOnBackInvokedCallback="false"
55+
android:enableOnBackInvokedCallback="true"
6056
android:label="@string/app_name"
6157
android:requestLegacyExternalStorage="true"
6258
android:supportsRtl="true"

app/src/main/java/org/akanework/gramophone/ui/MediaControllerViewModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ class MediaControllerViewModel(application: Application) : AndroidViewModel(appl
121121
controllerFuture = null
122122
}
123123

124+
// TODO reconsider whether onStop is a good place, as getting stopped is quite easy and
125+
// predictive back makes it obvious that we are reconnecting
124126
override fun onStop(owner: LifecycleOwner) {
125127
if (controllerFuture?.isDone == true) {
126128
if (controllerFuture?.isCancelled == false) {

app/src/main/java/org/akanework/gramophone/ui/components/PlayerBottomSheet.kt

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717

1818
package org.akanework.gramophone.ui.components
1919

20+
import android.animation.Animator
21+
import android.animation.AnimatorListenerAdapter
22+
import android.annotation.SuppressLint
2023
import android.content.Context
24+
import android.os.Build
2125
import android.os.Handler
2226
import android.os.Looper
2327
import android.util.AttributeSet
@@ -37,6 +41,8 @@ import androidx.core.view.WindowInsetsCompat
3741
import androidx.core.view.doOnLayout
3842
import androidx.core.view.doOnNextLayout
3943
import androidx.core.view.isVisible
44+
import androidx.fragment.app.Fragment
45+
import androidx.fragment.app.findFragment
4046
import androidx.lifecycle.DefaultLifecycleObserver
4147
import androidx.lifecycle.LifecycleOwner
4248
import androidx.media3.common.MediaItem
@@ -52,6 +58,7 @@ import coil3.size.Scale
5258
import com.google.android.material.bottomsheet.BottomSheetBehavior
5359
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
5460
import com.google.android.material.button.MaterialButton
61+
import com.google.android.material.motion.MaterialBottomContainerBackHelper
5562
import org.akanework.gramophone.BuildConfig
5663
import org.akanework.gramophone.R
5764
import org.akanework.gramophone.logic.clone
@@ -77,6 +84,8 @@ class PlayerBottomSheet private constructor(
7784

7885
private var lastDisposable: Disposable? = null
7986
private var standardBottomSheetBehavior: MyBottomSheetBehavior<FrameLayout>? = null
87+
@SuppressLint("RestrictedApi")
88+
private var lyricsBackHelper: MaterialBottomContainerBackHelper? = null
8089
private var bottomSheetBackCallback: OnBackPressedCallback? = null
8190
val fullPlayer: FullBottomSheet
8291
private val previewPlayer: View
@@ -100,6 +109,8 @@ class PlayerBottomSheet private constructor(
100109
set(value) {
101110
if (field != value) {
102111
field = value
112+
// TODO: this should be animated with predictive back once we switch to a better
113+
// back stack.
103114
standardBottomSheetBehavior?.state =
104115
if ((instance?.mediaItemCount ?: 0) > 0 && value) {
105116
if (standardBottomSheetBehavior?.state
@@ -218,37 +229,51 @@ class PlayerBottomSheet private constructor(
218229
fullPlayer.minimize = {
219230
standardBottomSheetBehavior!!.state = BottomSheetBehavior.STATE_COLLAPSED
220231
}
232+
@SuppressLint("RestrictedApi")
233+
lyricsBackHelper = MaterialBottomContainerBackHelper(fullPlayer.bottomSheetFullLyricView)
221234
bottomSheetBackCallback = object : OnBackPressedCallback(enabled = false) {
222235
override fun handleOnBackStarted(backEvent: BackEventCompat) {
223236
if (fullPlayer.bottomSheetFullLyricView.isVisible) {
224-
fullPlayer.bottomSheetFullLyricView.fadOutAnimation(FullBottomSheet.LYRIC_FADE_TRANSITION_SEC)
225-
fullPlayer.bottomSheetLyricButton.isChecked = false
237+
@SuppressLint("RestrictedApi")
238+
lyricsBackHelper!!.startBackProgress(backEvent)
226239
} else {
227240
standardBottomSheetBehavior!!.startBackProgress(backEvent)
228241
}
229242
}
230243

231244
override fun handleOnBackProgressed(backEvent: BackEventCompat) {
232245
if (fullPlayer.bottomSheetFullLyricView.isVisible) {
233-
// TODO
246+
@SuppressLint("RestrictedApi")
247+
lyricsBackHelper!!.updateBackProgress(backEvent)
234248
} else {
235249
standardBottomSheetBehavior!!.updateBackProgress(backEvent)
236250
}
237251
}
238252

239253
override fun handleOnBackPressed() {
240254
if (fullPlayer.bottomSheetFullLyricView.isVisible) {
241-
fullPlayer.bottomSheetFullLyricView.fadOutAnimation(FullBottomSheet.LYRIC_FADE_TRANSITION_SEC)
242-
fullPlayer.bottomSheetLyricButton.isChecked = false
255+
@SuppressLint("RestrictedApi")
256+
val backEvent = lyricsBackHelper!!.onHandleBackInvoked()
257+
if (backEvent == null || backEvent.progress == 0f
258+
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
259+
fullPlayer.bottomSheetFullLyricView.fadOutAnimation(FullBottomSheet.LYRIC_FADE_TRANSITION_SEC)
260+
return
261+
}
262+
@SuppressLint("RestrictedApi")
263+
lyricsBackHelper!!.finishBackProgressNotPersistent(backEvent, object : AnimatorListenerAdapter() {
264+
override fun onAnimationEnd(animation: Animator) {
265+
fullPlayer.bottomSheetFullLyricView.visibility = View.INVISIBLE
266+
}
267+
})
243268
} else {
244269
standardBottomSheetBehavior!!.handleBackInvoked()
245270
}
246271
}
247272

248273
override fun handleOnBackCancelled() {
249274
if (fullPlayer.bottomSheetFullLyricView.isVisible) {
250-
fullPlayer.bottomSheetFullLyricView.fadInAnimation(FullBottomSheet.LYRIC_FADE_TRANSITION_SEC)
251-
fullPlayer.bottomSheetLyricButton.isChecked = false
275+
@SuppressLint("RestrictedApi")
276+
lyricsBackHelper!!.cancelBackProgress()
252277
} else {
253278
standardBottomSheetBehavior!!.cancelBackProgress()
254279
}

0 commit comments

Comments
 (0)