Skip to content

Commit

Permalink
speed control button
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Reiner <[email protected]>
  • Loading branch information
arkascha committed Nov 25, 2024
1 parent e47b5aa commit f45dbe4
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Christian Reiner <[email protected]>
* SPDX-FileCopyrightText: 2021 Andy Scherzinger <[email protected]>
* SPDX-FileCopyrightText: 2021 Tim Krüger <[email protected]>
* SPDX-FileCopyrightText: 2021 Marcel Hibbe <[email protected]>
Expand Down Expand Up @@ -161,6 +162,10 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
}
})

voiceMessageInterface.registerMessageToObservePlaybackSpeedPreferences(message.user.id) { speed ->
binding.playbackSpeedControlBtn.setSpeed(speed)
}

Reaction().showReactions(
message,
::clickOnReaction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :

binding.checkMark.contentDescription = readStatusContentDescriptionString

voiceMessageInterface.registerMessageToObservePlaybackSpeedPreferences(message.user.id) { speed ->
binding.playbackSpeedControlBtn.setSpeed(speed)
}

Reaction().showReactions(
message,
::clickOnReaction,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Christian Reiner <[email protected]>
* SPDX-FileCopyrightText: 2021 Marcel Hibbe <[email protected]>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.adapters.messages

import com.nextcloud.talk.chat.data.model.ChatMessage
import com.nextcloud.talk.ui.PlaybackSpeed

interface VoiceMessageInterface {
fun updateMediaPlayerProgressBySlider(message: ChatMessage, progress: Int)
fun registerMessageToObservePlaybackSpeedPreferences(userId: String, listener: (speed: PlaybackSpeed) -> Unit)
}
50 changes: 50 additions & 0 deletions app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Christian Reiner <[email protected]>
* SPDX-FileCopyrightText: 2024 Parneet Singh <[email protected]>
* SPDX-FileCopyrightText: 2024 Giacomo Pacini <[email protected]>
* SPDX-FileCopyrightText: 2023 Ezhil Shanmugham <[email protected]>
Expand Down Expand Up @@ -136,6 +137,8 @@ import com.nextcloud.talk.shareditems.activities.SharedItemsActivity
import com.nextcloud.talk.signaling.SignalingMessageReceiver
import com.nextcloud.talk.signaling.SignalingMessageSender
import com.nextcloud.talk.translate.ui.TranslateActivity
import com.nextcloud.talk.ui.PlaybackSpeed
import com.nextcloud.talk.ui.PlaybackSpeedControl
import com.nextcloud.talk.ui.StatusDrawable
import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet
import com.nextcloud.talk.ui.dialog.DateTimePickerFragment
Expand Down Expand Up @@ -205,6 +208,7 @@ import java.util.Date
import java.util.Locale
import java.util.concurrent.ExecutionException
import javax.inject.Inject
import kotlin.String
import kotlin.collections.set
import kotlin.math.roundToInt

Expand Down Expand Up @@ -357,6 +361,20 @@ class ChatActivity :
private var voiceMessageToRestoreAudioPosition = 0
private var voiceMessageToRestoreWasPlaying = false

private final val playbackSpeedPreferencesObserver: (Map<String, PlaybackSpeed>) ->Unit = {
speedPreferenceLiveData ->
mediaPlayer?.let { mediaPlayer ->
(mediaPlayer.isPlaying == true).also {
currentlyPlayedVoiceMessage?.let { message ->
mediaPlayer.playbackParams.let { params ->
params.setSpeed(chatViewModel.getPlaybackSpeedPreference(message).value)
mediaPlayer.playbackParams = params
}
}
}
}
}

private val localParticipantMessageListener = object : SignalingMessageReceiver.LocalParticipantMessageListener {
override fun onSwitchTo(token: String?) {
if (token != null) {
Expand Down Expand Up @@ -434,6 +452,10 @@ class ChatActivity :

onBackPressedDispatcher.addCallback(this, onBackPressedCallback)

appPreferences.readVoiceMessagePlaybackSpeedPreferences().let { playbackSpeedPreferences ->
chatViewModel.applyPlaybackSpeedPreferences(playbackSpeedPreferences)
}

initObservers()

if (savedInstanceState != null) {
Expand Down Expand Up @@ -1045,6 +1067,8 @@ class ChatActivity :

setupSwipeToReply()

chatViewModel.voiceMessagePlaybackSpeedPreferences.observe(this, playbackSpeedPreferencesObserver)

binding.unreadMessagesPopup.setOnClickListener {
binding.messagesListView.smoothScrollToPosition(0)
binding.unreadMessagesPopup.visibility = View.GONE
Expand Down Expand Up @@ -1131,6 +1155,7 @@ class ChatActivity :
adapter?.setLoadMoreListener(this)
adapter?.setDateHeadersFormatter { format(it) }
adapter?.setOnMessageViewLongClickListener { view, message -> onMessageViewLongClick(view, message) }

adapter?.registerViewClickListener(
R.id.playPauseBtn
) { _, message ->
Expand All @@ -1154,6 +1179,15 @@ class ChatActivity :
}
}
}

adapter?.registerViewClickListener(R.id.playbackSpeedControlBtn) { button, message ->
val nextSpeed = (button as PlaybackSpeedControl).getSpeed().next()
HashMap(appPreferences.readVoiceMessagePlaybackSpeedPreferences()).let { playbackSpeedPreferences ->
playbackSpeedPreferences[message.user.id] = nextSpeed
chatViewModel.applyPlaybackSpeedPreferences(playbackSpeedPreferences)
appPreferences.saveVoiceMessagePlaybackSpeedPreferences(playbackSpeedPreferences)
}
}
}

private fun setUpWaveform(message: ChatMessage, thenPlay: Boolean = true) {
Expand Down Expand Up @@ -1579,6 +1613,9 @@ class ChatActivity :
mediaPlayer?.let {
if (!it.isPlaying && doPlay) {
chatViewModel.audioRequest(true) {
it.playbackParams = it.playbackParams.apply {
setSpeed(chatViewModel.getPlaybackSpeedPreference(message).value)
}
it.start()
}
}
Expand Down Expand Up @@ -1703,6 +1740,17 @@ class ChatActivity :
}
}

override fun registerMessageToObservePlaybackSpeedPreferences(userId: String, listener: (speed: PlaybackSpeed) -> Unit) {
chatViewModel.voiceMessagePlaybackSpeedPreferences.let { liveData ->
liveData.observe(this) {
playbackSpeedPreferences -> listener(playbackSpeedPreferences[userId]?:PlaybackSpeed.NORMAL)
}
liveData.value?.let {
playbackSpeedPreferences -> listener(playbackSpeedPreferences[userId] ?:PlaybackSpeed.NORMAL)
}
}
}

@SuppressLint("NotifyDataSetChanged")
override fun collapseSystemMessages() {
adapter?.items?.forEach {
Expand Down Expand Up @@ -2372,6 +2420,8 @@ class ChatActivity :
if (mentionAutocomplete != null && mentionAutocomplete!!.isPopupShowing) {
mentionAutocomplete?.dismissPopup()
}

chatViewModel.voiceMessagePlaybackSpeedPreferences.removeObserver(playbackSpeedPreferencesObserver)
}

private fun isActivityNotChangingConfigurations(): Boolean = !isChangingConfigurations
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Christian Reiner <[email protected]>
* SPDX-FileCopyrightText: 2023 Marcel Hibbe <[email protected]>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
Expand Down Expand Up @@ -33,6 +34,7 @@ import com.nextcloud.talk.models.json.conversations.RoomsOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.reminder.Reminder
import com.nextcloud.talk.repositories.reactions.ReactionsRepository
import com.nextcloud.talk.ui.PlaybackSpeed
import com.nextcloud.talk.utils.ConversationUtils
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
Expand Down Expand Up @@ -107,6 +109,10 @@ class ChatViewModel @Inject constructor(
val getVoiceRecordingLocked: LiveData<Boolean>
get() = _getVoiceRecordingLocked

private val _voiceMessagePlaybackSpeeds: MutableLiveData<Map<String, PlaybackSpeed>> = MutableLiveData()
val voiceMessagePlaybackSpeedPreferences: LiveData<Map<String, PlaybackSpeed>>
get() = _voiceMessagePlaybackSpeeds

val getMessageFlow = chatRepository.messageFlow
.onEach {
_chatMessageViewState.value = if (_chatMessageViewState.value == ChatMessageInitialState) {
Expand Down Expand Up @@ -644,6 +650,13 @@ class ChatViewModel @Inject constructor(
emit(message.first())
}

fun applyPlaybackSpeedPreferences(speeds: Map<String, PlaybackSpeed>) {
_voiceMessagePlaybackSpeeds.postValue(speeds)
}

fun getPlaybackSpeedPreference(message: ChatMessage) =
_voiceMessagePlaybackSpeeds.value?.get(message.user.id) ?:PlaybackSpeed.NORMAL

// inner class GetRoomObserver : Observer<ConversationModel> {
// override fun onSubscribe(d: Disposable) {
// // unused atm
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class MessageInputViewModel @Inject constructor(
private val audioRecorderManager: AudioRecorderManager,
private val mediaPlayerManager: MediaPlayerManager,
private val audioFocusRequestManager: AudioFocusRequestManager,
private val dataStore: AppPreferences
private val appPreferences: AppPreferences
) : ViewModel(), DefaultLifecycleObserver {
enum class LifeCycleFlag {
PAUSED,
Expand Down Expand Up @@ -147,9 +147,9 @@ class MessageInputViewModel @Inject constructor(
if (isQueueing) {
val tempID = System.currentTimeMillis().toInt()
val qMsg = QueuedMessage(tempID, message, displayName, replyTo, sendWithoutNotification)
messageQueue = dataStore.getMessageQueue(internalId)
messageQueue = appPreferences.getMessageQueue(internalId)
messageQueue.add(qMsg)
dataStore.saveMessageQueue(internalId, messageQueue)
appPreferences.saveMessageQueue(internalId, messageQueue)
_messageQueueSizeFlow.update { messageQueue.size }
_messageQueueFlow.postValue(listOf(qMsg))
return
Expand Down Expand Up @@ -260,8 +260,8 @@ class MessageInputViewModel @Inject constructor(
if (isQueueing) return
messageQueue.clear()

val queue = dataStore.getMessageQueue(internalId)
dataStore.saveMessageQueue(internalId, null) // empties the queue
val queue = appPreferences.getMessageQueue(internalId)
appPreferences.saveMessageQueue(internalId, null) // empties the queue
while (queue.size > 0) {
val msg = queue.removeAt(0)
sendChatMessage(
Expand All @@ -279,7 +279,7 @@ class MessageInputViewModel @Inject constructor(
}

fun getTempMessagesFromMessageQueue(internalId: String) {
val queue = dataStore.getMessageQueue(internalId)
val queue = appPreferences.getMessageQueue(internalId)
val list = mutableListOf<QueuedMessage>()
for (msg in queue) {
list.add(msg)
Expand All @@ -292,31 +292,31 @@ class MessageInputViewModel @Inject constructor(
}

fun restoreMessageQueue(internalId: String) {
messageQueue = dataStore.getMessageQueue(internalId)
messageQueue = appPreferences.getMessageQueue(internalId)
_messageQueueSizeFlow.tryEmit(messageQueue.size)
}

fun removeFromQueue(internalId: String, id: Int) {
val queue = dataStore.getMessageQueue(internalId)
val queue = appPreferences.getMessageQueue(internalId)
for (qMsg in queue) {
if (qMsg.id == id) {
queue.remove(qMsg)
break
}
}
dataStore.saveMessageQueue(internalId, queue)
appPreferences.saveMessageQueue(internalId, queue)
_messageQueueSizeFlow.tryEmit(queue.size)
}

fun editQueuedMessage(internalId: String, id: Int, newMessage: String) {
val queue = dataStore.getMessageQueue(internalId)
val queue = appPreferences.getMessageQueue(internalId)
for (qMsg in queue) {
if (qMsg.id == id) {
qMsg.message = newMessage
break
}
}
dataStore.saveMessageQueue(internalId, queue)
appPreferences.saveMessageQueue(internalId, queue)
}

fun showCallStartedIndicator(recent: ChatMessage, show: Boolean) {
Expand Down
60 changes: 60 additions & 0 deletions app/src/main/java/com/nextcloud/talk/ui/PlaybackSpeedControl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Christian Reiner <[email protected]>
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package com.nextcloud.talk.ui

import android.content.Context
import android.util.AttributeSet
import com.google.android.material.button.MaterialButton

class PlaybackSpeedControl @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : MaterialButton(context, attrs, defStyleAttr) {

private var currentSpeed = PlaybackSpeed.NORMAL

init {
text = currentSpeed.label
}

fun setSpeed(newSpeed: PlaybackSpeed) {
currentSpeed = newSpeed
text = currentSpeed.label
}

fun getSpeed(): PlaybackSpeed {
return currentSpeed
}

fun adjustSpeedAccordingToPreferences(userId: String, speeds: Map<String, PlaybackSpeed>) {
setSpeed(speeds[userId] ?: PlaybackSpeed.NORMAL)
}
}

enum class PlaybackSpeed(val value: Float, val label: String) {
SLOW(0.8f, "0.8x"),
NORMAL(1.0f, "1.0x"),
FASTER(1.5f, "1.5x"),
FASTEST(2.0f, "2.0x");

fun next(): PlaybackSpeed {
return entries[(ordinal + 1) % entries.size]
}

companion object {
fun byName(name: String): PlaybackSpeed {
for (speed in entries) {
if (speed.name.equals(name, ignoreCase = true)) {
return speed
}
}
return NORMAL
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Christian Reiner <[email protected]>
* SPDX-FileCopyrightText: 2021 Andy Scherzinger <[email protected]>
* SPDX-FileCopyrightText: 2021 Tim Krüger <[email protected]>
* SPDX-FileCopyrightText: 2017 Mario Danic <[email protected]>
Expand All @@ -11,8 +12,10 @@
import android.annotation.SuppressLint;

import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel;
import com.nextcloud.talk.ui.PlaybackSpeed;

import java.util.List;
import java.util.Map;

@SuppressLint("NonConstantResourceId")
public interface AppPreferences {
Expand Down Expand Up @@ -178,6 +181,9 @@ public interface AppPreferences {

void deleteAllMessageQueuesFor(String userId);

void saveVoiceMessagePlaybackSpeedPreferences(Map<String, PlaybackSpeed> speeds);

Map<String, PlaybackSpeed> readVoiceMessagePlaybackSpeedPreferences();

void clear();
}
Loading

0 comments on commit f45dbe4

Please sign in to comment.