From 6d9eb0a93263c3f99b7b282a5f28451bd36cbb5e Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 21 Jun 2021 13:36:45 +1000 Subject: [PATCH] Full voice message UI --- .../v2/messages/VisibleMessageContentView.kt | 3 +- .../v2/messages/VoiceMessageView.kt | 56 ++++++++++++++- .../main/res/layout/view_voice_message.xml | 71 +++++++++++++------ .../main/res/values-notnight-v21/themes.xml | 2 +- 4 files changed, 107 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt index 7e21946d89..2c5c908bd4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt @@ -5,6 +5,7 @@ import android.graphics.drawable.Drawable import android.util.AttributeSet import android.util.TypedValue import android.view.LayoutInflater +import android.view.ViewOutlineProvider import android.widget.LinearLayout import android.widget.TextView import androidx.annotation.DrawableRes @@ -62,7 +63,7 @@ class VisibleMessageContentView : LinearLayout { mainContainer.addView(bodyTextView) } else if (message is MmsMessageRecord && message.slideDeck.audioSlide != null) { val voiceMessageView = VoiceMessageView(context) - voiceMessageView.bind(message) + voiceMessageView.bind(message, background) mainContainer.addView(voiceMessageView) } else if (message is MmsMessageRecord && message.slideDeck.documentSlide != null) { val documentView = DocumentView(context) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt index 42f9a66b3e..136c9d9661 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt @@ -1,14 +1,28 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context +import android.graphics.drawable.Drawable +import android.os.Handler +import android.os.Looper import android.util.AttributeSet import android.view.LayoutInflater +import android.view.ViewOutlineProvider import android.widget.LinearLayout +import android.widget.RelativeLayout +import androidx.core.view.isVisible import kotlinx.android.synthetic.main.view_voice_message.view.* import network.loki.messenger.R -import org.thoughtcrime.securesms.database.model.MessageRecord +import org.thoughtcrime.securesms.database.model.MmsMessageRecord +import java.util.concurrent.TimeUnit +import kotlin.math.roundToInt class VoiceMessageView : LinearLayout { + private val snHandler = Handler(Looper.getMainLooper()) + private var runnable: Runnable? = null + private var mockIsPlaying = false + private var mockProgress = 0L + set(value) { field = value; handleProgressChanged() } + private var mockDuration = 12000L // region Lifecycle constructor(context: Context) : super(context) { initialize() } @@ -17,16 +31,54 @@ class VoiceMessageView : LinearLayout { private fun initialize() { LayoutInflater.from(context).inflate(R.layout.view_voice_message, this) + setOnClickListener { togglePlayBack() } + voiceMessageViewDurationTextView.text = String.format("%01d:%02d", + TimeUnit.MILLISECONDS.toMinutes(mockDuration), + TimeUnit.MILLISECONDS.toSeconds(mockDuration)) } // endregion // region Updating - fun bind(message: MessageRecord) { + fun bind(message: MmsMessageRecord, background: Drawable) { + val audio = message.slideDeck.audioSlide!! + voiceMessageViewLoader.isVisible = audio.isPendingDownload + mainVoiceMessageViewContainer.background = background + mainVoiceMessageViewContainer.outlineProvider = ViewOutlineProvider.BACKGROUND + mainVoiceMessageViewContainer.clipToOutline = true + } + private fun handleProgressChanged() { + voiceMessageViewDurationTextView.text = String.format("%01d:%02d", + TimeUnit.MILLISECONDS.toMinutes(mockDuration - mockProgress), + TimeUnit.MILLISECONDS.toSeconds(mockDuration - mockProgress)) + val layoutParams = progressView.layoutParams as RelativeLayout.LayoutParams + val fraction = mockProgress.toFloat() / mockDuration.toFloat() + layoutParams.width = (width.toFloat() * fraction).roundToInt() + progressView.layoutParams = layoutParams } fun recycle() { // TODO: Implement } // endregion + + // region Interaction + private fun togglePlayBack() { + mockIsPlaying = !mockIsPlaying + val iconID = if (mockIsPlaying) R.drawable.exo_icon_pause else R.drawable.exo_icon_play + voiceMessagePlaybackImageView.setImageResource(iconID) + if (mockIsPlaying) { + updateProgress() + } else { + runnable?.let { snHandler.removeCallbacks(it) } + } + } + + private fun updateProgress() { + mockProgress += 20L + val runnable = Runnable { updateProgress() } + this.runnable = runnable + snHandler.postDelayed(runnable, 20L) + } + // endregion } \ No newline at end of file diff --git a/app/src/main/res/layout/view_voice_message.xml b/app/src/main/res/layout/view_voice_message.xml index ae5768c41d..b319df392d 100644 --- a/app/src/main/res/layout/view_voice_message.xml +++ b/app/src/main/res/layout/view_voice_message.xml @@ -1,41 +1,70 @@ - + android:layout_height="36dp"> - - - - - + + + + + + + + + + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values-notnight-v21/themes.xml b/app/src/main/res/values-notnight-v21/themes.xml index a8540be632..53262d3598 100644 --- a/app/src/main/res/values-notnight-v21/themes.xml +++ b/app/src/main/res/values-notnight-v21/themes.xml @@ -8,7 +8,7 @@ #00FFFFFF #FFFFFFFF - #F5F5F5 + #F2F2F2 #00E076 @android:color/black