Skip to content

Commit

Permalink
Merge pull request #4423 from nextcloud/issue-4404-better-indicator-f…
Browse files Browse the repository at this point in the history
…or-calls

Better call started indicator
  • Loading branch information
mahibi authored Nov 21, 2024
2 parents 73228bd + 990f6ec commit 90c6eb0
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 180 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ public void onBindViewHolder(ViewHolder holder, int position) {
} else if (holder instanceof SystemMessageViewHolder holderInstance) {
holderInstance.assignSystemMessageInterface(chatActivity);

} else if (holder instanceof CallStartedViewHolder holderInstance) {
holderInstance.assignCallStartedMessageInterface(chatActivity);

} else if (holder instanceof TemporaryMessageViewHolder holderInstance) {
holderInstance.assignTemporaryMessageInterface(chatActivity);

Expand Down
39 changes: 9 additions & 30 deletions app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.activities.CallActivity
import com.nextcloud.talk.activities.TakePhotoActivity
import com.nextcloud.talk.adapters.messages.CallStartedMessageInterface
import com.nextcloud.talk.adapters.messages.CallStartedViewHolder
import com.nextcloud.talk.adapters.messages.CommonMessageInterface
import com.nextcloud.talk.adapters.messages.IncomingDeckCardViewHolder
import com.nextcloud.talk.adapters.messages.IncomingLinkPreviewMessageViewHolder
Expand Down Expand Up @@ -883,7 +882,7 @@ class ChatActivity :
}

processExpiredMessages()
processCallStartedMessages(chatMessageList)
processCallStartedMessages()

adapter?.notifyDataSetChanged()
}
Expand Down Expand Up @@ -1203,17 +1202,6 @@ class ChatActivity :
R.layout.item_custom_outcoming_preview_message
)

messageHolders.registerContentType(
CONTENT_TYPE_CALL_STARTED,
CallStartedViewHolder::class.java,
payload,
R.layout.call_started_message,
CallStartedViewHolder::class.java,
payload,
R.layout.call_started_message,
this
)

messageHolders.registerContentType(
CONTENT_TYPE_TEMP,
TemporaryMessageViewHolder::class.java,
Expand Down Expand Up @@ -2577,7 +2565,7 @@ class ChatActivity :
}
}

