-
-
Notifications
You must be signed in to change notification settings - Fork 251
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4482 from arkascha/issues-334-allow-voice-message…
…s-to-be-played-at-different-speeds Add playback speed control to voice messages
- Loading branch information
Showing
14 changed files
with
288 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]> | ||
|
@@ -68,10 +69,16 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : | |
|
||
lateinit var voiceMessageInterface: VoiceMessageInterface | ||
lateinit var commonMessageInterface: CommonMessageInterface | ||
private var isBound = false | ||
|
||
@SuppressLint("SetTextI18n") | ||
override fun onBind(message: ChatMessage) { | ||
super.onBind(message) | ||
if (isBound) { | ||
handleIsPlayingVoiceMessageState(message) | ||
return | ||
} | ||
|
||
this.message = message | ||
sharedApplication!!.componentApplication.inject(this) | ||
|
||
|
@@ -100,25 +107,6 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : | |
viewThemeUtils.talk.themeWaveFormSeekBar(binding.seekbar) | ||
viewThemeUtils.platform.colorCircularProgressBar(binding.progressBar, ColorRole.ON_SURFACE_VARIANT) | ||
|
||
if (message.isPlayingVoiceMessage) { | ||
showPlayButton() | ||
binding.playPauseBtn.icon = ContextCompat.getDrawable( | ||
context!!, | ||
R.drawable.ic_baseline_pause_voice_message_24 | ||
) | ||
val d = message.voiceMessageDuration.toLong() | ||
val t = message.voiceMessagePlayedSeconds.toLong() | ||
binding.voiceMessageDuration.text = android.text.format.DateUtils.formatElapsedTime(d - t) | ||
binding.voiceMessageDuration.visibility = View.VISIBLE | ||
binding.seekbar.progress = message.voiceMessageSeekbarProgress | ||
} else { | ||
binding.playPauseBtn.visibility = View.VISIBLE | ||
binding.playPauseBtn.icon = ContextCompat.getDrawable( | ||
context!!, | ||
R.drawable.ic_baseline_play_arrow_voice_message_24 | ||
) | ||
} | ||
|
||
if (message.isDownloadingVoiceMessage) { | ||
showVoiceMessageLoading() | ||
} else { | ||
|
@@ -158,6 +146,10 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : | |
} | ||
}) | ||
|
||
voiceMessageInterface.registerMessageToObservePlaybackSpeedPreferences(message.user.id) { speed -> | ||
binding.playbackSpeedControlBtn.setSpeed(speed) | ||
} | ||
|
||
Reaction().showReactions( | ||
message, | ||
::clickOnReaction, | ||
|
@@ -167,6 +159,8 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : | |
false, | ||
viewThemeUtils | ||
) | ||
|
||
isBound = true | ||
} | ||
|
||
private fun longClickOnReaction(chatMessage: ChatMessage) { | ||
|
@@ -177,6 +171,29 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : | |
commonMessageInterface.onClickReaction(chatMessage, emoji) | ||
} | ||
|
||
private fun handleIsPlayingVoiceMessageState(message: ChatMessage) { | ||
if (message.isPlayingVoiceMessage) { | ||
showPlayButton() | ||
binding.playPauseBtn.icon = ContextCompat.getDrawable( | ||
context!!, | ||
R.drawable.ic_baseline_pause_voice_message_24 | ||
) | ||
|
||
val d = message.voiceMessageDuration.toLong() | ||
val t = message.voiceMessagePlayedSeconds.toLong() | ||
binding.voiceMessageDuration.text = android.text.format.DateUtils.formatElapsedTime(d - t) | ||
binding.voiceMessageDuration.visibility = View.VISIBLE | ||
binding.seekbar.max = message.voiceMessageDuration * ONE_SEC | ||
binding.seekbar.progress = message.voiceMessageSeekbarProgress | ||
} else { | ||
binding.playPauseBtn.visibility = View.VISIBLE | ||
binding.playPauseBtn.icon = ContextCompat.getDrawable( | ||
context!!, | ||
R.drawable.ic_baseline_play_arrow_voice_message_24 | ||
) | ||
} | ||
} | ||
|
||
private fun updateDownloadState(message: ChatMessage) { | ||
// check if download worker is already running | ||
val fileId = message.selectedIndividualHashMap!!["id"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]> | ||
|
@@ -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 | ||
|
@@ -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 | ||
|
||
|
@@ -357,6 +361,19 @@ class ChatActivity : | |
private var voiceMessageToRestoreAudioPosition = 0 | ||
private var voiceMessageToRestoreWasPlaying = false | ||
|
||
private 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) { | ||
|
@@ -434,6 +451,10 @@ class ChatActivity : | |
|
||
onBackPressedDispatcher.addCallback(this, onBackPressedCallback) | ||
|
||
appPreferences.readVoiceMessagePlaybackSpeedPreferences().let { playbackSpeedPreferences -> | ||
chatViewModel.applyPlaybackSpeedPreferences(playbackSpeedPreferences) | ||
} | ||
|
||
initObservers() | ||
|
||
if (savedInstanceState != null) { | ||
|
@@ -1045,6 +1066,8 @@ class ChatActivity : | |
|
||
setupSwipeToReply() | ||
|
||
chatViewModel.voiceMessagePlaybackSpeedPreferences.observe(this, playbackSpeedPreferencesObserver) | ||
|
||
binding.unreadMessagesPopup.setOnClickListener { | ||
binding.messagesListView.smoothScrollToPosition(0) | ||
binding.unreadMessagesPopup.visibility = View.GONE | ||
|
@@ -1131,6 +1154,7 @@ class ChatActivity : | |
adapter?.setLoadMoreListener(this) | ||
adapter?.setDateHeadersFormatter { format(it) } | ||
adapter?.setOnMessageViewLongClickListener { view, message -> onMessageViewLongClick(view, message) } | ||
|
||
adapter?.registerViewClickListener( | ||
R.id.playPauseBtn | ||
) { _, message -> | ||
|
@@ -1154,6 +1178,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) { | ||
|
@@ -1579,6 +1612,9 @@ class ChatActivity : | |
mediaPlayer?.let { | ||
if (!it.isPlaying && doPlay) { | ||
chatViewModel.audioRequest(true) { | ||
it.playbackParams = it.playbackParams.apply { | ||
setSpeed(chatViewModel.getPlaybackSpeedPreference(message).value) | ||
} | ||
it.start() | ||
} | ||
} | ||
|
@@ -1703,6 +1739,20 @@ 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 { | ||
|
@@ -2372,6 +2422,8 @@ class ChatActivity : | |
if (mentionAutocomplete != null && mentionAutocomplete!!.isPopupShowing) { | ||
mentionAutocomplete?.dismissPopup() | ||
} | ||
|
||
chatViewModel.voiceMessagePlaybackSpeedPreferences.removeObserver(playbackSpeedPreferencesObserver) | ||
} | ||
|
||
private fun isActivityNotChangingConfigurations(): Boolean = !isChangingConfigurations | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
*/ | ||
|
@@ -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 | ||
|
@@ -107,6 +109,10 @@ class ChatViewModel @Inject constructor( | |
val getVoiceRecordingLocked: LiveData<Boolean> | ||
get() = _getVoiceRecordingLocked | ||
|
||
private val _voiceMessagePlaybackSpeedPreferences: MutableLiveData<Map<String, PlaybackSpeed>> = MutableLiveData() | ||
val voiceMessagePlaybackSpeedPreferences: LiveData<Map<String, PlaybackSpeed>> | ||
get() = _voiceMessagePlaybackSpeedPreferences | ||
|
||
val getMessageFlow = chatRepository.messageFlow | ||
.onEach { | ||
_chatMessageViewState.value = if (_chatMessageViewState.value == ChatMessageInitialState) { | ||
|
@@ -644,6 +650,13 @@ class ChatViewModel @Inject constructor( | |
emit(message.first()) | ||
} | ||
|
||
fun applyPlaybackSpeedPreferences(speeds: Map<String, PlaybackSpeed>) { | ||
_voiceMessagePlaybackSpeedPreferences.postValue(speeds) | ||
} | ||
|
||
fun getPlaybackSpeedPreference(message: ChatMessage) = | ||
_voiceMessagePlaybackSpeedPreferences.value?.get(message.user.id) ?: PlaybackSpeed.NORMAL | ||
|
||
// inner class GetRoomObserver : Observer<ConversationModel> { | ||
// override fun onSubscribe(d: Disposable) { | ||
// // unused atm | ||
|
Oops, something went wrong.