diff options
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/views')
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt | 63 | ||||
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt | 49 |
2 files changed, 80 insertions, 32 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt index c5508a4d..639dc9ba 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt @@ -8,10 +8,12 @@ import android.util.AttributeSet import android.view.GestureDetector import android.view.MotionEvent import android.view.View +import ca.allanwang.kau.utils.AnimHolder import ca.allanwang.kau.utils.dpToPx import ca.allanwang.kau.utils.scaleXY import com.devbrackets.android.exomedia.ui.widget.VideoView import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.ProgressAnimator /** * Created by Allan Wang on 2017-10-13. @@ -29,10 +31,10 @@ class FrostVideoView @JvmOverloads constructor( private inline val v get() = videoViewImpl - var backgroundView: View? = null var onFinishedListener: () -> Unit = {} - lateinit var viewerContract: FrostVideoViewerContract + private lateinit var viewerContract: FrostVideoViewerContract lateinit var containerContract: FrostVideoContainerContract + var repeat: Boolean = false private val videoDimensions = PointF(0f, 0f) @@ -47,8 +49,8 @@ class FrostVideoView @JvmOverloads constructor( private val SWIPE_TO_CLOSE_HORIZONTAL_THRESHOLD = 2f.dpToPx private val SWIPE_TO_CLOSE_VERTICAL_THRESHOLD = 5f.dpToPx private val SWIPE_TO_CLOSE_OFFSET_THRESHOLD = 75f.dpToPx - val ANIMATION_DURATION = 300L - private val FAST_ANIMATION_DURATION = 100L + const val ANIMATION_DURATION = 200L + private const val FAST_ANIMATION_DURATION = 100L } private var videoBounds = RectF() @@ -59,19 +61,32 @@ class FrostVideoView @JvmOverloads constructor( if (videoDimensions.x <= 0f || videoDimensions.y <= 0f) return L.d("Attempted to toggle video expansion when points have not been finalized") field = value + val origX = translationX + val origY = translationY + val origScale = scaleX if (field) { - animate().scaleXY(1f).translationX(0f).translationY(0f).setDuration(ANIMATION_DURATION).withStartAction { - backgroundView?.animate()?.alpha(1f)?.setDuration(ANIMATION_DURATION) - viewerContract.onFade(1f, ANIMATION_DURATION) - }.withEndAction { - if (!isPlaying) showControls() + ProgressAnimator.ofFloat { + duration = ANIMATION_DURATION + interpolator = AnimHolder.fastOutSlowInInterpolator(context) + withAnimator { viewerContract.onExpand(it) } + withAnimator(origScale, 1f) { scaleXY = it } + withAnimator(origX, 0f) { translationX = it } + withAnimator(origY, 0f) { translationY = it } + withEndAction { + if (!isPlaying) showControls() + else viewerContract.onControlsHidden() + } } } else { hideControls() val (scale, tX, tY) = mapBounds() - animate().scaleXY(scale).translationX(tX).translationY(tY).setDuration(ANIMATION_DURATION).withStartAction { - backgroundView?.animate()?.alpha(0f)?.setDuration(ANIMATION_DURATION) - viewerContract.onFade(0f, ANIMATION_DURATION) + ProgressAnimator.ofFloat { + duration = ANIMATION_DURATION + interpolator = AnimHolder.fastOutSlowInInterpolator(context) + withAnimatorInv { viewerContract.onExpand(it) } + withAnimator(origScale, scale) { scaleXY = it } + withAnimator(origX, tX) { translationX = it } + withAnimator(origY, tY) { translationY = it } } } } @@ -110,16 +125,28 @@ class FrostVideoView @JvmOverloads constructor( if (isExpanded) showControls() } setOnCompletionListener { - viewerContract.onVideoComplete() + if (repeat) restart() + else viewerContract.onVideoComplete() } setOnTouchListener(FrameTouchListener(context)) v.setOnTouchListener(VideoTouchListener(context)) setOnVideoSizedChangedListener { intrinsicWidth, intrinsicHeight -> val ratio = Math.min(width.toFloat() / intrinsicWidth, height.toFloat() / intrinsicHeight.toFloat()) + /** + * Only remap if not expanded and if dimensions have changed + */ + val shouldRemap = !isExpanded + && (videoDimensions.x != ratio * intrinsicWidth || videoDimensions.y != ratio * intrinsicHeight) videoDimensions.set(ratio * intrinsicWidth, ratio * intrinsicHeight) + if (shouldRemap) updateLocation() } } + fun setViewerContract(contract: FrostVideoViewerContract) { + this.viewerContract = contract + videoControls?.setVisibilityListener(viewerContract) + } + fun jumpToStart() { pause() v.seekTo(0) @@ -136,7 +163,7 @@ class FrostVideoView @JvmOverloads constructor( override fun restart(): Boolean { videoUri ?: return false - if (videoViewImpl.restart() && isExpanded) { + if (videoViewImpl.restart() && isExpanded && !repeat) { videoControls?.showLoading(true) return true } @@ -163,9 +190,11 @@ class FrostVideoView @JvmOverloads constructor( fun destroy() { stopPlayback() if (alpha > 0f) - animate().alpha(0f).setDuration(FAST_ANIMATION_DURATION).withEndAction { onFinishedListener() }.withStartAction { - viewerContract.onFade(0f, FAST_ANIMATION_DURATION) - }.start() + ProgressAnimator.ofFloat(alpha, 0f) { + duration = FAST_ANIMATION_DURATION + withAnimator { alpha = it } + withEndAction { onFinishedListener() } + } else onFinishedListener() } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt index bf4df8fe..3a773288 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt @@ -13,6 +13,7 @@ import android.view.ViewTreeObserver import android.widget.FrameLayout import android.widget.ImageView import ca.allanwang.kau.utils.* +import com.devbrackets.android.exomedia.listener.VideoControlsVisibilityListener import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.pitchedapps.frost.R import com.pitchedapps.frost.facebook.formattedFbUrl @@ -35,17 +36,21 @@ class FrostVideoViewer @JvmOverloads constructor( companion object { /** + * Matches VideoControls.CONTROL_VISIBILITY_ANIMATION_LENGTH + */ + private const val CONTROL_ANIMATION_DURATION = 300L + + /** * Simplified binding to add video to layout, and remove it when finished * This is under the assumption that the container allows for overlays, * such as a FrameLayout */ - fun showVideo(url: String, contract: FrostVideoContainerContract): FrostVideoViewer { + fun showVideo(url: String, repeat: Boolean, contract: FrostVideoContainerContract): FrostVideoViewer { val container = contract.videoContainer val videoViewer = FrostVideoViewer(container.context) container.addView(videoViewer) videoViewer.bringToFront() - L.d("Create video view", url) - videoViewer.setVideo(url) + videoViewer.setVideo(url, repeat) videoViewer.video.containerContract = contract videoViewer.video.onFinishedListener = { container.removeView(videoViewer); contract.onVideoFinished() } return videoViewer @@ -56,11 +61,9 @@ class FrostVideoViewer @JvmOverloads constructor( inflate(R.layout.view_video, true) alpha = 0f background.setBackgroundColor(if (Prefs.bgColor.isColorDark) Prefs.bgColor.withMinAlpha(200) else Color.BLACK) - video.backgroundView = background - video.viewerContract = this + video.setViewerContract(this) video.pause() toolbar.inflateMenu(R.menu.menu_video) - toolbar.setBackgroundColor(Prefs.headerColor) context.setMenuIcons(toolbar.menu, Prefs.iconColor, R.id.action_pip to GoogleMaterial.Icon.gmd_picture_in_picture_alt, R.id.action_download to GoogleMaterial.Icon.gmd_file_download @@ -77,12 +80,14 @@ class FrostVideoViewer @JvmOverloads constructor( video.restart() restarter.fadeOut { restarter.gone() } } -// toolbar.setOnTouchListener { _, event -> video.shouldParentAcceptTouch(event) } } - fun setVideo(url: String) { + fun setVideo(url: String, repeat: Boolean = false) { + val formattedUrl = url.formattedFbUrl + L.d("Load video view; repeat: $repeat", url) animate().alpha(1f).setDuration(FrostVideoView.ANIMATION_DURATION).start() - video.setVideoURI(Uri.parse(url.formattedFbUrl)) + video.setVideoURI(Uri.parse(formattedUrl)) + video.repeat = repeat } /** @@ -106,10 +111,9 @@ class FrostVideoViewer @JvmOverloads constructor( * ------------------------------------------------------------- */ - override fun onFade(alpha: Float, duration: Long) { - toolbar.visible().animate().alpha(alpha).setDuration(duration).withEndAction { - if (alpha == 0f) toolbar.gone() - } + override fun onExpand(progress: Float) { + toolbar.goneIf(progress == 0f).alpha = progress + background.alpha = progress } override fun onSingleTapConfirmed(event: MotionEvent): Boolean { @@ -134,11 +138,26 @@ class FrostVideoViewer @JvmOverloads constructor( }) } + override fun onControlsShown() { + if (video.isExpanded) + toolbar.fadeIn(duration = CONTROL_ANIMATION_DURATION, onStart = { toolbar.visible() }) + } + + override fun onControlsHidden() { + if (!toolbar.isGone) + toolbar.fadeOut(duration = CONTROL_ANIMATION_DURATION) { toolbar.gone() } + } + } -interface FrostVideoViewerContract { +interface FrostVideoViewerContract : VideoControlsVisibilityListener { fun onSingleTapConfirmed(event: MotionEvent): Boolean - fun onFade(alpha: Float, duration: Long) + /** + * Process of expansion + * 1f represents an expanded view, 0f represents a minimized view + */ + fun onExpand(progress: Float) + fun onVideoComplete() } |