Switch tracks by swipe on cover

This commit is contained in:
Koitharu 2023-06-30 12:36:14 +03:00
parent fcbce0fb98
commit 56a4102023
No known key found for this signature in database
GPG key ID: 8E861F8CE6E7CE27
6 changed files with 123 additions and 6 deletions

View file

@ -73,7 +73,7 @@ import org.oxycblt.auxio.util.getInteger
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
@AndroidEntryPoint @AndroidEntryPoint
class CoverView open class CoverView
@JvmOverloads @JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) : constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
FrameLayout(context, attrs, defStyleAttr) { FrameLayout(context, attrs, defStyleAttr) {

View file

@ -39,6 +39,7 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.playback.ui.StyledSeekBar import org.oxycblt.auxio.playback.ui.StyledSeekBar
import org.oxycblt.auxio.playback.ui.SwipeCoverView
import org.oxycblt.auxio.ui.ViewBindingFragment import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
@ -58,7 +59,8 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
class PlaybackPanelFragment : class PlaybackPanelFragment :
ViewBindingFragment<FragmentPlaybackPanelBinding>(), ViewBindingFragment<FragmentPlaybackPanelBinding>(),
Toolbar.OnMenuItemClickListener, Toolbar.OnMenuItemClickListener,
StyledSeekBar.Listener { StyledSeekBar.Listener,
SwipeCoverView.OnSwipeListener {
private val playbackModel: PlaybackViewModel by activityViewModels() private val playbackModel: PlaybackViewModel by activityViewModels()
private val musicModel: MusicViewModel by activityViewModels() private val musicModel: MusicViewModel by activityViewModels()
private val detailModel: DetailViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels()
@ -111,7 +113,7 @@ class PlaybackPanelFragment :
isSelected = true isSelected = true
setOnClickListener { navigateToCurrentAlbum() } setOnClickListener { navigateToCurrentAlbum() }
} }
binding.playbackCover.onSwipeListener = this
binding.playbackSeekBar.listener = this binding.playbackSeekBar.listener = this
// Set up actions // Set up actions
@ -191,6 +193,14 @@ class PlaybackPanelFragment :
playbackModel.seekTo(positionDs) playbackModel.seekTo(positionDs)
} }
override fun onSwipePrevious() {
playbackModel.prev()
}
override fun onSwipeNext() {
playbackModel.next()
}
private fun updateSong(song: Song?) { private fun updateSong(song: Song?) {
if (song == null) { if (song == null) {
// Nothing to do. // Nothing to do.

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2023 Auxio Project
* SwipeCoverView.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.playback.ui
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.GestureDetector.OnGestureListener
import android.view.MotionEvent
import android.view.ViewConfiguration
import androidx.annotation.AttrRes
import kotlin.math.abs
import org.oxycblt.auxio.image.CoverView
import org.oxycblt.auxio.util.isRtl
class SwipeCoverView
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
CoverView(context, attrs, defStyleAttr), OnGestureListener {
private val gestureDetector = GestureDetector(context, this)
private val viewConfig = ViewConfiguration.get(context)
var onSwipeListener: OnSwipeListener? = null
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
}
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
return gestureDetector.onGenericMotionEvent(event) || super.onGenericMotionEvent(event)
}
override fun onDown(e: MotionEvent): Boolean = true
override fun onShowPress(e: MotionEvent) = Unit
override fun onSingleTapUp(e: MotionEvent): Boolean = false
override fun onScroll(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean = false
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
e1 ?: return false
val diffY = e2.y - e1.y
val diffX = e2.x - e1.x
if (abs(diffX) > abs(diffY) &&
abs(diffX) > viewConfig.scaledTouchSlop &&
abs(velocityX) > viewConfig.scaledMinimumFlingVelocity
) {
if (diffX > 0) {
onSwipeRight()
} else {
onSwipeLeft()
}
return true
}
return false
}
override fun onLongPress(e: MotionEvent) = Unit
private fun onSwipeRight() {
onSwipeListener?.run { if (isRtl) onSwipeNext() else onSwipePrevious() }
}
private fun onSwipeLeft() {
onSwipeListener?.run { if (isRtl) onSwipePrevious() else onSwipeNext() }
}
interface OnSwipeListener {
fun onSwipePrevious()
fun onSwipeNext()
}
}

View file

@ -16,7 +16,7 @@
app:title="@string/lbl_playback" app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" /> tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.image.CoverView <org.oxycblt.auxio.playback.ui.SwipeCoverView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full" style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_medium" android:layout_margin="@dimen/spacing_medium"

View file

@ -16,7 +16,7 @@
app:title="@string/lbl_playback" app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" /> tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.image.CoverView <org.oxycblt.auxio.playback.ui.SwipeCoverView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full" style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_medium" android:layout_margin="@dimen/spacing_medium"

View file

@ -16,7 +16,7 @@
app:title="@string/lbl_playback" app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" /> tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.image.CoverView <org.oxycblt.auxio.playback.ui.SwipeCoverView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full" style="@style/Widget.Auxio.Image.Full"
android:layout_marginStart="@dimen/spacing_medium" android:layout_marginStart="@dimen/spacing_medium"