Przeglądaj źródła

splitting up complex methods into smaller, easier to understand methods

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Andy Scherzinger 3 lat temu
rodzic
commit
eed209428e

+ 87 - 78
app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt

@@ -158,84 +158,7 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
                     base64DecodedSubject
                 )
                 if (signatureVerification!!.signatureValid) {
-                    val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
-                    cipher.init(Cipher.DECRYPT_MODE, privateKey)
-                    val decryptedSubject = cipher.doFinal(base64DecodedSubject)
-                    decryptedPushMessage = LoganSquare.parse(
-                        String(decryptedSubject),
-                        DecryptedPushMessage::class.java
-                    )
-                    decryptedPushMessage?.apply {
-                        Log.d(TAG, this.toString())
-                        timestamp = System.currentTimeMillis()
-                        if (delete) {
-                            cancelExistingNotificationWithId(
-                                applicationContext,
-                                signatureVerification!!.userEntity,
-                                notificationId
-                            )
-                        } else if (deleteAll) {
-                            cancelAllNotificationsForAccount(applicationContext, signatureVerification!!.userEntity)
-                        } else if (deleteMultiple) {
-                            notificationIds!!.forEach {
-                                cancelExistingNotificationWithId(
-                                    applicationContext,
-                                    signatureVerification!!.userEntity,
-                                    it
-                                )
-                            }
-                        } else if (type == "call") {
-                            val fullScreenIntent = Intent(applicationContext, CallNotificationActivity::class.java)
-                            val bundle = Bundle()
-                            bundle.putString(BundleKeys.KEY_ROOM_ID, decryptedPushMessage!!.id)
-                            bundle.putParcelable(KEY_USER_ENTITY, signatureVerification!!.userEntity)
-                            bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, true)
-                            fullScreenIntent.putExtras(bundle)
-
-                            fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
-                            val fullScreenPendingIntent = PendingIntent.getActivity(
-                                this@MagicFirebaseMessagingService,
-                                0,
-                                fullScreenIntent,
-                                PendingIntent.FLAG_UPDATE_CURRENT
-                            )
-
-                            val soundUri = getCallRingtoneUri(applicationContext!!, appPreferences!!)
-                            val notificationChannelId = NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V4
-                            val uri = Uri.parse(signatureVerification!!.userEntity.baseUrl)
-                            val baseUrl = uri.host
-
-                            val notification =
-                                NotificationCompat.Builder(this@MagicFirebaseMessagingService, notificationChannelId)
-                                    .setPriority(NotificationCompat.PRIORITY_HIGH)
-                                    .setCategory(NotificationCompat.CATEGORY_CALL)
-                                    .setSmallIcon(R.drawable.ic_call_black_24dp)
-                                    .setSubText(baseUrl)
-                                    .setShowWhen(true)
-                                    .setWhen(decryptedPushMessage!!.timestamp)
-                                    .setContentTitle(EmojiCompat.get().process(decryptedPushMessage!!.subject))
-                                    .setAutoCancel(true)
-                                    .setOngoing(true)
-                                    // .setTimeoutAfter(45000L)
-                                    .setContentIntent(fullScreenPendingIntent)
-                                    .setFullScreenIntent(fullScreenPendingIntent, true)
-                                    .setSound(soundUri)
-                                    .build()
-                            notification.flags = notification.flags or Notification.FLAG_INSISTENT
-                            isServiceInForeground = true
-                            checkIfCallIsActive(signatureVerification!!, decryptedPushMessage!!)
-                            startForeground(decryptedPushMessage!!.timestamp.toInt(), notification)
-                        } else {
-                            val messageData = Data.Builder()
-                                .putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, subject)
-                                .putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, signature)
-                                .build()
-                            val pushNotificationWork =
-                                OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData)
-                                    .build()
-                            WorkManager.getInstance().enqueue(pushNotificationWork)
-                        }
-                    }
+                    decryptMessage(privateKey, base64DecodedSubject, subject, signature)
                 }
             } catch (e1: NoSuchAlgorithmException) {
                 Log.d(NotificationWorker.TAG, "No proper algorithm to decrypt the message " + e1.localizedMessage)
@@ -249,6 +172,92 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
         }
     }
 