private fun processCallStartedMessages(chatMessageList: List<ChatMessage>) {
private fun processCallStartedMessages() {
try {
val mostRecentCallSystemMessage = adapter?.items?.first {
it.item is ChatMessage &&
Expand All @@ -2595,8 +2583,7 @@ class ChatActivity :

if (mostRecentCallSystemMessage != null) {
processMostRecentMessage(
mostRecentCallSystemMessage as ChatMessage,
chatMessageList
mostRecentCallSystemMessage as ChatMessage
)
}
} catch (e: NoSuchElementException) {
Expand Down Expand Up @@ -3563,29 +3550,21 @@ class ChatActivity :
else -> false
}

private fun processMostRecentMessage(recent: ChatMessage, chatMessageList: List<ChatMessage>) {
private fun processMostRecentMessage(recent: ChatMessage) {
when (recent.systemMessageType) {
ChatMessage.SystemMessageType.CALL_STARTED -> { // add CallStartedMessage with id -2
ChatMessage.SystemMessageType.CALL_STARTED -> {
if (!callStarted) {
val callStartedChatMessage = ChatMessage()
callStartedChatMessage.jsonMessageId = CALL_STARTED_ID
callStartedChatMessage.actorId = "-2"
val name = if (recent.actorDisplayName.isNullOrEmpty()) "Guest" else recent.actorDisplayName
callStartedChatMessage.actorDisplayName = name
callStartedChatMessage.actorType = recent.actorType
callStartedChatMessage.timestamp = chatMessageList[0].timestamp
callStartedChatMessage.message = null
adapter?.addToStart(callStartedChatMessage, false)
messageInputViewModel.showCallStartedIndicator(recent, true)
callStarted = true
}
} // remove CallStartedMessage with id -2
}
ChatMessage.SystemMessageType.CALL_ENDED,
ChatMessage.SystemMessageType.CALL_MISSED,
ChatMessage.SystemMessageType.CALL_TRIED,
ChatMessage.SystemMessageType.CALL_ENDED_EVERYONE -> {
adapter?.deleteById("-2")
callStarted = false
} // remove message of id -2
messageInputViewModel.showCallStartedIndicator(recent, false)
}
else -> {}
}
}
Expand Down
101 changes: 101 additions & 0 deletions app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.nextcloud.talk.chat

import android.content.res.Resources
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.os.CountDownTimer
Expand Down Expand Up @@ -36,14 +37,19 @@ import android.widget.PopupMenu
import android.widget.RelativeLayout
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.content.ContextCompat
import androidx.core.widget.doAfterTextChanged
import androidx.emoji2.widget.EmojiTextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import autodagger.AutoInjector
import coil.Coil.imageLoader
import coil.load
import coil.request.ImageRequest
import coil.target.Target
import coil.transform.CircleCropTransformation
import com.google.android.flexbox.FlexboxLayout
import com.google.android.material.button.MaterialButton
import com.google.android.material.snackbar.Snackbar
Expand Down Expand Up @@ -119,6 +125,7 @@ class MessageInputFragment : Fragment() {
private var mentionAutocomplete: Autocomplete<*>? = null
private var xcounter = 0f
private var ycounter = 0f
private var isCollapsed = false

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -201,6 +208,49 @@ class MessageInputFragment : Fragment() {
binding.fragmentConnectionLost.text = getString(R.string.connection_lost_sent_messages_are_queued)
}
}

chatActivity.messageInputViewModel.callStartedFlow.observe(viewLifecycleOwner) {
val (message, show) = it
if (show) {
binding.fragmentCallStarted.callAuthorChip.text = message.actorDisplayName
binding.fragmentCallStarted.callAuthorChipSecondary.text = message.actorDisplayName
val user = userManager.currentUser.blockingGet()
val url: String = if (message.actorType == "guests" || message.actorType == "guest") {
ApiUtils.getUrlForGuestAvatar(
user!!.baseUrl!!,
message.actorDisplayName,
true
)
} else {
ApiUtils.getUrlForAvatar(user!!.baseUrl!!, message.actorId, false)
}

val imageRequest: ImageRequest = ImageRequest.Builder(requireContext())
.data(url)
.crossfade(true)
.transformations(CircleCropTransformation())
.target(object : Target {
override fun onStart(placeholder: Drawable?) {
// unused atm
}

override fun onError(error: Drawable?) {
// unused atm
}

override fun onSuccess(result: Drawable) {
binding.fragmentCallStarted.callAuthorChip.chipIcon = result
binding.fragmentCallStarted.callAuthorChipSecondary.chipIcon = result
}
})
.build()

imageLoader(requireContext()).enqueue(imageRequest)
binding.fragmentCallStarted.root.visibility = View.VISIBLE
} else {
binding.fragmentCallStarted.root.visibility = View.GONE
}
}
}

private fun handleUI(isOnline: Boolean, connectionGained: Boolean) {
Expand Down Expand Up @@ -395,6 +445,41 @@ class MessageInputFragment : Fragment() {

binding.fragmentMessageInputView.button?.contentDescription =
resources.getString(R.string.nc_description_send_message_button)

binding.fragmentCallStarted.joinAudioCall.setOnClickListener {
chatActivity.joinAudioCall()
}

binding.fragmentCallStarted.joinVideoCall.setOnClickListener {
chatActivity.joinVideoCall()
}

binding.fragmentCallStarted.callStartedCloseBtn.setOnClickListener {
isCollapsed = !isCollapsed
if (isCollapsed) {
binding.fragmentCallStarted.callAuthorLayout.visibility = View.GONE
binding.fragmentCallStarted.callBtnLayout.visibility = View.GONE
binding.fragmentCallStarted.callAuthorChipSecondary.visibility = View.VISIBLE
binding.fragmentCallStarted.callStartedSecondaryText.visibility = View.VISIBLE
} else {
binding.fragmentCallStarted.callAuthorLayout.visibility = View.VISIBLE
binding.fragmentCallStarted.callBtnLayout.visibility = View.VISIBLE
binding.fragmentCallStarted.callAuthorChipSecondary.visibility = View.GONE
binding.fragmentCallStarted.callStartedSecondaryText.visibility = View.GONE
}

setDropDown(isCollapsed)
}
}

private fun setDropDown(collapsed: Boolean) {
val drawable = if (collapsed) {
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_keyboard_arrow_up)
} else {
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_keyboard_arrow_down)
}

binding.fragmentCallStarted.callStartedCloseBtn.setImageDrawable(drawable)
}

@Suppress("ClickableViewAccessibility", "CyclomaticComplexMethod", "LongMethod")
Expand Down Expand Up @@ -911,6 +996,22 @@ class MessageInputFragment : Fragment() {
binding.fragmentEditView.clearEdit.let {
viewThemeUtils.platform.colorImageView(it, ColorRole.PRIMARY)
}

binding.fragmentCallStarted.callStartedBackground.apply {
viewThemeUtils.talk.themeOutgoingMessageBubble(this, grouped = true, false)
}

binding.fragmentCallStarted.callAuthorChip.apply {
viewThemeUtils.material.colorChipBackground(this)
}

binding.fragmentCallStarted.callAuthorChipSecondary.apply {
viewThemeUtils.material.colorChipBackground(this)
}

binding.fragmentCallStarted.callStartedCloseBtn.apply {
viewThemeUtils.platform.colorImageView(this, ColorRole.PRIMARY)
}
}

private fun cancelReply() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.lifecycle.asLiveData
import com.nextcloud.talk.chat.data.io.AudioFocusRequestManager
import com.nextcloud.talk.chat.data.io.AudioRecorderManager
import com.nextcloud.talk.chat.data.io.MediaPlayerManager
import com.nextcloud.talk.chat.data.model.ChatMessage
import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource
import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage
import com.nextcloud.talk.models.json.generic.GenericOverall
Expand Down Expand Up @@ -129,6 +130,10 @@ class MessageInputViewModel @Inject constructor(
val messageQueueFlow: LiveData<List<QueuedMessage>>
get() = _messageQueueFlow

private val _callStartedFlow: MutableLiveData<Pair<ChatMessage, Boolean>> = MutableLiveData()
val callStartedFlow: LiveData<Pair<ChatMessage, Boolean>>
get() = _callStartedFlow

@Suppress("LongParameterList")
fun sendChatMessage(
internalId: String,
Expand Down Expand Up @@ -314,6 +319,10 @@ class MessageInputViewModel @Inject constructor(
dataStore.saveMessageQueue(internalId, queue)
}

fun showCallStartedIndicator(recent: ChatMessage, show: Boolean) {
_callStartedFlow.postValue(Pair(recent, show))
}

companion object {
private val TAG = MessageInputViewModel::class.java.simpleName
private const val DELAY_BETWEEN_QUEUED_MESSAGES: Long = 1000
Expand Down
Loading

0 comments on commit 90c6eb0

Please sign in to comment.