mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 04:52:32 +00:00
Experimental changes to allow seeking from TransportFragment.
This commit is contained in:
parent
1d00103b7f
commit
8cb85af8ed
@ -2,6 +2,7 @@ package io.casey.musikcube.remote.ui.shared.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
@ -14,12 +15,17 @@ import io.casey.musikcube.remote.ui.shared.extension.fallback
|
||||
import io.casey.musikcube.remote.ui.shared.extension.getColorCompat
|
||||
import io.casey.musikcube.remote.ui.shared.extension.topOfStack
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.PlaybackMixin
|
||||
import io.casey.musikcube.remote.ui.shared.view.InterceptTouchFrameLayout
|
||||
import me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||
|
||||
class TransportFragment: BaseFragment() {
|
||||
private lateinit var rootView: View
|
||||
private lateinit var buffering: View
|
||||
private lateinit var title: TextView
|
||||
private lateinit var playPause: TextView
|
||||
private lateinit var progress: MaterialProgressBar
|
||||
private val seekTracker = TouchTracker()
|
||||
private var seekOverride = -1
|
||||
|
||||
lateinit var playback: PlaybackMixin
|
||||
private set
|
||||
@ -30,6 +36,7 @@ class TransportFragment: BaseFragment() {
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
|
||||
{
|
||||
this.rootView = inflater.inflate(R.layout.transport_fragment, container, false)
|
||||
progress = this.rootView.findViewById(R.id.progress)
|
||||
bindEventHandlers()
|
||||
rebindUi()
|
||||
return this.rootView
|
||||
@ -43,6 +50,12 @@ class TransportFragment: BaseFragment() {
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
rebindUi()
|
||||
scheduleUpdateTime()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
handler.removeCallbacks(updateTimeRunnable)
|
||||
}
|
||||
|
||||
private fun bindEventHandlers() {
|
||||
@ -52,10 +65,10 @@ class TransportFragment: BaseFragment() {
|
||||
|
||||
this.buffering = this.rootView.findViewById(R.id.buffering)
|
||||
|
||||
val titleBar = this.rootView.findViewById<View>(R.id.title_bar)
|
||||
val titleBar = this.rootView.findViewById<InterceptTouchFrameLayout>(R.id.title_bar)
|
||||
|
||||
titleBar?.setOnClickListener {
|
||||
if (playback.service.state != PlaybackState.Stopped) {
|
||||
if (!seekTracker.processed && playback.service.state != PlaybackState.Stopped) {
|
||||
appCompatActivity.supportFragmentManager.run {
|
||||
when (topOfStack != PlayQueueFragment.TAG) {
|
||||
true -> Navigate.toPlayQueue(
|
||||
@ -70,13 +83,51 @@ class TransportFragment: BaseFragment() {
|
||||
}
|
||||
|
||||
titleBar?.setOnLongClickListener {
|
||||
activity?.let { a ->
|
||||
startActivity(MainActivity.getStartIntent(a))
|
||||
return@setOnLongClickListener true
|
||||
if (!seekTracker.processed) {
|
||||
activity?.let { a ->
|
||||
startActivity(MainActivity.getStartIntent(a))
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
titleBar?.setOnInterceptTouchEventListener(object: InterceptTouchFrameLayout.OnInterceptTouchEventListener {
|
||||
override fun onInterceptTouchEvent(view: InterceptTouchFrameLayout, ev: MotionEvent, disallowIntercept: Boolean): Boolean {
|
||||
return when (ev.action) {
|
||||
MotionEvent.ACTION_DOWN,
|
||||
MotionEvent.ACTION_MOVE,
|
||||
MotionEvent.ACTION_CANCEL,
|
||||
MotionEvent.ACTION_UP -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTouchEvent(view: InterceptTouchFrameLayout, ev: MotionEvent): Boolean {
|
||||
seekTracker.update(ev)
|
||||
if (seekTracker.processed) {
|
||||
when (ev.action) {
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
seekOverride = (
|
||||
seekTracker.lastX.toFloat() /
|
||||
view.width.toFloat() *
|
||||
playback.service.duration.toFloat()).toInt()
|
||||
rebindProgress()
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
if (seekOverride >= 0) {
|
||||
playback.service.seekTo(seekOverride.toDouble())
|
||||
seekOverride = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
view.defaultOnTouchEvent(ev)
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
this.rootView.findViewById<View>(R.id.button_prev)?.setOnClickListener {
|
||||
playback.service.prev()
|
||||
}
|
||||
@ -97,6 +148,27 @@ class TransportFragment: BaseFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun rebindProgress() {
|
||||
if (playback.service.state == PlaybackState.Stopped) {
|
||||
progress.progress = 0
|
||||
progress.secondaryProgress = 0
|
||||
}
|
||||
else {
|
||||
val buffered = playback.service.bufferedTime.toInt()
|
||||
val total = playback.service.duration.toInt()
|
||||
progress.max = total
|
||||
progress.secondaryProgress = if (buffered >= 100) 0 else buffered
|
||||
|
||||
progress.progress = if (seekTracker.down && seekOverride >= 0) {
|
||||
seekOverride
|
||||
}
|
||||
else {
|
||||
playback.service.currentTime.toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun rebindUi() {
|
||||
val state = playback.service.state
|
||||
|
||||
@ -115,6 +187,18 @@ class TransportFragment: BaseFragment() {
|
||||
title.text = fallback(playback.service.playingTrack.title, defaultValue)
|
||||
title.setTextColor(getColorCompat(R.color.theme_green))
|
||||
}
|
||||
|
||||
rebindProgress()
|
||||
}
|
||||
|
||||
private fun scheduleUpdateTime() {
|
||||
handler.removeCallbacks(updateTimeRunnable)
|
||||
handler.postDelayed(updateTimeRunnable, 1000L)
|
||||
}
|
||||
|
||||
private val updateTimeRunnable = Runnable {
|
||||
rebindProgress()
|
||||
scheduleUpdateTime()
|
||||
}
|
||||
|
||||
private val playbackListener: () -> Unit = {
|
||||
@ -122,6 +206,56 @@ class TransportFragment: BaseFragment() {
|
||||
modelChangedListener?.invoke(this@TransportFragment)
|
||||
}
|
||||
|
||||
private class TouchTracker {
|
||||
var down = false
|
||||
var startX = 0
|
||||
var startY = 0
|
||||
var totalDx = 0
|
||||
var totalDy = 0
|
||||
var lastX = 0
|
||||
var lastY = 0
|
||||
|
||||
fun reset() {
|
||||
down = false
|
||||
startX = 0
|
||||
startY = 0
|
||||
totalDx = 0
|
||||
totalDy = 0
|
||||
lastX = 0
|
||||
lastY = 0
|
||||
}
|
||||
|
||||
fun update(ev: MotionEvent) {
|
||||
when (ev.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
reset()
|
||||
down = true
|
||||
startX = ev.x.toInt()
|
||||
startY = ev.y.toInt()
|
||||
lastX = startX
|
||||
lastY = startY
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val x = ev.x.toInt()
|
||||
val y = ev.y.toInt()
|
||||
totalDx += Math.abs(lastX - x)
|
||||
totalDy += Math.abs(lastY - y)
|
||||
lastX = x
|
||||
lastY = y
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
down = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val processed: Boolean
|
||||
get() { return totalDx >= 24 }
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "TransportFragment"
|
||||
fun create(): TransportFragment = TransportFragment()
|
||||
|
@ -0,0 +1,51 @@
|
||||
package io.casey.musikcube.remote.ui.shared.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.widget.FrameLayout
|
||||
|
||||
class InterceptTouchFrameLayout : FrameLayout {
|
||||
private var disallowIntercept: Boolean = false
|
||||
private var interceptor: OnInterceptTouchEventListener = DEFAULT_INTERCEPTOR
|
||||
|
||||
interface OnInterceptTouchEventListener {
|
||||
fun onInterceptTouchEvent(view: InterceptTouchFrameLayout, ev: MotionEvent, disallowIntercept: Boolean): Boolean
|
||||
fun onTouchEvent(view: InterceptTouchFrameLayout, event: MotionEvent): Boolean
|
||||
}
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||
|
||||
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
|
||||
parent.requestDisallowInterceptTouchEvent(disallowIntercept)
|
||||
this.disallowIntercept = disallowIntercept
|
||||
}
|
||||
|
||||
fun setOnInterceptTouchEventListener(interceptor: OnInterceptTouchEventListener?) {
|
||||
this.interceptor = interceptor ?: DEFAULT_INTERCEPTOR
|
||||
}
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
||||
val stealTouchEvent = interceptor.onInterceptTouchEvent(this, ev, disallowIntercept)
|
||||
return stealTouchEvent && !disallowIntercept || super.onInterceptTouchEvent(ev)
|
||||
}
|
||||
|
||||
override fun onTouchEvent(ev: MotionEvent): Boolean {
|
||||
val handled = interceptor.onTouchEvent(this, ev)
|
||||
return handled || super.onTouchEvent(ev)
|
||||
}
|
||||
|
||||
fun defaultOnInterceptTouchEvent(ev: MotionEvent): Boolean = super.onInterceptTouchEvent(ev)
|
||||
fun defaultOnTouchEvent(ev: MotionEvent): Boolean = super.onTouchEvent(ev)
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_INTERCEPTOR = object: OnInterceptTouchEventListener {
|
||||
override fun onInterceptTouchEvent(view: InterceptTouchFrameLayout, ev: MotionEvent, disallowIntercept: Boolean): Boolean = false
|
||||
override fun onTouchEvent(view: InterceptTouchFrameLayout, event: MotionEvent): Boolean = false
|
||||
}
|
||||
}
|
||||
}
|
@ -52,11 +52,11 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="2dp"/>
|
||||
|
||||
<FrameLayout
|
||||
<io.casey.musikcube.remote.ui.shared.view.InterceptTouchFrameLayout
|
||||
android:id="@+id/title_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="32dp"
|
||||
android:minHeight="28dp"
|
||||
android:background="@drawable/category_button"
|
||||
android:transitionName="play_queue_transition">
|
||||
|
||||
@ -105,6 +105,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</io.casey.musikcube.remote.ui.shared.view.InterceptTouchFrameLayout>
|
||||
|
||||
</LinearLayout>
|
Loading…
Reference in New Issue
Block a user