+    private fun decryptMessage(
+        privateKey: PrivateKey,
+        base64DecodedSubject: ByteArray?,
+        subject: String,
+        signature: String
+    ) {
+        val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+        cipher.init(Cipher.DECRYPT_MODE, privateKey)
+        val decryptedSubject = cipher.doFinal(base64DecodedSubject)
+        decryptedPushMessage = LoganSquare.parse(
+            String(decryptedSubject),
+            DecryptedPushMessage::class.java
+        )
+        decryptedPushMessage?.apply {
+            Log.d(TAG, this.toString())
+            timestamp = System.currentTimeMillis()
+            if (delete) {
+                cancelExistingNotificationWithId(
+                    applicationContext,
+                    signatureVerification!!.userEntity,
+                    notificationId
+                )
+            } else if (deleteAll) {
+                cancelAllNotificationsForAccount(applicationContext, signatureVerification!!.userEntity)
+            } else if (deleteMultiple) {
+                notificationIds!!.forEach {
+                    cancelExistingNotificationWithId(
+                        applicationContext,
+                        signatureVerification!!.userEntity,
+                        it
+                    )
+                }
+            } else if (type == "call") {
+                val fullScreenIntent = Intent(applicationContext, CallNotificationActivity::class.java)
+                val bundle = Bundle()
+                bundle.putString(BundleKeys.KEY_ROOM_ID, decryptedPushMessage!!.id)
+                bundle.putParcelable(KEY_USER_ENTITY, signatureVerification!!.userEntity)
+                bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, true)
+                fullScreenIntent.putExtras(bundle)
+
+                fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
+                val fullScreenPendingIntent = PendingIntent.getActivity(
+                    this@MagicFirebaseMessagingService,
+                    0,
+                    fullScreenIntent,
+                    PendingIntent.FLAG_UPDATE_CURRENT
+                )
+
+                val soundUri = getCallRingtoneUri(applicationContext!!, appPreferences!!)
+                val notificationChannelId = NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V4
+                val uri = Uri.parse(signatureVerification!!.userEntity.baseUrl)
+                val baseUrl = uri.host
+
+                val notification =
+                    NotificationCompat.Builder(this@MagicFirebaseMessagingService, notificationChannelId)
+                        .setPriority(NotificationCompat.PRIORITY_HIGH)
+                        .setCategory(NotificationCompat.CATEGORY_CALL)
+                        .setSmallIcon(R.drawable.ic_call_black_24dp)
+                        .setSubText(baseUrl)
+                        .setShowWhen(true)
+                        .setWhen(decryptedPushMessage!!.timestamp)
+                        .setContentTitle(EmojiCompat.get().process(decryptedPushMessage!!.subject))
+                        .setAutoCancel(true)
+                        .setOngoing(true)
+                        // .setTimeoutAfter(45000L)
+                        .setContentIntent(fullScreenPendingIntent)
+                        .setFullScreenIntent(fullScreenPendingIntent, true)
+                        .setSound(soundUri)
+                        .build()
+                notification.flags = notification.flags or Notification.FLAG_INSISTENT
+                isServiceInForeground = true
+                checkIfCallIsActive(signatureVerification!!, decryptedPushMessage!!)
+                startForeground(decryptedPushMessage!!.timestamp.toInt(), notification)
+            } else {
+                val messageData = Data.Builder()
+                    .putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, subject)
+                    .putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, signature)
+                    .build()
+                val pushNotificationWork =
+                    OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData)
+                        .build()
+                WorkManager.getInstance().enqueue(pushNotificationWork)
+            }
+        }
+    }
+
     private fun checkIfCallIsActive(
         signatureVerification: SignatureVerification,
         decryptedPushMessage: DecryptedPushMessage

+ 51 - 43
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt

@@ -153,24 +153,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
                     showVoiceMessageLoading()
                     WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(workInfo.id)
                         .observeForever { info: WorkInfo? ->
-                            if (info != null) {
-                                when (info.state) {
-                                    WorkInfo.State.RUNNING -> {
-                                        Log.d(TAG, "WorkInfo.State.RUNNING in ViewHolder")
-                                        showVoiceMessageLoading()
-                                    }
-                                    WorkInfo.State.SUCCEEDED -> {
-                                        Log.d(TAG, "WorkInfo.State.SUCCEEDED in ViewHolder")
-                                        showPlayButton()
-                                    }
-                                    WorkInfo.State.FAILED -> {
-                                        Log.d(TAG, "WorkInfo.State.FAILED in ViewHolder")
-                                        showPlayButton()
-                                    }
-                                    else -> {
-                                    }
-                                }
-                            }
+                            showStatus(info)
                         }
                 }
             }
