Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Showing temporary messages when queued #4251

Merged
merged 14 commits into from
Oct 22, 2024
4 changes: 4 additions & 0 deletions .idea/inspectionProfiles/ktlint.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,14 @@ import com.nextcloud.talk.ui.dialog.AudioOutputDialog
import com.nextcloud.talk.ui.dialog.MoreCallActionsDialog
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.SpreedFeatures
import com.nextcloud.talk.utils.CapabilitiesUtil
import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability
import com.nextcloud.talk.utils.CapabilitiesUtil.isCallRecordingAvailable
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.NotificationUtils.cancelExistingNotificationsForRoom
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
import com.nextcloud.talk.utils.ReceiverFlag
import com.nextcloud.talk.utils.SpreedFeatures
import com.nextcloud.talk.utils.VibrationUtils.vibrateShort
import com.nextcloud.talk.utils.animations.PulseAnimation
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY
Expand All @@ -117,9 +120,6 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_START_CALL_AFTER_ROOM_SWITCH
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SWITCH_TO_ROOM
import com.nextcloud.talk.utils.CapabilitiesUtil
import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability
import com.nextcloud.talk.utils.CapabilitiesUtil.isCallRecordingAvailable
import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil
import com.nextcloud.talk.utils.power.PowerManagerUtils
import com.nextcloud.talk.utils.registerPermissionHandlerBroadcastReceiver
Expand All @@ -129,9 +129,9 @@ import com.nextcloud.talk.viewmodels.CallRecordingViewModel.RecordingConfirmStop
import com.nextcloud.talk.viewmodels.CallRecordingViewModel.RecordingErrorState
import com.nextcloud.talk.viewmodels.CallRecordingViewModel.RecordingStartedState
import com.nextcloud.talk.viewmodels.CallRecordingViewModel.RecordingStartingState
import com.nextcloud.talk.webrtc.WebRTCUtils
import com.nextcloud.talk.webrtc.PeerConnectionWrapper
import com.nextcloud.talk.webrtc.PeerConnectionWrapper.PeerConnectionObserver
import com.nextcloud.talk.webrtc.WebRTCUtils
import com.nextcloud.talk.webrtc.WebRtcAudioManager
import com.nextcloud.talk.webrtc.WebRtcAudioManager.AudioDevice
import com.nextcloud.talk.webrtc.WebSocketConnectionHelper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public void onBindViewHolder(ViewHolder holder, int position) {
((SystemMessageViewHolder) holder).assignSystemMessageInterface(chatActivity);
} else if (holder instanceof CallStartedViewHolder) {
((CallStartedViewHolder) holder).assignCallStartedMessageInterface(chatActivity);
} else if (holder instanceof TemporaryMessageViewHolder) {
((TemporaryMessageViewHolder) holder).assignTemporaryMessageInterface(chatActivity);
}

super.onBindViewHolder(holder, position);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Julius Linus <[email protected]>
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package com.nextcloud.talk.adapters.messages

