Skip to content

Commit

Permalink
Design and animation updates for Media Preview.
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholas-signal committed Oct 27, 2022
1 parent 8e1ec5a commit d003dc4
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 44 deletions.
@@ -1,13 +1,24 @@
package org.thoughtcrime.securesms.mediapreview

import android.animation.Animator
import android.animation.Animator.AnimatorListener
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieProperty
import com.airbnb.lottie.model.KeyPath
import com.google.android.exoplayer2.ui.PlayerControlView
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.util.MediaUtil
import kotlin.time.DurationUnit
import kotlin.time.toDuration

/**
* The bottom bar for the media preview. This includes the standard seek bar as well as playback controls,
Expand All @@ -23,6 +34,7 @@ class MediaPreviewPlayerControlView @JvmOverloads constructor(
val recyclerView: RecyclerView = findViewById(R.id.media_preview_album_rail)
private val durationBar: LinearLayout = findViewById(R.id.exo_duration_viewgroup)
private val videoControls: LinearLayout = findViewById(R.id.exo_button_viewgroup)
private val durationLabel: TextView = findViewById(R.id.exo_duration)
private val shareButton: ImageButton = findViewById(R.id.exo_share)
private val forwardButton: ImageButton = findViewById(R.id.exo_forward)

Expand All @@ -47,12 +59,65 @@ class MediaPreviewPlayerControlView @JvmOverloads constructor(
showTimeoutMs = -1
}

fun setVisibility(mediaMode: MediaMode) {
@SuppressLint("SetTextI18n")
fun setMediaMode(mediaMode: MediaMode) {
durationBar.visibility = if (mediaMode == MediaMode.VIDEO) VISIBLE else GONE
videoControls.visibility = if (mediaMode == MediaMode.VIDEO) VISIBLE else INVISIBLE
if (mediaMode == MediaMode.VIDEO) {
setProgressUpdateListener { position, _ ->
val finalPlayer = player ?: return@setProgressUpdateListener
val remainingDuration = (finalPlayer.duration - position).toDuration(DurationUnit.MILLISECONDS)
val minutes: Long = remainingDuration.inWholeMinutes
val seconds: Long = remainingDuration.inWholeSeconds % 60
durationLabel.text = "${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}"
}
} else {
setProgressUpdateListener(null)
}
}

fun setShareButtonListener(listener: OnClickListener?) = shareButton.setOnClickListener(listener)

fun setForwardButtonListener(listener: OnClickListener?) = forwardButton.setOnClickListener(listener)
}

class LottieAnimatedButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : LottieAnimationView(context, attrs) {

init {
addValueCallback(KeyPath("**"), LottieProperty.COLOR) { ContextCompat.getColor(context, R.color.signal_colorOnSurface) }
}

override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
speed = 1f
playAnimation()
}
MotionEvent.ACTION_UP -> {
if (isAnimating) {
addAnimatorListener(object : AnimatorListener {
override fun onAnimationEnd(animation: Animator?) {
removeAllAnimatorListeners()
playAnimationReverse()
}

override fun onAnimationStart(animation: Animator?) {}
override fun onAnimationCancel(animation: Animator?) {}
override fun onAnimationRepeat(animation: Animator?) {}
})
} else {
playAnimationReverse()
}
}
}
return super.onTouchEvent(event)
}

private fun playAnimationReverse() {
speed = -1f
playAnimation()
}
}
Expand Up @@ -190,7 +190,7 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
} else {
MediaPreviewPlayerControlView.MediaMode.fromString(currentItem.contentType)
}
binding.mediaPreviewPlaybackControls.setVisibility(mediaType)
binding.mediaPreviewPlaybackControls.setMediaMode(mediaType)

binding.toolbar.title = getTitleText(currentItem, currentState.showThread)
binding.toolbar.subtitle = getSubTitleText(currentItem)
Expand Down
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/touch_highlight_material3">
<item android:id="@android:id/mask">
<shape android:shape="oval">
<solid android:color="@color/black" />
</shape>
</item>
</ripple>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="oval">
<solid android:color="@color/touch_highlight_material3" />
</shape>
</item>
</selector>
2 changes: 1 addition & 1 deletion app/src/main/res/drawable/mediarail_media_outline.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<corners android:radius="5dp" />
<corners android:radius="8dp" />

<stroke
android:width="3dp"
Expand Down
88 changes: 58 additions & 30 deletions app/src/main/res/layout/exo_player_control_view.xml
Expand Up @@ -14,9 +14,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/media_preview_video_timestamp_inset"
android:layout_marginTop="@dimen/media_preview_bottom_bar_vertical_margin"
android:layout_marginTop="@dimen/media_preview_bottom_bar_vertical_outer_margin"
android:layout_marginEnd="@dimen/media_preview_video_timestamp_inset"
android:layout_marginBottom="@dimen/media_preview_bottom_bar_vertical_margin"
android:layout_marginBottom="@dimen/media_preview_bottom_bar_vertical_inner_margin"
android:gravity="center_vertical"
android:orientation="horizontal">

Expand All @@ -28,13 +28,12 @@
android:includeFontPadding="false"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:textColor="#FFBEBEBE"
android:textSize="14sp" />
android:textColor="@color/signal_colorOnSurface" />

<com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="@id/exo_progress"
android:layout_width="0dp"
android:layout_height="26dp"
android:layout_height="24dp"
android:layout_weight="1" />

<TextView
Expand All @@ -45,8 +44,7 @@
android:includeFontPadding="false"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:textColor="#FFBEBEBE"
android:textSize="14sp" />
android:textColor="@color/signal_colorOnSurface" />

</LinearLayout>

Expand All @@ -56,26 +54,28 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="12dp"
android:orientation="horizontal"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:layout_height="64dp" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/media_preview_bottom_bar_vertical_margin"
android:layout_marginBottom="@dimen/media_preview_bottom_bar_vertical_margin"
android:layout_marginTop="@dimen/media_preview_bottom_bar_vertical_outer_margin"
android:layout_marginBottom="@dimen/media_preview_bottom_bar_vertical_outer_margin"
android:gravity="center"
android:orientation="horizontal"
android:paddingTop="4dp">

<ImageButton
android:id="@+id/exo_share"
android:layout_width="@dimen/exo_media_button_width"
android:layout_height="@dimen/exo_media_button_height"
android:background="?selectableItemBackground"
android:layout_width="@dimen/exo_media_preview_button_width"
android:layout_height="@dimen/exo_media_preview_button_height"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:background="@drawable/circle_touch_highlight_background_material3"
app:srcCompat="@drawable/ic_share_24_outline" />

<Space
Expand All @@ -87,48 +87,74 @@
android:id="@+id/exo_button_viewgroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible"
android:gravity="center"
android:orientation="horizontal">

<ImageButton
android:id="@id/exo_prev"
style="@style/ExoMediaButton.Previous" />
style="@style/ExoMediaButton.Previous"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" />

<ImageButton
<org.thoughtcrime.securesms.mediapreview.LottieAnimatedButton
android:id="@id/exo_rew"
style="@style/ExoMediaButton"
style="@style/MediaPreviewButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/exo_controls_rewind_description"
app:srcCompat="@drawable/ic_media_skipback_outline_24" />
android:layout_gravity="center_vertical"
android:background="@drawable/circle_touch_highlight_background_material3"
app:lottie_rawRes="@raw/lottie_15s_skip_back"
app:tint="@color/signal_colorOnSurface"
tools:visibility="visible" />

<ImageButton
android:id="@id/exo_shuffle"
style="@style/ExoMediaButton" />
style="@style/ExoMediaButton"
android:layout_marginStart="@dimen/media_preview_button_horizontal_margin"
android:layout_marginEnd="@dimen/media_preview_button_horizontal_margin" />

<ImageButton
android:id="@id/exo_repeat_toggle"
style="@style/ExoMediaButton" />
style="@style/ExoMediaButton"
android:layout_marginStart="@dimen/media_preview_button_horizontal_margin"
android:layout_marginEnd="@dimen/media_preview_button_horizontal_margin" />

<ImageButton
android:id="@id/exo_play"
style="@style/ExoMediaButton.Play" />
style="@style/MediaPreviewButton"
android:src="@drawable/exo_controls_play" />

<ImageButton
android:id="@id/exo_pause"
style="@style/ExoMediaButton.Pause" />
style="@style/MediaPreviewButton"
android:src="@drawable/exo_controls_pause" />

<ImageButton
<org.thoughtcrime.securesms.mediapreview.LottieAnimatedButton
android:id="@id/exo_ffwd"
style="@style/ExoMediaButton"
style="@style/MediaPreviewButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/exo_controls_fastforward_description"
app:srcCompat="@drawable/ic_media_skipforward_outline_24" />
android:layout_gravity="center_vertical"
android:background="@drawable/circle_touch_highlight_background_material3"
android:backgroundTint="@color/signal_colorOnSurface"
app:lottie_rawRes="@raw/lottie_15s_skip_forward"
app:tint="@color/signal_colorOnSurface"
tools:visibility="visible" />

<ImageButton
android:id="@id/exo_next"
style="@style/ExoMediaButton.Next" />
style="@style/ExoMediaButton.Next"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" />

<ImageButton
android:id="@id/exo_vr"
style="@style/ExoMediaButton.VR" />
style="@style/ExoMediaButton.VR"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" />
</LinearLayout>

<Space
Expand All @@ -138,9 +164,11 @@

<ImageButton
android:id="@+id/exo_forward"
android:layout_width="@dimen/exo_media_button_width"
android:layout_height="@dimen/exo_media_button_height"
android:background="?selectableItemBackground"
android:layout_width="@dimen/exo_media_preview_button_width"
android:layout_height="@dimen/exo_media_preview_button_height"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:background="@drawable/circle_touch_highlight_background_material3"
app:srcCompat="@drawable/ic_forward_outline_24" />
</LinearLayout>

Expand Down
20 changes: 10 additions & 10 deletions app/src/main/res/layout/mediarail_media_item.xml
Expand Up @@ -4,31 +4,31 @@
tools:viewBindingIgnore="true"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="57dp"
android:layout_height="57dp"
android:layout_margin="2dp"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_margin="4dp"
android:animateLayoutChanges="true">

<org.thoughtcrime.securesms.components.ThumbnailView
android:id="@+id/rail_item_image"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_gravity="center"
android:background="@drawable/mediarail_media_outline"
app:thumbnail_radius="5dp"/>
app:thumbnail_radius="8dp"/>

<ImageView
android:id="@+id/rail_item_outline"
android:layout_width="57dp"
android:layout_height="57dp"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_gravity="center"
android:src="@drawable/mediarail_media_outline"
android:visibility="gone"
tools:visibility="visible"/>

<ImageView
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_gravity="center"
android:src="@drawable/mediapicker_item_border_dark"/>

Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/raw/lottie_15s_play_pause.json
@@ -0,0 +1 @@
{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.0.2","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":50,"w":704,"h":704,"nm":"Pause","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Play","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":10,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":10,"s":[90]}],"ix":10},"p":{"a":0,"k":[352,352,0],"ix":2},"a":{"a":0,"k":[264,264,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"t":10,"s":[50,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.051,-2.95],[0,-3.593],[2.051,-2.95],[3.368,-1.25],[0,0],[0,18.15],[0,0],[-15.752,-9.108]],"o":[[3.368,1.25],[2.051,2.95],[0,3.593],[-2.051,2.95],[0,0],[-15.708,9.108],[0,0],[0,-18.15],[0,0]],"v":[[188.962,-16.544],[197.287,-10.093],[200.438,-0.044],[197.287,10.005],[188.962,16.456],[-171.838,225.456],[-200.438,209],[-200.438,-209],[-171.838,-225.456]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[288.438,263.999],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Pause","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":10,"s":[100]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-90]},{"t":10,"s":[0]}],"ix":10},"p":{"a":0,"k":[352,352,0],"ix":2},"a":{"a":0,"k":[264,264,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[50,50,100]},{"t":10,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.075,0],[0,0],[0,-6.075],[0,0],[6.075,0],[0,0],[0,6.075],[0,0]],"o":[[0,0],[6.075,0],[0,0],[0,6.075],[0,0],[-6.075,0],[0,0],[0,-6.075]],"v":[[-55,-220],[55,-220],[66,-209],[66,209],[55,220],[-55,220],[-66,209],[-66,-209]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[374,264],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.075,0],[0,0],[0,-6.075],[0,0],[6.075,0],[0,0],[0,6.075],[0,0]],"o":[[0,0],[6.075,0],[0,0],[0,6.075],[0,0],[-6.075,0],[0,0],[0,-6.075]],"v":[[-55,-220],[55,-220],[66,-209],[66,209],[55,220],[-55,220],[-66,209],[-66,-209]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[154,264],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0}],"markers":[]}

0 comments on commit d003dc4

Please sign in to comment.