@@ -181,6 +164,27 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
         }
     }
 
+    private fun showStatus(info: WorkInfo?) {
+        if (info != null) {
+            when (info.state) {
+                WorkInfo.State.RUNNING -> {
+                    Log.d(TAG, "WorkInfo.State.RUNNING in ViewHolder")
+                    showVoiceMessageLoading()
+                }
+                WorkInfo.State.SUCCEEDED -> {
+                    Log.d(TAG, "WorkInfo.State.SUCCEEDED in ViewHolder")
+                    showPlayButton()
+                }
+                WorkInfo.State.FAILED -> {
+                    Log.d(TAG, "WorkInfo.State.FAILED in ViewHolder")
+                    showPlayButton()
+                }
+                else -> {
+                }
+            }
+        }
+    }
+
     private fun showPlayButton() {
         binding.playPauseBtn.visibility = View.VISIBLE
         binding.progressBar.visibility = View.GONE
@@ -203,31 +207,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
         }
 
         if (!message.isGrouped && !message.isOneToOneConversation) {
-            binding.messageUserAvatar.visibility = View.VISIBLE
-            if (message.actorType == "guests") {
-                // do nothing, avatar is set
-            } else if (message.actorType == "bots" && message.actorId == "changelog") {
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                    val layers = arrayOfNulls<Drawable>(2)
-                    layers[0] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_background)
-                    layers[1] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_foreground)
-                    val layerDrawable = LayerDrawable(layers)
-                    binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
-                } else {
-                    binding.messageUserAvatar.setImageResource(R.mipmap.ic_launcher)
-                }
-            } else if (message.actorType == "bots") {
-                val drawable = TextDrawable.builder()
-                    .beginConfig()
-                    .bold()
-                    .endConfig()
-                    .buildRound(
-                        ">",
-                        ResourcesCompat.getColor(context!!.resources, R.color.black, null)
-                    )
-                binding.messageUserAvatar.visibility = View.VISIBLE
-                binding.messageUserAvatar.setImageDrawable(drawable)
-            }
+            setAvatarOnMessage(message)
         } else {
             if (message.isOneToOneConversation) {
                 binding.messageUserAvatar.visibility = View.GONE
@@ -238,6 +218,34 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
         }
     }
 
