Merge pull request #644 from RyanRory/auto-play-voice-message

Auto Play Next Voice Message If Possible
This commit is contained in:
Niels Andriesse 2021-07-08 11:25:57 +10:00 committed by GitHub
commit 7aefa288d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 3 deletions

View File

@ -23,6 +23,8 @@ import android.widget.RelativeLayout
import android.widget.Toast import android.widget.Toast
import androidx.annotation.DimenRes import androidx.annotation.DimenRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.children
import androidx.core.view.get
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
@ -40,6 +42,7 @@ import kotlinx.android.synthetic.main.view_conversation.view.*
import kotlinx.android.synthetic.main.view_input_bar.view.* import kotlinx.android.synthetic.main.view_input_bar.view.*
import kotlinx.android.synthetic.main.view_input_bar_recording.* import kotlinx.android.synthetic.main.view_input_bar_recording.*
import kotlinx.android.synthetic.main.view_input_bar_recording.view.* import kotlinx.android.synthetic.main.view_input_bar_recording.view.*
import kotlinx.android.synthetic.main.view_visible_message.view.*
import network.loki.messenger.R import network.loki.messenger.R
import nl.komponents.kovenant.ui.failUi import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.successUi import nl.komponents.kovenant.ui.successUi
@ -84,8 +87,7 @@ import org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCand
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallback import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallback
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallbackDelegate import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallbackDelegate
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageContentViewDelegate import org.thoughtcrime.securesms.conversation.v2.messages.*
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
import org.thoughtcrime.securesms.conversation.v2.search.SearchBottomBar import org.thoughtcrime.securesms.conversation.v2.search.SearchBottomBar
import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel
import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager
@ -124,7 +126,7 @@ import kotlin.math.*
class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate, class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate,
InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener, ActivityDispatcher, InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener, ActivityDispatcher,
ConversationActionModeCallbackDelegate, VisibleMessageContentViewDelegate, RecipientModifiedListener, ConversationActionModeCallbackDelegate, VisibleMessageContentViewDelegate, RecipientModifiedListener,
SearchBottomBar.EventListener { SearchBottomBar.EventListener, VoiceMessageViewDelegate {
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
private var linkPreviewViewModel: LinkPreviewViewModel? = null private var linkPreviewViewModel: LinkPreviewViewModel? = null
private var threadID: Long = -1 private var threadID: Long = -1
@ -844,6 +846,21 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
conversationRecyclerView.scrollToPosition(lastSeenItemPosition) conversationRecyclerView.scrollToPosition(lastSeenItemPosition)
} }
override fun playNextAudioIfPossible(current: Int) {
if (current > 0) {
val nextVisibleMessageView = conversationRecyclerView[current - 1] as? VisibleMessageView
nextVisibleMessageView?.let { visibleMessageView ->
visibleMessageView.messageContentView.mainContainer.children.forEach { child ->
val nextVoiceMessageView = child as? VoiceMessageView
nextVoiceMessageView?.let { voiceMessageView ->
voiceMessageView.togglePlayback()
return@forEach
}
}
}
}
}
override fun sendMessage() { override fun sendMessage() {
if (thread.isContactRecipient && thread.isBlocked) { if (thread.isContactRecipient && thread.isBlocked) {
BlockedDialog(thread).show(supportFragmentManager, "Blocked Dialog") BlockedDialog(thread).show(supportFragmentManager, "Blocked Dialog")

View File

@ -72,6 +72,7 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr
view.snIsSelected = isSelected view.snIsSelected = isSelected
view.messageTimestampTextView.isVisible = isSelected view.messageTimestampTextView.isVisible = isSelected
val position = viewHolder.adapterPosition val position = viewHolder.adapterPosition
view.viewHolderIndex = position
view.bind(message, getMessageBefore(position, cursor), getMessageAfter(position, cursor), glide, searchQuery) view.bind(message, getMessageBefore(position, cursor), getMessageAfter(position, cursor), glide, searchQuery)
view.onPress = { event -> onItemPress(message, viewHolder.adapterPosition, view, event) } view.onPress = { event -> onItemPress(message, viewHolder.adapterPosition, view, event) }
view.onSwipeToReply = { onItemSwipeToReply(message, viewHolder.adapterPosition) } view.onSwipeToReply = { onItemSwipeToReply(message, viewHolder.adapterPosition) }

View File

@ -32,6 +32,7 @@ import org.session.libsession.utilities.ViewUtil
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.components.AlbumThumbnailView import org.thoughtcrime.securesms.conversation.v2.components.AlbumThumbnailView
import org.thoughtcrime.securesms.components.emoji.EmojiTextView import org.thoughtcrime.securesms.components.emoji.EmojiTextView
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.conversation.v2.dialogs.OpenURLDialog import org.thoughtcrime.securesms.conversation.v2.dialogs.OpenURLDialog
import org.thoughtcrime.securesms.conversation.v2.utilities.ModalURLSpan import org.thoughtcrime.securesms.conversation.v2.utilities.ModalURLSpan
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.getIntersectedModalSpans import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.getIntersectedModalSpans
@ -48,6 +49,7 @@ class VisibleMessageContentView : LinearLayout {
var onContentClick: ((event: MotionEvent) -> Unit)? = null var onContentClick: ((event: MotionEvent) -> Unit)? = null
var onContentDoubleTap: (() -> Unit)? = null var onContentDoubleTap: (() -> Unit)? = null
var delegate: VisibleMessageContentViewDelegate? = null var delegate: VisibleMessageContentViewDelegate? = null
var viewHolderIndex: Int = -1
// region Lifecycle // region Lifecycle
constructor(context: Context) : super(context) { initialize() } constructor(context: Context) : super(context) { initialize() }
@ -107,6 +109,8 @@ class VisibleMessageContentView : LinearLayout {
} }
} else if (message is MmsMessageRecord && message.slideDeck.audioSlide != null) { } else if (message is MmsMessageRecord && message.slideDeck.audioSlide != null) {
val voiceMessageView = VoiceMessageView(context) val voiceMessageView = VoiceMessageView(context)
voiceMessageView.index = viewHolderIndex
voiceMessageView.delegate = context as? ConversationActivityV2
voiceMessageView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster) voiceMessageView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster)
mainContainer.addView(voiceMessageView) mainContainer.addView(voiceMessageView)
// We have to use onContentClick (rather than a click listener directly on the voice // We have to use onContentClick (rather than a click listener directly on the voice

View File

@ -47,6 +47,7 @@ class VisibleMessageView : LinearLayout {
private var longPressCallback: Runnable? = null private var longPressCallback: Runnable? = null
private var onDownTimestamp = 0L private var onDownTimestamp = 0L
private var onDoubleTap: (() -> Unit)? = null private var onDoubleTap: (() -> Unit)? = null
var viewHolderIndex: Int = -1
var snIsSelected = false var snIsSelected = false
set(value) { field = value; handleIsSelectedChanged()} set(value) { field = value; handleIsSelectedChanged()}
var onPress: ((event: MotionEvent) -> Unit)? = null var onPress: ((event: MotionEvent) -> Unit)? = null
@ -151,6 +152,7 @@ class VisibleMessageView : LinearLayout {
var maxWidth = screenWidth - startPadding - endPadding var maxWidth = screenWidth - startPadding - endPadding
if (profilePictureContainer.visibility != View.GONE) { maxWidth -= profilePictureContainer.width } if (profilePictureContainer.visibility != View.GONE) { maxWidth -= profilePictureContainer.width }
// Populate content view // Populate content view
messageContentView.viewHolderIndex = viewHolderIndex
messageContentView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster, glide, maxWidth, thread, searchQuery) messageContentView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster, glide, maxWidth, thread, searchQuery)
messageContentView.delegate = contentViewDelegate messageContentView.delegate = contentViewDelegate
onDoubleTap = { messageContentView.onContentDoubleTap?.invoke() } onDoubleTap = { messageContentView.onContentDoubleTap?.invoke() }

View File

@ -32,6 +32,8 @@ class VoiceMessageView : LinearLayout, AudioSlidePlayer.Listener {
private var duration = 0L private var duration = 0L
private var player: AudioSlidePlayer? = null private var player: AudioSlidePlayer? = null
private var isPreparing = false private var isPreparing = false
var delegate: VoiceMessageViewDelegate? = null
var index = -1
// region Lifecycle // region Lifecycle
constructor(context: Context) : super(context) { initialize() } constructor(context: Context) : super(context) { initialize() }
@ -84,6 +86,7 @@ class VoiceMessageView : LinearLayout, AudioSlidePlayer.Listener {
if (progress == 1.0) { if (progress == 1.0) {
togglePlayback() togglePlayback()
handleProgressChanged(0.0) handleProgressChanged(0.0)
delegate?.playNextAudioIfPossible(index)
} else { } else {
handleProgressChanged(progress) handleProgressChanged(progress)
} }
@ -133,3 +136,8 @@ class VoiceMessageView : LinearLayout, AudioSlidePlayer.Listener {
} }
// endregion // endregion
} }
interface VoiceMessageViewDelegate {
fun playNextAudioIfPossible(current: Int)
}