Issue 3142

- Added duration of the voice message playing
- Fixed the seekbar bug, and made it more smoother

Signed-off-by: Julius Linus <julius.linus@nextcloud.com>
This commit is contained in:
Julius Linus 2023-07-13 17:12:53 -05:00 committed by rapterjet2004
parent b899433180
commit bb45ebd3b8
5 changed files with 165 additions and 127 deletions

View file

@ -111,7 +111,11 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
context!!, context!!,
R.drawable.ic_baseline_pause_voice_message_24 R.drawable.ic_baseline_pause_voice_message_24
) )
binding.seekbar.progress = message.voiceMessagePlayedSeconds 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.setProgress(message.voiceMessagePlayedSeconds, true)
} else { } else {
binding.playPauseBtn.visibility = View.VISIBLE binding.playPauseBtn.visibility = View.VISIBLE
binding.playPauseBtn.icon = ContextCompat.getDrawable( binding.playPauseBtn.icon = ContextCompat.getDrawable(
@ -134,6 +138,8 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
) )
binding.seekbar.progress = SEEKBAR_START binding.seekbar.progress = SEEKBAR_START
message.resetVoiceMessage = false message.resetVoiceMessage = false
message.voiceMessagePlayedSeconds = 0
binding.voiceMessageDuration.visibility = View.GONE
} }
binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
@ -276,7 +282,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
if (!message.isDeleted && message.parentMessage != null) { if (!message.isDeleted && message.parentMessage != null) {
val parentChatMessage = message.parentMessage val parentChatMessage = message.parentMessage
parentChatMessage!!.activeUser = message.activeUser parentChatMessage!!.activeUser = message.activeUser
parentChatMessage!!.imageUrl?.let { parentChatMessage.imageUrl?.let {
binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
binding.messageQuote.quotedMessageImage.load(it) { binding.messageQuote.quotedMessageImage.load(it) {
addHeader( addHeader(

View file

@ -146,7 +146,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
} }
} }
binding.checkMark.setContentDescription(readStatusContentDescriptionString) binding.checkMark.contentDescription = readStatusContentDescriptionString
Reaction().showReactions( Reaction().showReactions(
message, message,
@ -175,6 +175,8 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
R.drawable.ic_baseline_play_arrow_voice_message_24 R.drawable.ic_baseline_play_arrow_voice_message_24
) )
binding.seekbar.progress = SEEKBAR_START binding.seekbar.progress = SEEKBAR_START
message.voiceMessagePlayedSeconds = 0
binding.voiceMessageDuration.visibility = View.GONE
message.resetVoiceMessage = false message.resetVoiceMessage = false
} }
} }
@ -194,7 +196,12 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
context!!, context!!,
R.drawable.ic_baseline_pause_voice_message_24 R.drawable.ic_baseline_pause_voice_message_24
) )
binding.seekbar.progress = message.voiceMessagePlayedSeconds
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.setProgress(message.voiceMessagePlayedSeconds, true)
} else { } else {
binding.playPauseBtn.visibility = View.VISIBLE binding.playPauseBtn.visibility = View.VISIBLE
binding.playPauseBtn.icon = ContextCompat.getDrawable( binding.playPauseBtn.icon = ContextCompat.getDrawable(

View file

@ -544,7 +544,7 @@ class ChatActivity :
sessionIdAfterRoomJoined sessionIdAfterRoomJoined
) )
} }
if (startCallFromNotification != null && startCallFromNotification ?: false) { if (startCallFromNotification != null && startCallFromNotification) {
startCallFromNotification = false startCallFromNotification = false
startACall(voiceOnly, false) startACall(voiceOnly, false)
} }
@ -584,11 +584,11 @@ class ChatActivity :
initSmileyKeyboardToggler() initSmileyKeyboardToggler()
binding?.messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.setOnClickListener { binding.messageInputView.findViewById<ImageButton>(R.id.cancelReplyButton)?.setOnClickListener {
cancelReply() cancelReply()
} }
binding?.messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.let { binding.messageInputView.findViewById<ImageButton>(R.id.cancelReplyButton)?.let {
viewThemeUtils.platform viewThemeUtils.platform
.themeImageButton(it) .themeImageButton(it)
} }
@ -601,9 +601,9 @@ class ChatActivity :
setupSwipeToReply() setupSwipeToReply()
binding?.popupBubbleView?.setRecyclerView(binding?.messagesListView) binding.popupBubbleView.setRecyclerView(binding.messagesListView)
binding?.popupBubbleView?.setPopupBubbleListener { context -> binding.popupBubbleView.setPopupBubbleListener { context ->
if (newMessagesCount != 0) { if (newMessagesCount != 0) {
val scrollPosition = if (newMessagesCount - 1 < 0) { val scrollPosition = if (newMessagesCount - 1 < 0) {
0 0
@ -612,41 +612,41 @@ class ChatActivity :
} }
Handler().postDelayed( Handler().postDelayed(
{ {
binding?.messagesListView?.smoothScrollToPosition(scrollPosition) binding.messagesListView.smoothScrollToPosition(scrollPosition)
}, },
NEW_MESSAGES_POPUP_BUBBLE_DELAY NEW_MESSAGES_POPUP_BUBBLE_DELAY
) )
} }
} }
binding?.scrollDownButton?.setOnClickListener { binding.scrollDownButton.setOnClickListener {
binding?.messagesListView?.scrollToPosition(0) binding.messagesListView.scrollToPosition(0)
it.visibility = View.GONE it.visibility = View.GONE
} }
binding?.let { viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it.scrollDownButton) } binding.let { viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it.scrollDownButton) }
binding?.let { viewThemeUtils.material.colorMaterialButtonPrimaryFilled(it.popupBubbleView) } binding.let { viewThemeUtils.material.colorMaterialButtonPrimaryFilled(it.popupBubbleView) }
binding?.messageInputView?.setPadding(0, 0, 0, 0) binding.messageInputView.setPadding(0, 0, 0, 0)
binding?.messagesListView?.addOnScrollListener(object : RecyclerView.OnScrollListener() { binding.messagesListView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
if (layoutManager!!.findFirstCompletelyVisibleItemPosition() > 0) { if (layoutManager!!.findFirstCompletelyVisibleItemPosition() > 0) {
binding?.scrollDownButton?.visibility = View.VISIBLE binding.scrollDownButton.visibility = View.VISIBLE
} else { } else {
binding?.scrollDownButton?.visibility = View.GONE binding.scrollDownButton.visibility = View.GONE
} }
if (newMessagesCount != 0 && layoutManager != null) { if (newMessagesCount != 0 && layoutManager != null) {
if (layoutManager!!.findFirstCompletelyVisibleItemPosition() < newMessagesCount) { if (layoutManager!!.findFirstCompletelyVisibleItemPosition() < newMessagesCount) {
newMessagesCount = 0 newMessagesCount = 0
if (binding?.popupBubbleView?.isShown == true) { if (binding.popupBubbleView.isShown == true) {
binding?.popupBubbleView?.hide() binding.popupBubbleView.hide()
} }
} }
} }
@ -658,9 +658,9 @@ class ChatActivity :
val lengthFilter = CapabilitiesUtilNew.getMessageMaxLength(conversationUser) val lengthFilter = CapabilitiesUtilNew.getMessageMaxLength(conversationUser)
filters[0] = InputFilter.LengthFilter(lengthFilter) filters[0] = InputFilter.LengthFilter(lengthFilter)
binding?.messageInputView?.inputEditText?.filters = filters binding.messageInputView.inputEditText?.filters = filters
binding?.messageInputView?.inputEditText?.addTextChangedListener(object : TextWatcher { binding.messageInputView.inputEditText?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// unused atm // unused atm
} }
@ -670,19 +670,19 @@ class ChatActivity :
updateOwnTypingStatus(s) updateOwnTypingStatus(s)
if (s.length >= lengthFilter) { if (s.length >= lengthFilter) {
binding?.messageInputView?.inputEditText?.error = String.format( binding.messageInputView.inputEditText?.error = String.format(
Objects.requireNonNull<Resources>(resources).getString(R.string.nc_limit_hit), Objects.requireNonNull<Resources>(resources).getString(R.string.nc_limit_hit),
lengthFilter.toString() lengthFilter.toString()
) )
} else { } else {
binding?.messageInputView?.inputEditText?.error = null binding.messageInputView.inputEditText?.error = null
} }
val editable = binding?.messageInputView?.inputEditText?.editableText val editable = binding.messageInputView.inputEditText?.editableText
if (editable != null && binding?.messageInputView?.inputEditText != null) { if (editable != null && binding.messageInputView.inputEditText != null) {
val mentionSpans = editable.getSpans( val mentionSpans = editable.getSpans(
0, 0,
binding?.messageInputView?.inputEditText!!.length(), binding.messageInputView.inputEditText!!.length(),
Spans.MentionChipSpan::class.java Spans.MentionChipSpan::class.java
) )
var mentionSpan: Spans.MentionChipSpan var mentionSpan: Spans.MentionChipSpan
@ -710,32 +710,32 @@ class ChatActivity :
// Image keyboard support // Image keyboard support
// See: https://developer.android.com/guide/topics/text/image-keyboard // See: https://developer.android.com/guide/topics/text/image-keyboard
(binding?.messageInputView?.inputEditText as ImageEmojiEditText).onCommitContentListener = { (binding.messageInputView.inputEditText as ImageEmojiEditText).onCommitContentListener = {
uploadFile(it.toString(), false) uploadFile(it.toString(), false)
} }
initVoiceRecordButton() initVoiceRecordButton()
if (sharedText.isNotEmpty()) { if (sharedText.isNotEmpty()) {
binding?.messageInputView?.inputEditText?.setText(sharedText) binding.messageInputView.inputEditText?.setText(sharedText)
} }
binding?.messageInputView?.setAttachmentsListener { binding.messageInputView.setAttachmentsListener {
AttachmentDialog(this, this).show() AttachmentDialog(this, this).show()
} }
binding?.messageInputView?.button?.setOnClickListener { submitMessage(false) } binding.messageInputView.button?.setOnClickListener { submitMessage(false) }
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-send")) { if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-send")) {
binding?.messageInputView?.button?.setOnLongClickListener { binding.messageInputView.button?.setOnLongClickListener {
showSendButtonMenu() showSendButtonMenu()
true true
} }
} }
binding?.messageInputView?.button?.contentDescription = binding.messageInputView.button?.contentDescription =
resources?.getString(R.string.nc_description_send_message_button) resources?.getString(R.string.nc_description_send_message_button)
binding?.messageInputView?.button?.let { viewThemeUtils.platform.colorImageView(it, ColorRole.PRIMARY) } binding.messageInputView.button?.let { viewThemeUtils.platform.colorImageView(it, ColorRole.PRIMARY) }
loadAvatarForStatusBar() loadAvatarForStatusBar()
setActionBarTitle() setActionBarTitle()
@ -892,8 +892,8 @@ class ChatActivity :
private fun initVoiceRecordButton() { private fun initVoiceRecordButton() {
showMicrophoneButton(true) showMicrophoneButton(true)
binding?.messageInputView?.messageInput?.doAfterTextChanged { binding.messageInputView.messageInput?.doAfterTextChanged {
if (binding?.messageInputView?.messageInput?.text?.isEmpty() == true) { if (binding.messageInputView.messageInput?.text?.isEmpty() == true) {
showMicrophoneButton(true) showMicrophoneButton(true)
} else { } else {
showMicrophoneButton(false) showMicrophoneButton(false)
@ -907,7 +907,7 @@ class ChatActivity :
var voiceRecordStartTime = 0L var voiceRecordStartTime = 0L
var voiceRecordEndTime = 0L var voiceRecordEndTime = 0L
binding?.messageInputView?.recordAudioButton?.setOnTouchListener(object : View.OnTouchListener { binding.messageInputView.recordAudioButton?.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean { override fun onTouch(v: View?, event: MotionEvent?): Boolean {
v?.performClick() // ????????? v?.performClick() // ?????????
when (event?.action) { when (event?.action) {
@ -937,7 +937,7 @@ class ChatActivity :
stopAndDiscardAudioRecording() stopAndDiscardAudioRecording()
showRecordAudioUi(false) showRecordAudioUi(false)
binding?.messageInputView?.slideToCancelDescription?.x = sliderInitX binding.messageInputView.slideToCancelDescription?.x = sliderInitX
} }
MotionEvent.ACTION_UP -> { MotionEvent.ACTION_UP -> {
@ -964,7 +964,7 @@ class ChatActivity :
stopAndSendAudioRecording() stopAndSendAudioRecording()
} }
binding?.messageInputView?.slideToCancelDescription?.x = sliderInitX binding.messageInputView.slideToCancelDescription?.x = sliderInitX
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
@ -980,25 +980,25 @@ class ChatActivity :
deltaX = movedX - downX deltaX = movedX - downX
// only allow slide to left // only allow slide to left
binding?.messageInputView?.slideToCancelDescription?.x?.let { binding.messageInputView.slideToCancelDescription?.x?.let {
if (sliderInitX == 0.0F) { if (sliderInitX == 0.0F) {
sliderInitX = it sliderInitX = it
} }
if (it > sliderInitX) { if (it > sliderInitX) {
binding?.messageInputView?.slideToCancelDescription?.x = sliderInitX binding.messageInputView.slideToCancelDescription?.x = sliderInitX
} }
} }
binding?.messageInputView?.slideToCancelDescription?.x?.let { binding.messageInputView.slideToCancelDescription?.x?.let {
if (it < VOICE_RECORD_CANCEL_SLIDER_X) { if (it < VOICE_RECORD_CANCEL_SLIDER_X) {
Log.d(TAG, "stopping recording because slider was moved to left") Log.d(TAG, "stopping recording because slider was moved to left")
stopAndDiscardAudioRecording() stopAndDiscardAudioRecording()
showRecordAudioUi(false) showRecordAudioUi(false)
binding?.messageInputView?.slideToCancelDescription?.x = sliderInitX binding.messageInputView.slideToCancelDescription?.x = sliderInitX
return true return true
} else { } else {
binding?.messageInputView?.slideToCancelDescription?.x = it + deltaX binding.messageInputView.slideToCancelDescription?.x = it + deltaX
downX = movedX downX = movedX
} }
} }
@ -1011,9 +1011,9 @@ class ChatActivity :
} }
private fun initSmileyKeyboardToggler() { private fun initSmileyKeyboardToggler() {
val smileyButton = binding?.messageInputView?.findViewById<ImageButton>(R.id.smileyButton) val smileyButton = binding.messageInputView.findViewById<ImageButton>(R.id.smileyButton)
emojiPopup = binding?.messageInputView?.inputEditText?.let { emojiPopup = binding.messageInputView.inputEditText?.let {
EmojiPopup( EmojiPopup(
rootView = binding.root, rootView = binding.root,
editText = it, editText = it,
@ -1030,7 +1030,7 @@ class ChatActivity :
) )
}, },
onEmojiClickListener = { onEmojiClickListener = {
binding?.messageInputView?.inputEditText?.editableText?.append(" ") binding.messageInputView.inputEditText?.editableText?.append(" ")
} }
) )
} }
@ -1204,7 +1204,7 @@ class ChatActivity :
) )
val itemTouchHelper = ItemTouchHelper(messageSwipeController) val itemTouchHelper = ItemTouchHelper(messageSwipeController)
itemTouchHelper.attachToRecyclerView(binding?.messagesListView) itemTouchHelper.attachToRecyclerView(binding.messagesListView)
} }
} }
@ -1311,7 +1311,7 @@ class ChatActivity :
private fun showSendButtonMenu() { private fun showSendButtonMenu() {
val popupMenu = PopupMenu( val popupMenu = PopupMenu(
ContextThemeWrapper(this, R.style.ChatSendButtonMenu), ContextThemeWrapper(this, R.style.ChatSendButtonMenu),
binding?.messageInputView?.button, binding.messageInputView.button,
Gravity.END Gravity.END
) )
popupMenu.inflate(R.menu.chat_send_menu) popupMenu.inflate(R.menu.chat_send_menu)
@ -1376,11 +1376,21 @@ class ChatActivity :
mediaPlayerHandler = Handler() mediaPlayerHandler = Handler()
runOnUiThread(object : Runnable { runOnUiThread(object : Runnable {
var timeElapsed = if (message.voiceMessagePlayedSeconds > 0) message.voiceMessagePlayedSeconds else 0
override fun run() { override fun run() {
if (mediaPlayer != null) { if (mediaPlayer != null) {
val currentPosition: Int = mediaPlayer!!.currentPosition / VOICE_MESSAGE_SEEKBAR_BASE if (message.isPlayingVoiceMessage) {
message.voiceMessagePlayedSeconds = currentPosition if (timeElapsed < (mediaPlayer!!.duration / VOICE_MESSAGE_SEEKBAR_BASE)) {
adapter?.update(message) timeElapsed += 1
message.voiceMessagePlayedSeconds = timeElapsed
adapter?.update(message)
} else {
message.resetVoiceMessage = true
adapter?.update(message)
timeElapsed = 0
stopMediaPlayer(message)
}
}
} }
mediaPlayerHandler.postDelayed(this, SECOND) mediaPlayerHandler.postDelayed(this, SECOND)
} }
@ -1536,23 +1546,23 @@ class ChatActivity :
private fun showRecordAudioUi(show: Boolean) { private fun showRecordAudioUi(show: Boolean) {
if (show) { if (show) {
binding?.messageInputView?.microphoneEnabledInfo?.visibility = View.VISIBLE binding.messageInputView.microphoneEnabledInfo?.visibility = View.VISIBLE
binding?.messageInputView?.microphoneEnabledInfoBackground?.visibility = View.VISIBLE binding.messageInputView.microphoneEnabledInfoBackground?.visibility = View.VISIBLE
binding?.messageInputView?.audioRecordDuration?.visibility = View.VISIBLE binding.messageInputView.audioRecordDuration?.visibility = View.VISIBLE
binding?.messageInputView?.slideToCancelDescription?.visibility = View.VISIBLE binding.messageInputView.slideToCancelDescription?.visibility = View.VISIBLE
binding?.messageInputView?.attachmentButton?.visibility = View.GONE binding.messageInputView.attachmentButton?.visibility = View.GONE
binding?.messageInputView?.smileyButton?.visibility = View.GONE binding.messageInputView.smileyButton?.visibility = View.GONE
binding?.messageInputView?.messageInput?.visibility = View.GONE binding.messageInputView.messageInput?.visibility = View.GONE
binding?.messageInputView?.messageInput?.hint = "" binding.messageInputView.messageInput?.hint = ""
} else { } else {
binding?.messageInputView?.microphoneEnabledInfo?.visibility = View.GONE binding.messageInputView.microphoneEnabledInfo?.visibility = View.GONE
binding?.messageInputView?.microphoneEnabledInfoBackground?.visibility = View.GONE binding.messageInputView.microphoneEnabledInfoBackground?.visibility = View.GONE
binding?.messageInputView?.audioRecordDuration?.visibility = View.GONE binding.messageInputView.audioRecordDuration?.visibility = View.GONE
binding?.messageInputView?.slideToCancelDescription?.visibility = View.GONE binding.messageInputView.slideToCancelDescription?.visibility = View.GONE
binding?.messageInputView?.attachmentButton?.visibility = View.VISIBLE binding.messageInputView.attachmentButton?.visibility = View.VISIBLE
binding?.messageInputView?.smileyButton?.visibility = View.VISIBLE binding.messageInputView.smileyButton?.visibility = View.VISIBLE
binding?.messageInputView?.messageInput?.visibility = View.VISIBLE binding.messageInputView.messageInput?.visibility = View.VISIBLE
binding?.messageInputView?.messageInput?.hint = binding.messageInputView.messageInput?.hint =
context.resources?.getString(R.string.nc_hint_enter_a_message) context.resources?.getString(R.string.nc_hint_enter_a_message)
} }
} }
@ -1565,15 +1575,15 @@ class ChatActivity :
} }
private fun startAudioRecording(file: String) { private fun startAudioRecording(file: String) {
binding?.messageInputView?.audioRecordDuration?.base = SystemClock.elapsedRealtime() binding.messageInputView.audioRecordDuration?.base = SystemClock.elapsedRealtime()
binding?.messageInputView?.audioRecordDuration?.start() binding.messageInputView.audioRecordDuration?.start()
val animation: Animation = AlphaAnimation(1.0f, 0.0f) val animation: Animation = AlphaAnimation(1.0f, 0.0f)
animation.duration = ANIMATION_DURATION animation.duration = ANIMATION_DURATION
animation.interpolator = LinearInterpolator() animation.interpolator = LinearInterpolator()
animation.repeatCount = Animation.INFINITE animation.repeatCount = Animation.INFINITE
animation.repeatMode = Animation.REVERSE animation.repeatMode = Animation.REVERSE
binding?.messageInputView?.microphoneEnabledInfo?.startAnimation(animation) binding.messageInputView.microphoneEnabledInfo?.startAnimation(animation)
recorder = MediaRecorder().apply { recorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.MIC) setAudioSource(MediaRecorder.AudioSource.MIC)
@ -1616,8 +1626,8 @@ class ChatActivity :
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
private fun stopAudioRecording() { private fun stopAudioRecording() {
binding?.messageInputView?.audioRecordDuration?.stop() binding.messageInputView.audioRecordDuration?.stop()
binding?.messageInputView?.microphoneEnabledInfo?.clearAnimation() binding.messageInputView.microphoneEnabledInfo?.clearAnimation()
if (isVoiceRecordingInProgress) { if (isVoiceRecordingInProgress) {
recorder?.apply { recorder?.apply {
@ -1698,9 +1708,9 @@ class ChatActivity :
shouldShowLobby() || shouldShowLobby() ||
!participantPermissions.hasChatPermission() !participantPermissions.hasChatPermission()
) { ) {
binding?.messageInputView?.visibility = View.GONE binding.messageInputView.visibility = View.GONE
} else { } else {
binding?.messageInputView?.visibility = View.VISIBLE binding.messageInputView.visibility = View.VISIBLE
} }
} }
@ -1751,10 +1761,10 @@ class ChatActivity :
ConversationUtils.isLobbyViewApplicable(currentConversation!!, conversationUser!!) ConversationUtils.isLobbyViewApplicable(currentConversation!!, conversationUser!!)
) { ) {
if (shouldShowLobby()) { if (shouldShowLobby()) {
binding?.lobby?.lobbyView?.visibility = View.VISIBLE binding.lobby.lobbyView?.visibility = View.VISIBLE
binding?.messagesListView?.visibility = View.GONE binding.messagesListView.visibility = View.GONE
binding?.messageInputView?.visibility = View.GONE binding.messageInputView.visibility = View.GONE
binding?.progressBar?.visibility = View.GONE binding.progressBar.visibility = View.GONE
val sb = StringBuilder() val sb = StringBuilder()
sb.append(resources!!.getText(R.string.nc_lobby_waiting)) sb.append(resources!!.getText(R.string.nc_lobby_waiting))
@ -1775,11 +1785,11 @@ class ChatActivity :
} }
sb.append(currentConversation!!.description) sb.append(currentConversation!!.description)
binding?.lobby?.lobbyTextView?.text = sb.toString() binding.lobby.lobbyTextView?.text = sb.toString()
} else { } else {
binding?.lobby?.lobbyView?.visibility = View.GONE binding.lobby.lobbyView?.visibility = View.GONE
binding?.messagesListView?.visibility = View.VISIBLE binding.messagesListView.visibility = View.VISIBLE
binding?.messageInputView?.inputEditText?.visibility = View.VISIBLE binding.messageInputView.inputEditText?.visibility = View.VISIBLE
if (isFirstMessagesProcessing && pastPreconditionFailed) { if (isFirstMessagesProcessing && pastPreconditionFailed) {
pastPreconditionFailed = false pastPreconditionFailed = false
pullChatMessages(false) pullChatMessages(false)
@ -1789,9 +1799,9 @@ class ChatActivity :
} }
} }
} else { } else {
binding?.lobby?.lobbyView?.visibility = View.GONE binding.lobby.lobbyView?.visibility = View.GONE
binding?.messagesListView?.visibility = View.VISIBLE binding.messagesListView.visibility = View.VISIBLE
binding?.messageInputView?.inputEditText?.visibility = View.VISIBLE binding.messageInputView.inputEditText?.visibility = View.VISIBLE
} }
} }
@ -1856,7 +1866,7 @@ class ChatActivity :
} }
} }
binding?.messageInputView?.context?.let { binding.messageInputView.context?.let {
val materialAlertDialogBuilder = MaterialAlertDialogBuilder(it) val materialAlertDialogBuilder = MaterialAlertDialogBuilder(it)
.setTitle(confirmationQuestion) .setTitle(confirmationQuestion)
.setMessage(filenamesWithLineBreaks.toString()) .setMessage(filenamesWithLineBreaks.toString())
@ -1969,7 +1979,7 @@ class ChatActivity :
it.item is ChatMessage && (it.item as ChatMessage).id == messageId it.item is ChatMessage && (it.item as ChatMessage).id == messageId
} }
if (position != null && position >= 0) { if (position != null && position >= 0) {
binding?.messagesListView?.smoothScrollToPosition(position) binding.messagesListView.smoothScrollToPosition(position)
} else { } else {
// TODO show error that we don't have that message? // TODO show error that we don't have that message?
} }
@ -2075,7 +2085,7 @@ class ChatActivity :
require(fileUri.isNotEmpty()) require(fileUri.isNotEmpty())
UploadAndShareFilesWorker.upload( UploadAndShareFilesWorker.upload(
fileUri, fileUri,
roomToken!!, roomToken,
currentConversation?.displayName!!, currentConversation?.displayName!!,
metaData metaData
) )
@ -2146,12 +2156,12 @@ class ChatActivity :
val callback = MentionAutocompleteCallback( val callback = MentionAutocompleteCallback(
this, this,
conversationUser!!, conversationUser!!,
binding?.messageInputView?.inputEditText, binding.messageInputView.inputEditText,
viewThemeUtils viewThemeUtils
) )
if (mentionAutocomplete == null && binding?.messageInputView?.inputEditText != null) { if (mentionAutocomplete == null && binding.messageInputView.inputEditText != null) {
mentionAutocomplete = Autocomplete.on<Mention>(binding?.messageInputView?.inputEditText) mentionAutocomplete = Autocomplete.on<Mention>(binding.messageInputView.inputEditText)
.with(elevation) .with(elevation)
.with(backgroundDrawable) .with(backgroundDrawable)
.with(MagicCharPolicy('@')) .with(MagicCharPolicy('@'))
@ -2169,8 +2179,8 @@ class ChatActivity :
} }
private fun cancelReply() { private fun cancelReply() {
binding?.messageInputView?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.visibility = View.GONE binding.messageInputView.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.visibility = View.GONE
binding?.messageInputView?.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.VISIBLE binding.messageInputView.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.VISIBLE
} }
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
@ -2181,7 +2191,7 @@ class ChatActivity :
NotificationUtils.cancelExistingNotificationsForRoom( NotificationUtils.cancelExistingNotificationsForRoom(
applicationContext, applicationContext,
conversationUser!!, conversationUser!!,
roomToken!! roomToken
) )
} catch (e: RuntimeException) { } catch (e: RuntimeException) {
Log.w(TAG, "Cancel notifications for current conversation results with an error.", e) Log.w(TAG, "Cancel notifications for current conversation results with an error.", e)
@ -2225,7 +2235,7 @@ class ChatActivity :
} }
private fun isActivityNotChangingConfigurations(): Boolean { private fun isActivityNotChangingConfigurations(): Boolean {
return !isChangingConfigurations!! return !isChangingConfigurations
} }
private fun isNotInCall(): Boolean { private fun isNotInCall(): Boolean {
@ -2291,7 +2301,7 @@ class ChatActivity :
if (webSocketInstance != null) { if (webSocketInstance != null) {
webSocketInstance?.joinRoomWithRoomTokenAndSession( webSocketInstance?.joinRoomWithRoomTokenAndSession(
roomToken!!, roomToken,
sessionIdAfterRoomJoined sessionIdAfterRoomJoined
) )
} }
@ -2371,8 +2381,8 @@ class ChatActivity :
} }
private fun submitMessage(sendWithoutNotification: Boolean) { private fun submitMessage(sendWithoutNotification: Boolean) {
if (binding?.messageInputView?.inputEditText != null) { if (binding.messageInputView.inputEditText != null) {
val editable = binding?.messageInputView?.inputEditText!!.editableText val editable = binding.messageInputView.inputEditText!!.editableText
val mentionSpans = editable.getSpans( val mentionSpans = editable.getSpans(
0, 0,
editable.length, editable.length,
@ -2391,7 +2401,7 @@ class ChatActivity :
editable.replace(editable.getSpanStart(mentionSpan), editable.getSpanEnd(mentionSpan), "@$mentionId") editable.replace(editable.getSpanStart(mentionSpan), editable.getSpanEnd(mentionSpan), "@$mentionId")
} }
binding?.messageInputView?.inputEditText?.setText("") binding.messageInputView.inputEditText?.setText("")
sendStopTypingMessage() sendStopTypingMessage()
val replyMessageId: Int? = findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.tag as Int? val replyMessageId: Int? = findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.tag as Int?
sendMessage( sendMessage(
@ -2430,10 +2440,10 @@ class ChatActivity :
override fun onNext(genericOverall: GenericOverall) { override fun onNext(genericOverall: GenericOverall) {
myFirstMessage = message myFirstMessage = message
if (binding?.popupBubbleView?.isShown == true) { if (binding.popupBubbleView.isShown == true) {
binding?.popupBubbleView?.hide() binding.popupBubbleView.hide()
} }
binding?.messagesListView?.smoothScrollToPosition(0) binding.messagesListView.smoothScrollToPosition(0)
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
@ -2442,11 +2452,11 @@ class ChatActivity :
if (code.toString().startsWith("2")) { if (code.toString().startsWith("2")) {
myFirstMessage = message myFirstMessage = message
if (binding?.popupBubbleView?.isShown == true) { if (binding.popupBubbleView.isShown == true) {
binding?.popupBubbleView?.hide() binding.popupBubbleView.hide()
} }
binding?.messagesListView?.smoothScrollToPosition(0) binding.messagesListView.smoothScrollToPosition(0)
} }
} }
} }
@ -2582,8 +2592,8 @@ class ChatActivity :
if (isFirstMessagesProcessing) { if (isFirstMessagesProcessing) {
cancelNotificationsForCurrentConversation() cancelNotificationsForCurrentConversation()
isFirstMessagesProcessing = false isFirstMessagesProcessing = false
binding?.progressBar?.visibility = View.GONE binding.progressBar.visibility = View.GONE
binding?.messagesListView?.visibility = View.VISIBLE binding.messagesListView.visibility = View.VISIBLE
} }
} }
@ -2764,17 +2774,17 @@ class ChatActivity :
private fun modifyMessageCount(shouldAddNewMessagesNotice: Boolean, shouldScroll: Boolean) { private fun modifyMessageCount(shouldAddNewMessagesNotice: Boolean, shouldScroll: Boolean) {
if (!shouldAddNewMessagesNotice && !shouldScroll) { if (!shouldAddNewMessagesNotice && !shouldScroll) {
binding?.popupBubbleView?.isShown?.let { binding.popupBubbleView.isShown?.let {
if (it) { if (it) {
newMessagesCount++ newMessagesCount++
} else { } else {
newMessagesCount = 1 newMessagesCount = 1
binding?.scrollDownButton?.visibility = View.GONE binding.scrollDownButton.visibility = View.GONE
binding?.popupBubbleView?.show() binding.popupBubbleView.show()
} }
} }
} else { } else {
binding?.scrollDownButton?.visibility = View.GONE binding.scrollDownButton.visibility = View.GONE
newMessagesCount = 0 newMessagesCount = 0
} }
} }
@ -2886,7 +2896,7 @@ class ChatActivity :
super.onCreateOptionsMenu(menu) super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.menu_conversation, menu) menuInflater.inflate(R.menu.menu_conversation, menu)
binding?.messageInputView?.context?.let { binding.messageInputView.context?.let {
viewThemeUtils.platform.colorToolbarMenuIcon( viewThemeUtils.platform.colorToolbarMenuIcon(
it, it,
menu.findItem(R.id.conversation_voice_call) menu.findItem(R.id.conversation_voice_call)
@ -3400,21 +3410,21 @@ class ChatActivity :
fun replyToMessage(message: IMessage?) { fun replyToMessage(message: IMessage?) {
val chatMessage = message as ChatMessage? val chatMessage = message as ChatMessage?
chatMessage?.let { chatMessage?.let {
binding?.messageInputView?.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = binding.messageInputView.findViewById<ImageButton>(R.id.attachmentButton)?.visibility =
View.GONE View.GONE
binding?.messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility = binding.messageInputView.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility =
View.VISIBLE View.VISIBLE
val quotedMessage = binding?.messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage) val quotedMessage = binding.messageInputView.findViewById<EmojiTextView>(R.id.quotedMessage)
quotedMessage?.maxLines = 2 quotedMessage?.maxLines = 2
quotedMessage?.ellipsize = TextUtils.TruncateAt.END quotedMessage?.ellipsize = TextUtils.TruncateAt.END
quotedMessage?.text = it.text quotedMessage?.text = it.text
binding?.messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text = binding.messageInputView.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text =
it.actorDisplayName ?: context.getText(R.string.nc_nick_guest) it.actorDisplayName ?: context.getText(R.string.nc_nick_guest)
conversationUser?.let { conversationUser?.let {
val quotedMessageImage = binding?.messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage) val quotedMessageImage = binding.messageInputView.findViewById<ImageView>(R.id.quotedMessageImage)
chatMessage.imageUrl?.let { previewImageUrl -> chatMessage.imageUrl?.let { previewImageUrl ->
quotedMessageImage?.visibility = View.VISIBLE quotedMessageImage?.visibility = View.VISIBLE
@ -3432,12 +3442,12 @@ class ChatActivity :
addHeader("Authorization", credentials!!) addHeader("Authorization", credentials!!)
} }
} ?: run { } ?: run {
binding?.messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.GONE binding.messageInputView.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.GONE
} }
} }
val quotedChatMessageView = val quotedChatMessageView =
binding?.messageInputView?.findViewById<RelativeLayout>(R.id.quotedChatMessageView) binding.messageInputView.findViewById<RelativeLayout>(R.id.quotedChatMessageView)
quotedChatMessageView?.tag = message?.jsonMessageId quotedChatMessageView?.tag = message?.jsonMessageId
quotedChatMessageView?.visibility = View.VISIBLE quotedChatMessageView?.visibility = View.VISIBLE
} }
@ -3445,11 +3455,11 @@ class ChatActivity :
private fun showMicrophoneButton(show: Boolean) { private fun showMicrophoneButton(show: Boolean) {
if (show && CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "voice-message-sharing")) { if (show && CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "voice-message-sharing")) {
binding?.messageInputView?.messageSendButton?.visibility = View.GONE binding.messageInputView.messageSendButton?.visibility = View.GONE
binding?.messageInputView?.recordAudioButton?.visibility = View.VISIBLE binding.messageInputView.recordAudioButton?.visibility = View.VISIBLE
} else { } else {
binding?.messageInputView?.messageSendButton?.visibility = View.VISIBLE binding.messageInputView.messageSendButton?.visibility = View.VISIBLE
binding?.messageInputView?.recordAudioButton?.visibility = View.GONE binding.messageInputView.recordAudioButton?.visibility = View.GONE
} }
} }
@ -3666,7 +3676,7 @@ class ChatActivity :
fun createPoll() { fun createPoll() {
val pollVoteDialog = PollCreateDialogFragment.newInstance( val pollVoteDialog = PollCreateDialogFragment.newInstance(
roomToken!! roomToken
) )
pollVoteDialog.show(supportFragmentManager, TAG) pollVoteDialog.show(supportFragmentManager, TAG)
} }
@ -3729,7 +3739,7 @@ class ChatActivity :
private const val VIDEO_SUFFIX = ".mp4" private const val VIDEO_SUFFIX = ".mp4"
private const val FULLY_OPAQUE_INT: Int = 255 private const val FULLY_OPAQUE_INT: Int = 255
private const val SEMI_TRANSPARENT_INT: Int = 99 private const val SEMI_TRANSPARENT_INT: Int = 99
private const val VOICE_MESSAGE_SEEKBAR_BASE: Int = 1000 private const val VOICE_MESSAGE_SEEKBAR_BASE = 1000
private const val SECOND: Long = 1000 private const val SECOND: Long = 1000
private const val NO_PREVIOUS_MESSAGE_ID: Int = -1 private const val NO_PREVIOUS_MESSAGE_ID: Int = -1
private const val GROUPED_MESSAGES_THRESHOLD = 4 private const val GROUPED_MESSAGES_THRESHOLD = 4

View file

@ -95,8 +95,16 @@
android:id="@+id/seekbar" android:id="@+id/seekbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"
tools:progress="50" /> tools:progress="50" />
<TextView
android:id="@+id/voiceMessageDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
tools:text="00:00" />
</LinearLayout> </LinearLayout>
<TextView <TextView

View file

@ -82,7 +82,14 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="40dp" android:layout_height="40dp"
android:thumb="@drawable/voice_message_outgoing_seek_bar_slider" android:thumb="@drawable/voice_message_outgoing_seek_bar_slider"
tools:progress="50" /> tools:progress="50"
android:layout_weight="1" />
<TextView
android:id="@+id/voiceMessageDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout> </LinearLayout>