+    private fun setAvatarOnMessage(message: ChatMessage) {
+        binding.messageUserAvatar.visibility = View.VISIBLE
+        if (message.actorType == "guests") {
+            // do nothing, avatar is set
+        } else if (message.actorType == "bots" && message.actorId == "changelog") {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                val layers = arrayOfNulls<Drawable>(2)
+                layers[0] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_background)
+                layers[1] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_foreground)
+                val layerDrawable = LayerDrawable(layers)
+                binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
+            } else {
+                binding.messageUserAvatar.setImageResource(R.mipmap.ic_launcher)
+            }
+        } else if (message.actorType == "bots") {
+            val drawable = TextDrawable.builder()
+                .beginConfig()
+                .bold()
+                .endConfig()
+                .buildRound(
+                    ">",
+                    ResourcesCompat.getColor(context!!.resources, R.color.black, null)
+                )
+            binding.messageUserAvatar.visibility = View.VISIBLE
+            binding.messageUserAvatar.setImageDrawable(drawable)
+        }
+    }
+
     private fun colorizeMessageBubble(message: ChatMessage) {
         val resources = itemView.resources
 

+ 144 - 116
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt

@@ -26,6 +26,7 @@ package com.nextcloud.talk.adapters.messages
 
 import android.content.Context
 import android.content.Intent
+import android.content.res.Resources
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
 import android.net.Uri
@@ -53,6 +54,7 @@ import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.TextMatchers
 import com.nextcloud.talk.utils.preferences.AppPreferences
 import com.stfalcon.chatkit.messages.MessageHolders
+import java.util.HashMap
 import javax.inject.Inject
 
 @AutoInjector(NextcloudTalkApplication::class)
@@ -72,44 +74,10 @@ class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : Message
     override fun onBind(message: ChatMessage) {
         super.onBind(message)
         sharedApplication!!.componentApplication.inject(this)
-        val author: String = message.actorDisplayName
-        if (!TextUtils.isEmpty(author)) {
-            binding.messageAuthor.text = author
-            binding.messageUserAvatar.setOnClickListener {
-                (payload as? ProfileBottomSheet)?.showFor(message.actorId, itemView.context)
-            }
-        } else {
-            binding.messageAuthor.setText(R.string.nc_nick_guest)
-        }
+        processAuthor(message)
 
         if (!message.isGrouped && !message.isOneToOneConversation) {
-            binding.messageUserAvatar.visibility = View.VISIBLE
-            if (message.actorType == "guests") {
-                // do nothing, avatar is set
-            } else if (message.actorType == "bots" && message.actorId == "changelog") {
-                if (context != null) {
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                        val layers = arrayOfNulls<Drawable>(2)
-                        layers[0] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_background)
-                        layers[1] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_foreground)
-                        val layerDrawable = LayerDrawable(layers)
-                        binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
-                    } else {
-                        binding.messageUserAvatar.setImageResource(R.mipmap.ic_launcher)
-                    }
-                }
-            } else if (message.actorType == "bots") {
-                val drawable = TextDrawable.builder()
-                    .beginConfig()
-                    .bold()
-                    .endConfig()
-                    .buildRound(
-                        ">",
-                        ResourcesCompat.getColor(context!!.resources, R.color.black, null)
-                    )
-                binding.messageUserAvatar.visibility = View.VISIBLE
-                binding.messageUserAvatar.setImageDrawable(drawable)
-            }
+            showAvatarOnChatMessage(message)
         } else {
             if (message.isOneToOneConversation) {
                 binding.messageUserAvatar.visibility = View.GONE
@@ -121,6 +89,53 @@ class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : Message
 
         val resources = itemView.resources
 
+        setBubbleOnChatMessage(message, resources)
+
+        itemView.isSelected = false
+        binding.messageTime.setTextColor(ResourcesCompat.getColor(resources, R.color.warm_grey_four, null))
+
+        var messageString: Spannable = SpannableString(message.text)
+
+        var textSize = context?.resources!!.getDimension(R.dimen.chat_text_size)
+
+        val messageParameters = message.messageParameters
+        if (messageParameters != null && messageParameters.size > 0) {
+            messageString = processMessageParameters(messageParameters, message, messageString)
+        } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
+            textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat()
+            itemView.isSelected = true
+            binding.messageAuthor.visibility = View.GONE
+        }
+
+        binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
+        binding.messageText.text = messageString
+
+        // parent message handling
+        if (!message.isDeleted && message.parentMessage != null) {
+            processParentMessage(message)
+            binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
+        } else {
+            binding.messageQuote.quotedChatMessageView.visibility = View.GONE
+        }
+
+        itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
+    }
+
+    private fun processAuthor(message: ChatMessage) {
+        if (!TextUtils.isEmpty(message.actorDisplayName)) {
+            binding.messageAuthor.text = message.actorDisplayName
+            binding.messageUserAvatar.setOnClickListener {
+                (payload as? ProfileBottomSheet)?.showFor(message.actorId, itemView.context)
+            }
+        } else {
+            binding.messageAuthor.setText(R.string.nc_nick_guest)
+        }
+    }
+
+    private fun setBubbleOnChatMessage(
+        message: ChatMessage,
+        resources: Resources
+    ) {
         val bgBubbleColor = if (message.isDeleted) {
             ResourcesCompat.getColor(resources, R.color.bg_message_list_incoming_bubble_deleted, null)
         } else {
@@ -139,97 +154,110 @@ class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : Message
             bgBubbleColor, bubbleResource
         )
         ViewCompat.setBackground(bubble, bubbleDrawable)
+    }
 