interface TemporaryMessageInterface {
fun editTemporaryMessage(id: Int, newMessage: String)
fun deleteTemporaryMessage(id: Int)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Julius Linus <[email protected]>
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package com.nextcloud.talk.adapters.messages

import android.content.Context
import android.util.Log
import android.view.View
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import autodagger.AutoInjector
import coil.load
import com.nextcloud.android.common.ui.theme.utils.ColorRole
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.chat.data.model.ChatMessage
import com.nextcloud.talk.databinding.ItemTemporaryMessageBinding
import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.message.MessageUtils
import com.stfalcon.chatkit.messages.MessagesListAdapter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject

@AutoInjector(NextcloudTalkApplication::class)
class TemporaryMessageViewHolder(outgoingView: View, payload: Any) :
MessagesListAdapter.OutcomingMessageViewHolder<ChatMessage>(outgoingView) {

private val binding: ItemTemporaryMessageBinding = ItemTemporaryMessageBinding.bind(outgoingView)

@Inject
lateinit var viewThemeUtils: ViewThemeUtils

@Inject
lateinit var context: Context

@Inject
lateinit var messageUtils: MessageUtils

lateinit var temporaryMessageInterface: TemporaryMessageInterface
var isEditing = false

override fun onBind(message: ChatMessage) {
super.onBind(message)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)

viewThemeUtils.platform.colorImageView(binding.tempMsgEdit, ColorRole.PRIMARY)
viewThemeUtils.platform.colorImageView(binding.tempMsgDelete, ColorRole.PRIMARY)

binding.tempMsgEdit.setOnClickListener {
isEditing = !isEditing
if (isEditing) {
binding.tempMsgEdit.setImageDrawable(
ResourcesCompat.getDrawable(
context.resources,
R.drawable.ic_check,
null
)
)
binding.messageEdit.visibility = View.VISIBLE
binding.messageEdit.requestFocus()
ViewCompat.getWindowInsetsController(binding.root)?.show(WindowInsetsCompat.Type.ime())
binding.messageEdit.setText(binding.messageText.text)
binding.messageText.visibility = View.GONE
} else {
binding.tempMsgEdit.setImageDrawable(
ResourcesCompat.getDrawable(
context.resources,
R.drawable.ic_edit,
null
)
)
binding.messageEdit.visibility = View.GONE
binding.messageText.visibility = View.VISIBLE
val newMessage = binding.messageEdit.text.toString()
message.message = newMessage
temporaryMessageInterface.editTemporaryMessage(message.tempMessageId, newMessage)
}
}

binding.tempMsgDelete.setOnClickListener {
temporaryMessageInterface.deleteTemporaryMessage(message.tempMessageId)
}

// parent message handling
if (message.parentMessageId != null && message.parentMessageId!! > 0) {
processParentMessage(message)
binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
} else {
binding.messageQuote.quotedChatMessageView.visibility = View.GONE
}

val bgBubbleColor = bubble.resources.getColor(R.color.bg_message_list_incoming_bubble, null)
val layout = R.drawable.shape_outcoming_message
val bubbleDrawable = DisplayUtils.getMessageSelector(
bgBubbleColor,
ResourcesCompat.getColor(bubble.resources, R.color.transparent, null),
bgBubbleColor,
layout
)
ViewCompat.setBackground(bubble, bubbleDrawable)
}

private fun processParentMessage(message: ChatMessage) {
if (message.parentMessageId != null && !message.isDeleted) {
CoroutineScope(Dispatchers.Main).launch {
try {
val chatActivity = temporaryMessageInterface as ChatActivity
val urlForChatting = ApiUtils.getUrlForChat(
chatActivity.chatApiVersion,
chatActivity.conversationUser?.baseUrl,
chatActivity.roomToken
)

val parentChatMessage = withContext(Dispatchers.IO) {
chatActivity.chatViewModel.getMessageById(
urlForChatting,
chatActivity.currentConversation!!,
message.parentMessageId!!
).first()
}

parentChatMessage!!.activeUser = message.activeUser
parentChatMessage.imageUrl?.let {
binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
val placeholder = context.resources.getDrawable(R.drawable.ic_mimetype_image)
binding.messageQuote.quotedMessageImage.setImageDrawable(placeholder)
binding.messageQuote.quotedMessageImage.load(it) {
addHeader(
"Authorization",
ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!!
)
}
} ?: run {
binding.messageQuote.quotedMessageImage.visibility = View.GONE
}
binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
?: context.getText(R.string.nc_nick_guest)
binding.messageQuote.quotedMessage.text = messageUtils
.enrichChatReplyMessageText(
binding.messageQuote.quotedMessage.context,
parentChatMessage,
false,
viewThemeUtils
)

viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)

binding.messageQuote.quotedChatMessageView.setOnClickListener {
val chatActivity = temporaryMessageInterface as ChatActivity
chatActivity.jumpToQuotedMessage(parentChatMessage)
}
} catch (e: Exception) {
Log.d(TAG, "Error when processing parent message in view holder", e)
}
}
}
}

fun assignTemporaryMessageInterface(temporaryMessageInterface: TemporaryMessageInterface) {
this.temporaryMessageInterface = temporaryMessageInterface
}

override fun viewDetached() {
// unused atm
}

override fun viewAttached() {
// unused atm
}

override fun viewRecycled() {
// unused atm
}

companion object {
private val TAG = TemporaryMessageViewHolder::class.java.simpleName
}
}
Loading
Loading