-        val messageParameters = message.messageParameters
-
-        itemView.isSelected = false
-        binding.messageTime.setTextColor(ResourcesCompat.getColor(resources, R.color.warm_grey_four, null))
+    private fun processParentMessage(message: ChatMessage) {
+        val parentChatMessage = message.parentMessage
+        parentChatMessage.activeUser = message.activeUser
+        parentChatMessage.imageUrl?.let {
+            binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
+            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 = if (parentChatMessage.actorDisplayName.isNullOrEmpty())
+            context!!.getText(R.string.nc_nick_guest) else parentChatMessage.actorDisplayName
+        binding.messageQuote.quotedMessage.text = parentChatMessage.text
 
-        var messageString: Spannable = SpannableString(message.text)
+        binding.messageQuote.quotedMessageAuthor
+            .setTextColor(ContextCompat.getColor(context!!, R.color.textColorMaxContrast))
 
-        var textSize = context?.resources!!.getDimension(R.dimen.chat_text_size)
+        if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
+            binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.colorPrimary)
+        } else {
+            binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast)
+        }
+    }
 
-        if (messageParameters != null && messageParameters.size > 0) {
-            for (key in messageParameters.keys) {
-                val individualHashMap = message.messageParameters[key]
-                if (individualHashMap != null) {
-                    if (
-                        individualHashMap["type"] == "user" ||
-                        individualHashMap["type"] == "guest" ||
-                        individualHashMap["type"] == "call"
-                    ) {
-                        if (individualHashMap["id"] == message.activeUser!!.userId) {
-                            messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
-                                binding.messageText.context,
-                                messageString,
-                                individualHashMap["id"]!!,
-                                individualHashMap["name"]!!,
-                                individualHashMap["type"]!!,
-                                message.activeUser!!,
-                                R.xml.chip_you
-                            )
-                        } else {
-                            messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
-                                binding.messageText.context,
-                                messageString,
-                                individualHashMap["id"]!!,
-                                individualHashMap["name"]!!,
-                                individualHashMap["type"]!!,
-                                message.activeUser!!,
-                                R.xml.chip_others
-                            )
-                        }
-                    } else if (individualHashMap["type"] == "file") {
-                        itemView.setOnClickListener { v ->
-                            val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
-                            context!!.startActivity(browserIntent)
-                        }
-                    }
+    private fun showAvatarOnChatMessage(message: ChatMessage) {
+        binding.messageUserAvatar.visibility = View.VISIBLE
+        if (message.actorType == "guests") {
+            // do nothing, avatar is set
+        } else if (message.actorType == "bots" && message.actorId == "changelog") {
+            if (context != null) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                    val layers = arrayOfNulls<Drawable>(2)
+                    layers[0] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_background)
+                    layers[1] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_foreground)
+                    val layerDrawable = LayerDrawable(layers)
+                    binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
+                } else {
+                    binding.messageUserAvatar.setImageResource(R.mipmap.ic_launcher)
                 }
             }
-        } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
-            textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat()
-            itemView.isSelected = true
-            binding.messageAuthor.visibility = View.GONE
+        } else if (message.actorType == "bots") {
+            val drawable = TextDrawable.builder()
+                .beginConfig()
+                .bold()
+                .endConfig()
+                .buildRound(
+                    ">",
+                    ResourcesCompat.getColor(context!!.resources, R.color.black, null)
+                )
+            binding.messageUserAvatar.visibility = View.VISIBLE
+            binding.messageUserAvatar.setImageDrawable(drawable)
         }
+    }
 
-        binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
-        binding.messageText.text = messageString
-
-        // parent message handling
-        if (!message.isDeleted && message.parentMessage != null) {
-            val parentChatMessage = message.parentMessage
-            parentChatMessage.activeUser = message.activeUser
-            parentChatMessage.imageUrl?.let {
-                binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
-                binding.messageQuote.quotedMessageImage.load(it) {
-                    addHeader(
-                        "Authorization",
-                        ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
-                    )
+    private fun processMessageParameters(
+        messageParameters: HashMap<String, HashMap<String, String>>,
+        message: ChatMessage,
+        messageString: Spannable
+    ): Spannable {
+        var messageStringInternal = messageString
+        for (key in messageParameters.keys) {
+            val individualHashMap = message.messageParameters[key]
+            if (individualHashMap != null) {
+                if (
+                    individualHashMap["type"] == "user" ||
+                    individualHashMap["type"] == "guest" ||
+                    individualHashMap["type"] == "call"
+                ) {
+                    if (individualHashMap["id"] == message.activeUser!!.userId) {
+                        messageStringInternal = DisplayUtils.searchAndReplaceWithMentionSpan(
+                            binding.messageText.context,
+                            messageStringInternal,
+                            individualHashMap["id"]!!,
+                            individualHashMap["name"]!!,
+                            individualHashMap["type"]!!,
+                            message.activeUser!!,
+                            R.xml.chip_you
+                        )
+                    } else {
+                        messageStringInternal = DisplayUtils.searchAndReplaceWithMentionSpan(
+                            binding.messageText.context,
+                            messageStringInternal,
+                            individualHashMap["id"]!!,
+                            individualHashMap["name"]!!,
+                            individualHashMap["type"]!!,
+                            message.activeUser!!,
+                            R.xml.chip_others
+                        )
+                    }
+                } else if (individualHashMap["type"] == "file") {
+                    itemView.setOnClickListener { v ->
+                        val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
+                        context!!.startActivity(browserIntent)
+                    }
                 }
-            } ?: run {
-                binding.messageQuote.quotedMessageImage.visibility = View.GONE
             }
-            binding.messageQuote.quotedMessageAuthor.text = if (parentChatMessage.actorDisplayName.isNullOrEmpty())
-                context!!.getText(R.string.nc_nick_guest) else parentChatMessage.actorDisplayName
-            binding.messageQuote.quotedMessage.text = parentChatMessage.text
-
-            binding.messageQuote.quotedMessageAuthor
-                .setTextColor(ContextCompat.getColor(context!!, R.color.textColorMaxContrast))
-
-            if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
-                binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.colorPrimary)
-            } else {
-                binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast)
-            }
-
-            binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
-        } else {
-            binding.messageQuote.quotedChatMessageView.visibility = View.GONE
         }
-
-        itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
+        return messageStringInternal
     }
 
     companion object {

+ 89 - 71
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.kt

@@ -72,30 +72,7 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
         layoutParams.isWrapBefore = false
         var textSize = context!!.resources.getDimension(R.dimen.chat_text_size)
         if (messageParameters != null && messageParameters.size > 0) {
-            for (key in messageParameters.keys) {
-                val individualHashMap: HashMap<String, String>? = message.messageParameters[key]
-                if (individualHashMap != null) {
-                    if (individualHashMap["type"] == "user" ||
-                        individualHashMap["type"] == "guest" ||
-                        individualHashMap["type"] == "call"
-                    ) {
-                        messageString = searchAndReplaceWithMentionSpan(
-                            binding.messageText.context,
-                            messageString,
-                            individualHashMap["id"]!!,
-                            individualHashMap["name"]!!,
-                            individualHashMap["type"]!!,
-                            message.activeUser,
-                            R.xml.chip_others
-                        )
-                    } else if (individualHashMap["type"] == "file") {
-                        realView.setOnClickListener { v: View? ->
-                            val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
-                            context!!.startActivity(browserIntent)
-                        }
-                    }
-                }
-            }
+            messageString = processMessageParameters(messageParameters, message, messageString)
         } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
             textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat()
             layoutParams.isWrapBefore = true
@@ -104,59 +81,16 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
             )
             realView.isSelected = true
         }
-        val resources = sharedApplication!!.resources
-        val bgBubbleColor = if (message.isDeleted) {
-            ResourcesCompat.getColor(resources, R.color.bg_message_list_outcoming_bubble_deleted, null)
-        } else {
-            ResourcesCompat.getColor(resources, R.color.bg_message_list_outcoming_bubble, null)
-        }
-        if (message.isGrouped) {
-            val bubbleDrawable = getMessageSelector(
-                bgBubbleColor,
-                ResourcesCompat.getColor(resources, R.color.transparent, null),
-                bgBubbleColor,
-                R.drawable.shape_grouped_outcoming_message
-            )
-            ViewCompat.setBackground(bubble, bubbleDrawable)
-        } else {
-            val bubbleDrawable = getMessageSelector(
-                bgBubbleColor,
-                ResourcesCompat.getColor(resources, R.color.transparent, null),
-                bgBubbleColor,
-                R.drawable.shape_outcoming_message
-            )
-            ViewCompat.setBackground(bubble, bubbleDrawable)
-        }
+
+        setBubbleOnChatMessage(message)
+
         binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
         binding.messageTime.layoutParams = layoutParams
         binding.messageText.text = messageString
 
         // parent message handling
-
         if (!message.isDeleted && message.parentMessage != null) {
-            val parentChatMessage = message.parentMessage
-            parentChatMessage.activeUser = message.activeUser
-            parentChatMessage.imageUrl?.let {
-                binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
-                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 = parentChatMessage.text
-            binding.messageQuote.quotedMessage.setTextColor(
-                ContextCompat.getColor(context!!, R.color.nc_outcoming_text_default)
-            )
-            binding.messageQuote.quotedMessageAuthor.setTextColor(ContextCompat.getColor(context!!, R.color.nc_grey))
-
-            binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.white)
-
+            processParentMessage(message)
             binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
         } else {
             binding.messageQuote.quotedChatMessageView.visibility = View.GONE
@@ -186,6 +120,90 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
         itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
     }
 
+    private fun processParentMessage(message: ChatMessage) {
+        val parentChatMessage = message.parentMessage
+        parentChatMessage.activeUser = message.activeUser
+        parentChatMessage.imageUrl?.let {
+            binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
+            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 = parentChatMessage.text
+        binding.messageQuote.quotedMessage.setTextColor(
+            ContextCompat.getColor(context!!, R.color.nc_outcoming_text_default)
+        )
+        binding.messageQuote.quotedMessageAuthor.setTextColor(ContextCompat.getColor(context!!, R.color.nc_grey))
+
+        binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.white)
+    }
+
+    private fun setBubbleOnChatMessage(message: ChatMessage) {
+        val resources = sharedApplication!!.resources
+        val bgBubbleColor = if (message.isDeleted) {
+            ResourcesCompat.getColor(resources, R.color.bg_message_list_outcoming_bubble_deleted, null)
+        } else {
+            ResourcesCompat.getColor(resources, R.color.bg_message_list_outcoming_bubble, null)
+        }
+        if (message.isGrouped) {
+            val bubbleDrawable = getMessageSelector(
+                bgBubbleColor,
+                ResourcesCompat.getColor(resources, R.color.transparent, null),
+                bgBubbleColor,
+                R.drawable.shape_grouped_outcoming_message
+            )
+            ViewCompat.setBackground(bubble, bubbleDrawable)
+        } else {
+            val bubbleDrawable = getMessageSelector(
+                bgBubbleColor,
+                ResourcesCompat.getColor(resources, R.color.transparent, null),
+                bgBubbleColor,
+                R.drawable.shape_outcoming_message
+            )
+            ViewCompat.setBackground(bubble, bubbleDrawable)
+        }
+    }
+
+    private fun processMessageParameters(
+        messageParameters: HashMap<String, HashMap<String, String>>,
+        message: ChatMessage,
+        messageString: Spannable
+    ): Spannable {
+        var messageString1 = messageString
+        for (key in messageParameters.keys) {
+            val individualHashMap: HashMap<String, String>? = message.messageParameters[key]
+            if (individualHashMap != null) {
+                if (individualHashMap["type"] == "user" ||
+                    individualHashMap["type"] == "guest" ||
+                    individualHashMap["type"] == "call"
+                ) {
+                    messageString1 = searchAndReplaceWithMentionSpan(
+                        binding.messageText.context,
+                        messageString1,
+                        individualHashMap["id"]!!,
+                        individualHashMap["name"]!!,
+                        individualHashMap["type"]!!,
+                        message.activeUser,
+                        R.xml.chip_others
+                    )
+                } else if (individualHashMap["type"] == "file") {
+                    realView.setOnClickListener { v: View? ->
+                        val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
+                        context!!.startActivity(browserIntent)
+                    }
+                }
+            }
+        }
+        return messageString1
+    }
+
     companion object {
         const val TEXT_SIZE_MULTIPLIER = 2.5
     }

+ 40 - 28
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt

@@ -87,36 +87,11 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders
         updateDownloadState(message)
         binding.seekbar.max = message.voiceMessageDuration
 
-        if (message.isPlayingVoiceMessage) {
-            showPlayButton()
-            binding.playPauseBtn.icon = ContextCompat.getDrawable(
-                context!!,
-                R.drawable.ic_baseline_pause_voice_message_24
-            )
-            binding.seekbar.progress = message.voiceMessagePlayedSeconds
-        } else {
-            binding.playPauseBtn.visibility = View.VISIBLE
-            binding.playPauseBtn.icon = ContextCompat.getDrawable(
-                context!!,
-                R.drawable.ic_baseline_play_arrow_voice_message_24
-            )
-        }
+        handleIsPlayingVoiceMessageState(message)
 
-        if (message.isDownloadingVoiceMessage) {
-            showVoiceMessageLoading()
-        } else {
-            binding.progressBar.visibility = View.GONE
-        }
+        handleIsDownloadingVoiceMessageState(message)
 
-        if (message.resetVoiceMessage) {
-            binding.playPauseBtn.visibility = View.VISIBLE
-            binding.playPauseBtn.icon = ContextCompat.getDrawable(
-                context!!,
-                R.drawable.ic_baseline_play_arrow_voice_message_24
-            )
-            binding.seekbar.progress = SEEKBAR_START
-            message.resetVoiceMessage = false
-        }
+        handleResetVoiceMessageState(message)
 
         binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
             override fun onStopTrackingTouch(seekBar: SeekBar) {
@@ -156,6 +131,43 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders
         binding.checkMark.setContentDescription(readStatusContentDescriptionString)
     }
 
+    private fun handleResetVoiceMessageState(message: ChatMessage) {
+        if (message.resetVoiceMessage) {
+            binding.playPauseBtn.visibility = View.VISIBLE
+            binding.playPauseBtn.icon = ContextCompat.getDrawable(
+                context!!,
+                R.drawable.ic_baseline_play_arrow_voice_message_24
+            )
+            binding.seekbar.progress = SEEKBAR_START
+            message.resetVoiceMessage = false
+        }
+    }
+
+    private fun handleIsDownloadingVoiceMessageState(message: ChatMessage) {
+        if (message.isDownloadingVoiceMessage) {
+            showVoiceMessageLoading()
+        } else {
+            binding.progressBar.visibility = View.GONE
+        }
+    }
+
+    private fun handleIsPlayingVoiceMessageState(message: ChatMessage) {
+        if (message.isPlayingVoiceMessage) {
+            showPlayButton()
+            binding.playPauseBtn.icon = ContextCompat.getDrawable(
+                context!!,
+                R.drawable.ic_baseline_pause_voice_message_24
+            )
+            binding.seekbar.progress = message.voiceMessagePlayedSeconds
+        } 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.getSelectedIndividualHashMap()["id"]

+ 1 - 1
detekt.yml

@@ -1,5 +1,5 @@
 build:
-  maxIssues: 108
+  maxIssues: 99
   weights:
     # complexity: 2
     # LongParameterList: 1