Move message holders to native view bindings

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
This commit is contained in:
Andy Scherzinger 2021-06-10 16:40:55 +02:00
parent 71bffc0ea8
commit 6ba541b6b1
No known key found for this signature in database
GPG key ID: 6CADC7E3523C308B
12 changed files with 256 additions and 339 deletions

View file

@ -3,8 +3,10 @@
* *
* @author Mario Danic * @author Mario Danic
* @author Marcel Hibbe * @author Marcel Hibbe
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> * @author Andy Scherzinger
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
* Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de> * Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -35,22 +37,16 @@ import android.view.MotionEvent
import android.view.View import android.view.View
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.emoji.widget.EmojiTextView
import autodagger.AutoInjector import autodagger.AutoInjector
import butterknife.BindView
import butterknife.ButterKnife
import coil.load import coil.load
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.facebook.drawee.view.SimpleDraweeView
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.databinding.ItemCustomIncomingLocationMessageBinding
import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils
@ -62,6 +58,7 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
.IncomingTextMessageViewHolder<ChatMessage>(incomingView) { .IncomingTextMessageViewHolder<ChatMessage>(incomingView) {
private val binding: ItemCustomIncomingLocationMessageBinding = ItemCustomIncomingLocationMessageBinding.bind(itemView)
private val TAG = "LocMessageView" private val TAG = "LocMessageView"
@ -70,42 +67,6 @@ class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
var locationName: String? = "" var locationName: String? = ""
var locationGeoLink: String? = "" var locationGeoLink: String? = ""
@JvmField
@BindView(R.id.messageAuthor)
var messageAuthor: EmojiTextView? = null
@JvmField
@BindView(R.id.messageText)
var messageText: EmojiTextView? = null
@JvmField
@BindView(R.id.messageUserAvatar)
var messageUserAvatarView: SimpleDraweeView? = null
@JvmField
@BindView(R.id.messageTime)
var messageTimeView: TextView? = null
@JvmField
@BindView(R.id.quotedChatMessageView)
var quotedChatMessageView: RelativeLayout? = null
@JvmField
@BindView(R.id.quotedMessageAuthor)
var quotedUserName: EmojiTextView? = null
@JvmField
@BindView(R.id.quotedMessageImage)
var quotedMessagePreview: ImageView? = null
@JvmField
@BindView(R.id.quotedMessage)
var quotedMessage: EmojiTextView? = null
@JvmField
@BindView(R.id.quoteColoredView)
var quoteColoredView: View? = null
@JvmField @JvmField
@Inject @Inject
var context: Context? = null var context: Context? = null
@ -114,30 +75,19 @@ class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
@Inject @Inject
var appPreferences: AppPreferences? = null var appPreferences: AppPreferences? = null
@JvmField
@BindView(R.id.webview)
var webview: WebView? = null
init {
ButterKnife.bind(
this,
itemView
)
}
@SuppressLint("SetTextI18n", "SetJavaScriptEnabled", "ClickableViewAccessibility") @SuppressLint("SetTextI18n", "SetJavaScriptEnabled", "ClickableViewAccessibility")
override fun onBind(message: ChatMessage) { override fun onBind(message: ChatMessage) {
super.onBind(message) super.onBind(message)
sharedApplication!!.componentApplication.inject(this) sharedApplication!!.componentApplication.inject(this)
val author: String = message.actorDisplayName val author: String = message.actorDisplayName
if (!TextUtils.isEmpty(author)) { if (!TextUtils.isEmpty(author)) {
messageAuthor!!.text = author binding.messageAuthor.text = author
} else { } else {
messageAuthor!!.setText(R.string.nc_nick_guest) binding.messageAuthor.setText(R.string.nc_nick_guest)
} }
if (!message.isGrouped && !message.isOneToOneConversation) { if (!message.isGrouped && !message.isOneToOneConversation) {
messageUserAvatarView!!.visibility = View.VISIBLE binding.messageUserAvatar.visibility = View.VISIBLE
if (message.actorType == "guests") { if (message.actorType == "guests") {
// do nothing, avatar is set // do nothing, avatar is set
} else if (message.actorType == "bots" && message.actorId == "changelog") { } else if (message.actorType == "bots" && message.actorId == "changelog") {
@ -145,7 +95,7 @@ class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
layers[0] = AppCompatResources.getDrawable(context!!, R.drawable.ic_launcher_background) layers[0] = AppCompatResources.getDrawable(context!!, R.drawable.ic_launcher_background)
layers[1] = AppCompatResources.getDrawable(context!!, R.drawable.ic_launcher_foreground) layers[1] = AppCompatResources.getDrawable(context!!, R.drawable.ic_launcher_foreground)
val layerDrawable = LayerDrawable(layers) val layerDrawable = LayerDrawable(layers)
messageUserAvatarView?.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable)) binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
} else if (message.actorType == "bots") { } else if (message.actorType == "bots") {
val drawable = TextDrawable.builder() val drawable = TextDrawable.builder()
.beginConfig() .beginConfig()
@ -155,16 +105,16 @@ class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
">", ">",
context!!.resources.getColor(R.color.black) context!!.resources.getColor(R.color.black)
) )
messageUserAvatarView!!.visibility = View.VISIBLE binding.messageUserAvatar.visibility = View.VISIBLE
messageUserAvatarView?.setImageDrawable(drawable) binding.messageUserAvatar.setImageDrawable(drawable)
} }
} else { } else {
if (message.isOneToOneConversation) { if (message.isOneToOneConversation) {
messageUserAvatarView!!.visibility = View.GONE binding.messageUserAvatar.visibility = View.GONE
} else { } else {
messageUserAvatarView!!.visibility = View.INVISIBLE binding.messageUserAvatar.visibility = View.INVISIBLE
} }
messageAuthor!!.visibility = View.GONE binding.messageAuthor.visibility = View.GONE
} }
val resources = itemView.resources val resources = itemView.resources
@ -188,47 +138,45 @@ class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
) )
ViewCompat.setBackground(bubble, bubbleDrawable) ViewCompat.setBackground(bubble, bubbleDrawable)
val messageParameters = message.messageParameters
itemView.isSelected = false itemView.isSelected = false
messageTimeView!!.setTextColor(context?.resources!!.getColor(R.color.warm_grey_four)) binding.messageTime.setTextColor(context?.resources!!.getColor(R.color.warm_grey_four))
val textSize = context?.resources!!.getDimension(R.dimen.chat_text_size) val textSize = context?.resources!!.getDimension(R.dimen.chat_text_size)
messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
messageText!!.text = message.text binding.messageText.text = message.text
messageText!!.isEnabled = false binding.messageText.isEnabled = false
// parent message handling // parent message handling
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 {
quotedMessagePreview?.visibility = View.VISIBLE binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
quotedMessagePreview?.load(it) { binding.messageQuote.quotedMessageImage.load(it) {
addHeader( addHeader(
"Authorization", "Authorization",
ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token) ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
) )
} }
} ?: run { } ?: run {
quotedMessagePreview?.visibility = View.GONE binding.messageQuote.quotedMessageImage.visibility = View.GONE
} }
quotedUserName?.text = parentChatMessage.actorDisplayName binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
?: context!!.getText(R.string.nc_nick_guest) ?: context!!.getText(R.string.nc_nick_guest)
quotedMessage?.text = parentChatMessage.text binding.messageQuote.quotedMessage.text = parentChatMessage.text
quotedUserName?.setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast)) binding.messageQuote.quotedMessageAuthor
.setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast))
if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) { if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
quoteColoredView?.setBackgroundResource(R.color.colorPrimary) binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.colorPrimary)
} else { } else {
quoteColoredView?.setBackgroundResource(R.color.textColorMaxContrast) binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast)
} }
quotedChatMessageView?.visibility = View.VISIBLE binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
} else { } else {
quotedChatMessageView?.visibility = View.GONE binding.messageQuote.quotedChatMessageView.visibility = View.GONE
} }
// geo-location // geo-location
@ -245,9 +193,9 @@ class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
} }
} }
webview?.settings?.javaScriptEnabled = true binding.webview.settings?.javaScriptEnabled = true
webview?.webViewClient = object : WebViewClient() { binding.webview.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return if (url != null && (url.startsWith("http://") || url.startsWith("https://")) return if (url != null && (url.startsWith("http://") || url.startsWith("https://"))
) { ) {
@ -268,9 +216,9 @@ class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
urlStringBuffer.append("&locationName=" + URLEncoder.encode(locationName)) urlStringBuffer.append("&locationName=" + URLEncoder.encode(locationName))
urlStringBuffer.append("&locationGeoLink=" + URLEncoder.encode(locationGeoLink)) urlStringBuffer.append("&locationGeoLink=" + URLEncoder.encode(locationGeoLink))
webview?.loadUrl(urlStringBuffer.toString()) binding.webview.loadUrl(urlStringBuffer.toString())
webview?.setOnTouchListener(object : View.OnTouchListener { binding.webview.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean { override fun onTouch(v: View?, event: MotionEvent?): Boolean {
when (event?.action) { when (event?.action) {
MotionEvent.ACTION_UP -> openGeoLink() MotionEvent.ACTION_UP -> openGeoLink()

View file

@ -0,0 +1,45 @@
/*
* Nextcloud Talk application
*
* @author Andy Scherzinger
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.adapters.messages;
import android.view.View;
import android.widget.ProgressBar;
import com.nextcloud.talk.databinding.ItemCustomIncomingPreviewMessageBinding;
import androidx.emoji.widget.EmojiTextView;
public class IncomingPreviewMessageViewHolder extends MagicPreviewMessageViewHolder {
private final ItemCustomIncomingPreviewMessageBinding binding;
public IncomingPreviewMessageViewHolder(View itemView) {
super(itemView);
binding = ItemCustomIncomingPreviewMessageBinding.bind(itemView);
}
public EmojiTextView getMessageText() {
return binding.messageText;
}
public ProgressBar getProgressBar() {
return binding.progressBar;
}
}

View file

@ -2,6 +2,8 @@
* Nextcloud Talk application * Nextcloud Talk application
* *
* @author Mario Danic * @author Mario Danic
* @author Andy Scherzinger
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -30,20 +32,14 @@ import android.text.SpannableString
import android.text.TextUtils import android.text.TextUtils
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.emoji.widget.EmojiTextView
import autodagger.AutoInjector import autodagger.AutoInjector
import butterknife.BindView
import butterknife.ButterKnife
import coil.load import coil.load
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.facebook.drawee.view.SimpleDraweeView
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.databinding.ItemCustomIncomingTextMessageBinding
import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
@ -57,41 +53,7 @@ import javax.inject.Inject
class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
.IncomingTextMessageViewHolder<ChatMessage>(itemView) { .IncomingTextMessageViewHolder<ChatMessage>(itemView) {
@JvmField private val binding: ItemCustomIncomingTextMessageBinding = ItemCustomIncomingTextMessageBinding.bind(itemView)
@BindView(R.id.messageAuthor)
var messageAuthor: EmojiTextView? = null
@JvmField
@BindView(R.id.messageText)
var messageText: EmojiTextView? = null
@JvmField
@BindView(R.id.messageUserAvatar)
var messageUserAvatarView: SimpleDraweeView? = null
@JvmField
@BindView(R.id.messageTime)
var messageTimeView: TextView? = null
@JvmField
@BindView(R.id.quotedChatMessageView)
var quotedChatMessageView: RelativeLayout? = null
@JvmField
@BindView(R.id.quotedMessageAuthor)
var quotedUserName: EmojiTextView? = null
@JvmField
@BindView(R.id.quotedMessageImage)
var quotedMessagePreview: ImageView? = null
@JvmField
@BindView(R.id.quotedMessage)
var quotedMessage: EmojiTextView? = null
@JvmField
@BindView(R.id.quoteColoredView)
var quoteColoredView: View? = null
@JvmField @JvmField
@Inject @Inject
@ -106,13 +68,13 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
sharedApplication!!.componentApplication.inject(this) sharedApplication!!.componentApplication.inject(this)
val author: String = message.actorDisplayName val author: String = message.actorDisplayName
if (!TextUtils.isEmpty(author)) { if (!TextUtils.isEmpty(author)) {
messageAuthor!!.text = author binding.messageAuthor.text = author
} else { } else {
messageAuthor!!.setText(R.string.nc_nick_guest) binding.messageAuthor.setText(R.string.nc_nick_guest)
} }
if (!message.isGrouped && !message.isOneToOneConversation) { if (!message.isGrouped && !message.isOneToOneConversation) {
messageUserAvatarView!!.visibility = View.VISIBLE binding.messageUserAvatar.visibility = View.VISIBLE
if (message.actorType == "guests") { if (message.actorType == "guests") {
// do nothing, avatar is set // do nothing, avatar is set
} else if (message.actorType == "bots" && message.actorId == "changelog") { } else if (message.actorType == "bots" && message.actorId == "changelog") {
@ -120,7 +82,7 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
layers[0] = context?.getDrawable(R.drawable.ic_launcher_background) layers[0] = context?.getDrawable(R.drawable.ic_launcher_background)
layers[1] = context?.getDrawable(R.drawable.ic_launcher_foreground) layers[1] = context?.getDrawable(R.drawable.ic_launcher_foreground)
val layerDrawable = LayerDrawable(layers) val layerDrawable = LayerDrawable(layers)
messageUserAvatarView?.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable)) binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
} else if (message.actorType == "bots") { } else if (message.actorType == "bots") {
val drawable = TextDrawable.builder() val drawable = TextDrawable.builder()
.beginConfig() .beginConfig()
@ -130,16 +92,16 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
">", ">",
context!!.resources.getColor(R.color.black) context!!.resources.getColor(R.color.black)
) )
messageUserAvatarView!!.visibility = View.VISIBLE binding.messageUserAvatar.visibility = View.VISIBLE
messageUserAvatarView?.setImageDrawable(drawable) binding.messageUserAvatar.setImageDrawable(drawable)
} }
} else { } else {
if (message.isOneToOneConversation) { if (message.isOneToOneConversation) {
messageUserAvatarView!!.visibility = View.GONE binding.messageUserAvatar.visibility = View.GONE
} else { } else {
messageUserAvatarView!!.visibility = View.INVISIBLE binding.messageUserAvatar.visibility = View.INVISIBLE
} }
messageAuthor!!.visibility = View.GONE binding.messageAuthor.visibility = View.GONE
} }
val resources = itemView.resources val resources = itemView.resources
@ -166,7 +128,7 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
val messageParameters = message.messageParameters val messageParameters = message.messageParameters
itemView.isSelected = false itemView.isSelected = false
messageTimeView!!.setTextColor(context?.resources!!.getColor(R.color.warm_grey_four)) binding.messageTime.setTextColor(context?.resources!!.getColor(R.color.warm_grey_four))
var messageString: Spannable = SpannableString(message.text) var messageString: Spannable = SpannableString(message.text)
@ -183,7 +145,7 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
) { ) {
if (individualHashMap["id"] == message.activeUser!!.userId) { if (individualHashMap["id"] == message.activeUser!!.userId) {
messageString = DisplayUtils.searchAndReplaceWithMentionSpan( messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
messageText!!.context, binding.messageText.context,
messageString, messageString,
individualHashMap["id"]!!, individualHashMap["id"]!!,
individualHashMap["name"]!!, individualHashMap["name"]!!,
@ -193,7 +155,7 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
) )
} else { } else {
messageString = DisplayUtils.searchAndReplaceWithMentionSpan( messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
messageText!!.context, binding.messageText.context,
messageString, messageString,
individualHashMap["id"]!!, individualHashMap["id"]!!,
individualHashMap["name"]!!, individualHashMap["name"]!!,
@ -213,49 +175,45 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
} else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) { } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
textSize = (textSize * 2.5).toFloat() textSize = (textSize * 2.5).toFloat()
itemView.isSelected = true itemView.isSelected = true
messageAuthor!!.visibility = View.GONE binding.messageAuthor.visibility = View.GONE
} }
messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
messageText!!.text = messageString binding.messageText.text = messageString
// parent message handling // parent message handling
if (!message.isDeleted && message.parentMessage != null) { if (!message.isDeleted && message.parentMessage != null) {
var parentChatMessage = message.parentMessage val parentChatMessage = message.parentMessage
parentChatMessage.activeUser = message.activeUser parentChatMessage.activeUser = message.activeUser
parentChatMessage.imageUrl?.let { parentChatMessage.imageUrl?.let {
quotedMessagePreview?.visibility = View.VISIBLE binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
quotedMessagePreview?.load(it) { binding.messageQuote.quotedMessageImage.load(it) {
addHeader( addHeader(
"Authorization", "Authorization",
ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token) ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
) )
} }
} ?: run { } ?: run {
quotedMessagePreview?.visibility = View.GONE binding.messageQuote.quotedMessageImage.visibility = View.GONE
} }
quotedUserName?.text = parentChatMessage.actorDisplayName binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
?: context!!.getText(R.string.nc_nick_guest) ?: context!!.getText(R.string.nc_nick_guest)
quotedMessage?.text = parentChatMessage.text binding.messageQuote.quotedMessage.text = parentChatMessage.text
quotedUserName?.setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast)) binding.messageQuote.quotedMessageAuthor
.setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast))
if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) { if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
quoteColoredView?.setBackgroundResource(R.color.colorPrimary) binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.colorPrimary)
} else { } else {
quoteColoredView?.setBackgroundResource(R.color.textColorMaxContrast) binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast)
} }
quotedChatMessageView?.visibility = View.VISIBLE binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
} else { } else {
quotedChatMessageView?.visibility = View.GONE binding.messageQuote.quotedChatMessageView.visibility = View.GONE
} }
itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable) itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
} }
init {
ButterKnife.bind(this, itemView)
}
} }

View file

@ -2,6 +2,8 @@
* Nextcloud Talk application * Nextcloud Talk application
* *
* @author Mario Danic * @author Mario Danic
* @author Andy Scherzinger
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -27,19 +29,14 @@ import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.emoji.widget.EmojiTextView
import autodagger.AutoInjector import autodagger.AutoInjector
import butterknife.BindView
import butterknife.ButterKnife
import coil.load import coil.load
import com.google.android.flexbox.FlexboxLayout import com.google.android.flexbox.FlexboxLayout
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.databinding.ItemCustomOutcomingTextMessageBinding
import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.models.json.chat.ReadStatus import com.nextcloud.talk.models.json.chat.ReadStatus
import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback
@ -53,57 +50,21 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewHolder<ChatMessage>(itemView) { class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewHolder<ChatMessage>(itemView) {
@JvmField private val binding: ItemCustomOutcomingTextMessageBinding = ItemCustomOutcomingTextMessageBinding.bind(itemView)
@BindView(R.id.messageText) private val realView: View = itemView
var messageText: EmojiTextView? = null
@JvmField
@BindView(R.id.messageTime)
var messageTimeView: TextView? = null
@JvmField
@BindView(R.id.quotedChatMessageView)
var quotedChatMessageView: RelativeLayout? = null
@JvmField
@BindView(R.id.quotedMessageAuthor)
var quotedUserName: EmojiTextView? = null
@JvmField
@BindView(R.id.quotedMessageImage)
var quotedMessagePreview: ImageView? = null
@JvmField
@BindView(R.id.quotedMessage)
var quotedMessage: EmojiTextView? = null
@JvmField
@BindView(R.id.quoteColoredView)
var quoteColoredView: View? = null
@JvmField
@BindView(R.id.checkMark)
var checkMark: ImageView? = null
@JvmField @JvmField
@Inject @Inject
var context: Context? = null var context: Context? = null
private val realView: View
init {
ButterKnife.bind(this, itemView)
this.realView = itemView
}
override fun onBind(message: ChatMessage) { override fun onBind(message: ChatMessage) {
super.onBind(message) super.onBind(message)
sharedApplication!!.componentApplication.inject(this) sharedApplication!!.componentApplication.inject(this)
val messageParameters: HashMap<String, HashMap<String, String>>? = message.messageParameters val messageParameters: HashMap<String, HashMap<String, String>>? = message.messageParameters
var messageString: Spannable = SpannableString(message.text) var messageString: Spannable = SpannableString(message.text)
realView.isSelected = false realView.isSelected = false
messageTimeView!!.setTextColor(context!!.resources.getColor(R.color.white60)) binding.messageTime.setTextColor(context!!.resources.getColor(R.color.white60))
val layoutParams = messageTimeView!!.layoutParams as FlexboxLayout.LayoutParams val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams
layoutParams.isWrapBefore = false layoutParams.isWrapBefore = false
var textSize = context!!.resources.getDimension(R.dimen.chat_text_size) var textSize = context!!.resources.getDimension(R.dimen.chat_text_size)
if (messageParameters != null && messageParameters.size > 0) { if (messageParameters != null && messageParameters.size > 0) {
@ -115,7 +76,7 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
) || individualHashMap["type"] == "call" ) || individualHashMap["type"] == "call"
) { ) {
messageString = searchAndReplaceWithMentionSpan( messageString = searchAndReplaceWithMentionSpan(
messageText!!.context, binding.messageText.context,
messageString, messageString,
individualHashMap["id"]!!, individualHashMap["id"]!!,
individualHashMap["name"]!!, individualHashMap["name"]!!,
@ -136,7 +97,7 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
} else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) { } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
textSize = (textSize * 2.5).toFloat() textSize = (textSize * 2.5).toFloat()
layoutParams.isWrapBefore = true layoutParams.isWrapBefore = true
messageTimeView!!.setTextColor(context!!.resources.getColor(R.color.warm_grey_four)) binding.messageTime.setTextColor(context!!.resources.getColor(R.color.warm_grey_four))
realView.isSelected = true realView.isSelected = true
} }
val resources = sharedApplication!!.resources val resources = sharedApplication!!.resources
@ -162,9 +123,9 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
) )
ViewCompat.setBackground(bubble, bubbleDrawable) ViewCompat.setBackground(bubble, bubbleDrawable)
} }
messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
messageTimeView!!.layoutParams = layoutParams binding.messageTime.layoutParams = layoutParams
messageText!!.text = messageString binding.messageText.text = messageString
// parent message handling // parent message handling
@ -172,27 +133,27 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
var parentChatMessage = message.parentMessage var parentChatMessage = message.parentMessage
parentChatMessage.activeUser = message.activeUser parentChatMessage.activeUser = message.activeUser
parentChatMessage.imageUrl?.let { parentChatMessage.imageUrl?.let {
quotedMessagePreview?.visibility = View.VISIBLE binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
quotedMessagePreview?.load(it) { binding.messageQuote.quotedMessageImage.load(it) {
addHeader( addHeader(
"Authorization", "Authorization",
ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token) ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
) )
} }
} ?: run { } ?: run {
quotedMessagePreview?.visibility = View.GONE binding.messageQuote.quotedMessageImage.visibility = View.GONE
} }
quotedUserName?.text = parentChatMessage.actorDisplayName binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
?: context!!.getText(R.string.nc_nick_guest) ?: context!!.getText(R.string.nc_nick_guest)
quotedMessage?.text = parentChatMessage.text binding.messageQuote.quotedMessage.text = parentChatMessage.text
quotedMessage?.setTextColor(context!!.resources.getColor(R.color.nc_outcoming_text_default)) binding.messageQuote.quotedMessage.setTextColor(context!!.resources.getColor(R.color.nc_outcoming_text_default))
quotedUserName?.setTextColor(context!!.resources.getColor(R.color.nc_grey)) binding.messageQuote.quotedMessageAuthor.setTextColor(context!!.resources.getColor(R.color.nc_grey))
quoteColoredView?.setBackgroundResource(R.color.white) binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.white)
quotedChatMessageView?.visibility = View.VISIBLE binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
} else { } else {
quotedChatMessageView?.visibility = View.GONE binding.messageQuote.quotedChatMessageView.visibility = View.GONE
} }
val readStatusDrawableInt = when (message.readStatus) { val readStatusDrawableInt = when (message.readStatus) {
@ -210,11 +171,11 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
readStatusDrawableInt?.let { drawableInt -> readStatusDrawableInt?.let { drawableInt ->
context?.resources?.getDrawable(drawableInt, null)?.let { context?.resources?.getDrawable(drawableInt, null)?.let {
it.setColorFilter(context?.resources!!.getColor(R.color.white60), PorterDuff.Mode.SRC_ATOP) it.setColorFilter(context?.resources!!.getColor(R.color.white60), PorterDuff.Mode.SRC_ATOP)
checkMark?.setImageDrawable(it) binding.checkMark.setImageDrawable(it)
} }
} }
checkMark?.setContentDescription(readStatusContentDescriptionString) binding.checkMark.setContentDescription(readStatusContentDescriptionString)
itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable) itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
} }

View file

@ -3,8 +3,10 @@
* *
* @author Mario Danic * @author Mario Danic
* @author Marcel Hibbe * @author Marcel Hibbe
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> * @author Andy Scherzinger
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
* Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de> * Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -35,6 +37,7 @@ import android.util.Log;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.ProgressBar;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
@ -45,6 +48,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.components.filebrowser.models.BrowserFile; import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
import com.nextcloud.talk.components.filebrowser.models.DavResponse; import com.nextcloud.talk.components.filebrowser.models.DavResponse;
import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation; import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation;
import com.nextcloud.talk.databinding.ItemCustomIncomingPreviewMessageBinding;
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker; import com.nextcloud.talk.jobs.DownloadFileToCacheWorker;
import com.nextcloud.talk.models.database.CapabilitiesUtil; import com.nextcloud.talk.models.database.CapabilitiesUtil;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
@ -70,8 +74,6 @@ import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkInfo; import androidx.work.WorkInfo;
import androidx.work.WorkManager; import androidx.work.WorkManager;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.Single; import io.reactivex.Single;
import io.reactivex.SingleObserver; import io.reactivex.SingleObserver;
import io.reactivex.annotations.NonNull; import io.reactivex.annotations.NonNull;
@ -82,15 +84,10 @@ import okhttp3.OkHttpClient;
import static com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback.REPLYABLE_VIEW_TAG; import static com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback.REPLYABLE_VIEW_TAG;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageMessageViewHolder<ChatMessage> { public abstract class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageMessageViewHolder<ChatMessage> {
private static final String TAG = "PreviewMsgViewHolder"; private static final String TAG = "PreviewMsgViewHolder";
@BindView(R.id.messageText)
EmojiTextView messageText;
View progressBar;
@Inject @Inject
Context context; Context context;
@ -99,8 +96,6 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
public MagicPreviewMessageViewHolder(View itemView) { public MagicPreviewMessageViewHolder(View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView);
progressBar = itemView.findViewById(R.id.progress_bar);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
} }
@ -131,7 +126,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
if (message.getMessageType() == ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) { if (message.getMessageType() == ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) {
String fileName = message.getSelectedIndividualHashMap().get("name"); String fileName = message.getSelectedIndividualHashMap().get("name");
messageText.setText(fileName); getMessageText().setText(fileName);
if (message.getSelectedIndividualHashMap().containsKey("mimetype")) { if (message.getSelectedIndividualHashMap().containsKey("mimetype")) {
String mimetype = message.getSelectedIndividualHashMap().get("mimetype"); String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
int drawableResourceId = DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(mimetype); int drawableResourceId = DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(mimetype);
@ -165,7 +160,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
try { try {
for (WorkInfo workInfo : workers.get()) { for (WorkInfo workInfo : workers.get()) {
if (workInfo.getState() == WorkInfo.State.RUNNING || workInfo.getState() == WorkInfo.State.ENQUEUED) { if (workInfo.getState() == WorkInfo.State.RUNNING || workInfo.getState() == WorkInfo.State.ENQUEUED) {
progressBar.setVisibility(View.VISIBLE); getProgressBar().setVisibility(View.VISIBLE);
String mimetype = message.getSelectedIndividualHashMap().get("mimetype"); String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
@ -178,11 +173,11 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
Log.e(TAG, "Error when checking if worker already exists", e); Log.e(TAG, "Error when checking if worker already exists", e);
} }
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_GIPHY_MESSAGE) { } else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_GIPHY_MESSAGE) {
messageText.setText("GIPHY"); getMessageText().setText("GIPHY");
DisplayUtils.setClickableString("GIPHY", "https://giphy.com", messageText); DisplayUtils.setClickableString("GIPHY", "https://giphy.com", getMessageText());
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_TENOR_MESSAGE) { } else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_TENOR_MESSAGE) {
messageText.setText("Tenor"); getMessageText().setText("Tenor");
DisplayUtils.setClickableString("Tenor", "https://tenor.com", messageText); DisplayUtils.setClickableString("Tenor", "https://tenor.com", getMessageText());
} else { } else {
if (message.getMessageType().equals(ChatMessage.MessageType.SINGLE_LINK_IMAGE_MESSAGE)) { if (message.getMessageType().equals(ChatMessage.MessageType.SINGLE_LINK_IMAGE_MESSAGE)) {
image.setOnClickListener(v -> { image.setOnClickListener(v -> {
@ -193,12 +188,16 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
} else { } else {
image.setOnClickListener(null); image.setOnClickListener(null);
} }
messageText.setText(""); getMessageText().setText("");
} }
itemView.setTag(REPLYABLE_VIEW_TAG, message.isReplyable()); itemView.setTag(REPLYABLE_VIEW_TAG, message.isReplyable());
} }
public abstract EmojiTextView getMessageText();
public abstract ProgressBar getProgressBar();
private void openOrDownloadFile(ChatMessage message) { private void openOrDownloadFile(ChatMessage message) {
String filename = message.getSelectedIndividualHashMap().get("name"); String filename = message.getSelectedIndividualHashMap().get("name");
String mimetype = message.getSelectedIndividualHashMap().get("mimetype"); String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
@ -388,7 +387,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
WorkManager.getInstance().enqueue(downloadWorker); WorkManager.getInstance().enqueue(downloadWorker);
progressBar.setVisibility(View.VISIBLE); getProgressBar().setVisibility(View.VISIBLE);
WorkManager.getInstance(context).getWorkInfoByIdLiveData(downloadWorker.getId()).observeForever(workInfo -> { WorkManager.getInstance(context).getWorkInfoByIdLiveData(downloadWorker.getId()).observeForever(workInfo -> {
updateViewsByProgress(fileName, mimetype, workInfo); updateViewsByProgress(fileName, mimetype, workInfo);
@ -400,7 +399,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
case RUNNING: case RUNNING:
int progress = workInfo.getProgress().getInt(DownloadFileToCacheWorker.PROGRESS, -1); int progress = workInfo.getProgress().getInt(DownloadFileToCacheWorker.PROGRESS, -1);
if (progress > -1) { if (progress > -1) {
messageText.setText(String.format(context.getResources().getString(R.string.filename_progress), fileName, progress)); getMessageText().setText(String.format(context.getResources().getString(R.string.filename_progress), fileName, progress));
} }
break; break;
@ -411,13 +410,13 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
Log.d(TAG, "file " + fileName + " was downloaded but it's not opened because view is not shown on" + Log.d(TAG, "file " + fileName + " was downloaded but it's not opened because view is not shown on" +
" screen"); " screen");
} }
messageText.setText(fileName); getMessageText().setText(fileName);
progressBar.setVisibility(View.GONE); getProgressBar().setVisibility(View.GONE);
break; break;
case FAILED: case FAILED:
messageText.setText(fileName); getMessageText().setText(fileName);
progressBar.setVisibility(View.GONE); getProgressBar().setVisibility(View.GONE);
break; break;
default: default:
// do nothing // do nothing
@ -486,6 +485,5 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
Log.e(TAG, "Error reading file information", e); Log.e(TAG, "Error reading file information", e);
} }
}); });
} }
} }

View file

@ -33,21 +33,16 @@ import android.view.MotionEvent
import android.view.View import android.view.View
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.emoji.widget.EmojiTextView
import autodagger.AutoInjector import autodagger.AutoInjector
import butterknife.BindView
import butterknife.ButterKnife
import coil.load import coil.load
import com.google.android.flexbox.FlexboxLayout import com.google.android.flexbox.FlexboxLayout
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.databinding.ItemCustomOutcomingLocationMessageBinding
import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.models.json.chat.ReadStatus import com.nextcloud.talk.models.json.chat.ReadStatus
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
@ -59,6 +54,9 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
.OutcomingTextMessageViewHolder<ChatMessage>(incomingView) { .OutcomingTextMessageViewHolder<ChatMessage>(incomingView) {
private val binding: ItemCustomOutcomingLocationMessageBinding =
ItemCustomOutcomingLocationMessageBinding.bind(itemView)
private val realView: View = itemView
private val TAG = "LocMessageView" private val TAG = "LocMessageView"
@ -67,56 +65,18 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
var locationName: String? = "" var locationName: String? = ""
var locationGeoLink: String? = "" var locationGeoLink: String? = ""
@JvmField
@BindView(R.id.messageText)
var messageText: EmojiTextView? = null
@JvmField
@BindView(R.id.messageTime)
var messageTimeView: TextView? = null
@JvmField
@BindView(R.id.quotedChatMessageView)
var quotedChatMessageView: RelativeLayout? = null
@JvmField
@BindView(R.id.quotedMessageAuthor)
var quotedUserName: EmojiTextView? = null
@JvmField
@BindView(R.id.quotedMessageImage)
var quotedMessagePreview: ImageView? = null
@JvmField
@BindView(R.id.quotedMessage)
var quotedMessage: EmojiTextView? = null
@JvmField
@BindView(R.id.quoteColoredView)
var quoteColoredView: View? = null
@JvmField
@BindView(R.id.checkMark)
var checkMark: ImageView? = null
@JvmField @JvmField
@Inject @Inject
var context: Context? = null var context: Context? = null
@JvmField
@BindView(R.id.webview)
var webview: WebView? = null
private val realView: View
@SuppressLint("SetTextI18n", "SetJavaScriptEnabled", "ClickableViewAccessibility") @SuppressLint("SetTextI18n", "SetJavaScriptEnabled", "ClickableViewAccessibility")
override fun onBind(message: ChatMessage) { override fun onBind(message: ChatMessage) {
super.onBind(message) super.onBind(message)
sharedApplication!!.componentApplication.inject(this) sharedApplication!!.componentApplication.inject(this)
realView.isSelected = false realView.isSelected = false
messageTimeView!!.setTextColor(context!!.resources.getColor(R.color.white60)) binding.messageTime.setTextColor(context!!.resources.getColor(R.color.white60))
val layoutParams = messageTimeView!!.layoutParams as FlexboxLayout.LayoutParams val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams
layoutParams.isWrapBefore = false layoutParams.isWrapBefore = false
val textSize = context!!.resources.getDimension(R.dimen.chat_text_size) val textSize = context!!.resources.getDimension(R.dimen.chat_text_size)
@ -144,10 +104,10 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
) )
ViewCompat.setBackground(bubble, bubbleDrawable) ViewCompat.setBackground(bubble, bubbleDrawable)
} }
messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
messageTimeView!!.layoutParams = layoutParams binding.messageTime.layoutParams = layoutParams
messageText!!.text = message.text binding.messageText.text = message.text
messageText!!.isEnabled = false binding.messageText.isEnabled = false
// parent message handling // parent message handling
@ -155,27 +115,27 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
val parentChatMessage = message.parentMessage val parentChatMessage = message.parentMessage
parentChatMessage.activeUser = message.activeUser parentChatMessage.activeUser = message.activeUser
parentChatMessage.imageUrl?.let { parentChatMessage.imageUrl?.let {
quotedMessagePreview?.visibility = View.VISIBLE binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
quotedMessagePreview?.load(it) { binding.messageQuote.quotedMessageImage.load(it) {
addHeader( addHeader(
"Authorization", "Authorization",
ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token) ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
) )
} }
} ?: run { } ?: run {
quotedMessagePreview?.visibility = View.GONE binding.messageQuote.quotedMessageImage.visibility = View.GONE
} }
quotedUserName?.text = parentChatMessage.actorDisplayName binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
?: context!!.getText(R.string.nc_nick_guest) ?: context!!.getText(R.string.nc_nick_guest)
quotedMessage?.text = parentChatMessage.text binding.messageQuote.quotedMessage.text = parentChatMessage.text
quotedMessage?.setTextColor(context!!.resources.getColor(R.color.nc_outcoming_text_default)) binding.messageQuote.quotedMessage.setTextColor(context!!.resources.getColor(R.color.nc_outcoming_text_default))
quotedUserName?.setTextColor(context!!.resources.getColor(R.color.nc_grey)) binding.messageQuote.quotedMessageAuthor.setTextColor(context!!.resources.getColor(R.color.nc_grey))
quoteColoredView?.setBackgroundResource(R.color.white) binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.white)
quotedChatMessageView?.visibility = View.VISIBLE binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
} else { } else {
quotedChatMessageView?.visibility = View.GONE binding.messageQuote.quotedChatMessageView.visibility = View.GONE
} }
val readStatusDrawableInt = when (message.readStatus) { val readStatusDrawableInt = when (message.readStatus) {
@ -193,11 +153,11 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
readStatusDrawableInt?.let { drawableInt -> readStatusDrawableInt?.let { drawableInt ->
AppCompatResources.getDrawable(context!!, drawableInt)?.let { AppCompatResources.getDrawable(context!!, drawableInt)?.let {
it.setColorFilter(context?.resources!!.getColor(R.color.white60), PorterDuff.Mode.SRC_ATOP) it.setColorFilter(context?.resources!!.getColor(R.color.white60), PorterDuff.Mode.SRC_ATOP)
checkMark?.setImageDrawable(it) binding.checkMark.setImageDrawable(it)
} }
} }
checkMark?.setContentDescription(readStatusContentDescriptionString) binding.checkMark.setContentDescription(readStatusContentDescriptionString)
// geo-location // geo-location
@ -213,9 +173,9 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
} }
} }
webview?.settings?.javaScriptEnabled = true binding.webview.settings?.javaScriptEnabled = true
webview?.webViewClient = object : WebViewClient() { binding.webview.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return if (url != null && (url.startsWith("http://") || url.startsWith("https://")) return if (url != null && (url.startsWith("http://") || url.startsWith("https://"))
) { ) {
@ -242,9 +202,9 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
urlStringBuffer.append("&locationName=" + URLEncoder.encode(locationName)) urlStringBuffer.append("&locationName=" + URLEncoder.encode(locationName))
urlStringBuffer.append("&locationGeoLink=" + URLEncoder.encode(locationGeoLink)) urlStringBuffer.append("&locationGeoLink=" + URLEncoder.encode(locationGeoLink))
webview?.loadUrl(urlStringBuffer.toString()) binding.webview.loadUrl(urlStringBuffer.toString())
webview?.setOnTouchListener(object : View.OnTouchListener { binding.webview.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean { override fun onTouch(v: View?, event: MotionEvent?): Boolean {
when (event?.action) { when (event?.action) {
MotionEvent.ACTION_UP -> openGeoLink() MotionEvent.ACTION_UP -> openGeoLink()
@ -270,9 +230,4 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
private fun addMarkerToGeoLink(locationGeoLink: String): String { private fun addMarkerToGeoLink(locationGeoLink: String): String {
return locationGeoLink.replace("geo:", "geo:0,0?q=") return locationGeoLink.replace("geo:", "geo:0,0?q=")
} }
init {
ButterKnife.bind(this, itemView)
this.realView = itemView
}
} }

View file

@ -0,0 +1,45 @@
/*
* Nextcloud Talk application
*
* @author Andy Scherzinger
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.adapters.messages;
import android.view.View;
import android.widget.ProgressBar;
import com.nextcloud.talk.databinding.ItemCustomOutcomingPreviewMessageBinding;
import androidx.emoji.widget.EmojiTextView;
public class OutcomingPreviewMessageViewHolder extends MagicPreviewMessageViewHolder {
private final ItemCustomOutcomingPreviewMessageBinding binding;
public OutcomingPreviewMessageViewHolder(View itemView) {
super(itemView);
binding = ItemCustomOutcomingPreviewMessageBinding.bind(itemView);
}
public EmojiTextView getMessageText() {
return binding.messageText;
}
public ProgressBar getProgressBar() {
return binding.progressBar;
}
}

View file

@ -79,12 +79,13 @@ import com.google.android.flexbox.FlexboxLayout
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MagicCallActivity import com.nextcloud.talk.activities.MagicCallActivity
import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder
import com.nextcloud.talk.adapters.messages.IncomingPreviewMessageViewHolder
import com.nextcloud.talk.adapters.messages.MagicIncomingTextMessageViewHolder import com.nextcloud.talk.adapters.messages.MagicIncomingTextMessageViewHolder
import com.nextcloud.talk.adapters.messages.MagicOutcomingTextMessageViewHolder import com.nextcloud.talk.adapters.messages.MagicOutcomingTextMessageViewHolder
import com.nextcloud.talk.adapters.messages.MagicPreviewMessageViewHolder
import com.nextcloud.talk.adapters.messages.MagicSystemMessageViewHolder import com.nextcloud.talk.adapters.messages.MagicSystemMessageViewHolder
import com.nextcloud.talk.adapters.messages.MagicUnreadNoticeMessageViewHolder import com.nextcloud.talk.adapters.messages.MagicUnreadNoticeMessageViewHolder
import com.nextcloud.talk.adapters.messages.OutcomingLocationMessageViewHolder import com.nextcloud.talk.adapters.messages.OutcomingLocationMessageViewHolder
import com.nextcloud.talk.adapters.messages.OutcomingPreviewMessageViewHolder
import com.nextcloud.talk.adapters.messages.TalkMessagesListAdapter import com.nextcloud.talk.adapters.messages.TalkMessagesListAdapter
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
@ -400,23 +401,15 @@ class ChatController(args: Bundle) :
) )
messageHolders.setIncomingImageConfig( messageHolders.setIncomingImageConfig(
MagicPreviewMessageViewHolder::class.java, IncomingPreviewMessageViewHolder::class.java,
R.layout.item_custom_incoming_preview_message R.layout.item_custom_incoming_preview_message
) )
messageHolders.setOutcomingImageConfig( messageHolders.setOutcomingImageConfig(
MagicPreviewMessageViewHolder::class.java, OutcomingPreviewMessageViewHolder::class.java,
R.layout.item_custom_outcoming_preview_message R.layout.item_custom_outcoming_preview_message
) )
// messageHolders.setIncomingLocationConfig(
// LocationMessageViewHolder::class.java,
// R.layout.item_custom_location_message
// )
// messageHolders.setOutcomingLocationConfig(
// LocationMessageViewHolder::class.java,
// R.layout.item_custom_location_message
// )
messageHolders.registerContentType( messageHolders.registerContentType(
CONTENT_TYPE_SYSTEM_MESSAGE, CONTENT_TYPE_SYSTEM_MESSAGE,
MagicSystemMessageViewHolder::class.java, MagicSystemMessageViewHolder::class.java,

View file

@ -3,8 +3,10 @@
~ ~
~ @author Mario Danic ~ @author Mario Danic
~ @author Marcel Hibbe ~ @author Marcel Hibbe
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> ~ @author Andy Scherzinger
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de> ~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~ ~
~ This program is free software: you can redistribute it and/or modify ~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by ~ it under the terms of the GNU General Public License as published by
@ -49,13 +51,15 @@
app:flexWrap="wrap" app:flexWrap="wrap"
app:justifyContent="flex_end"> app:justifyContent="flex_end">
<include layout="@layout/item_message_quote" android:visibility="gone"/> <include
android:id="@+id/message_quote"
layout="@layout/item_message_quote"
android:visibility="gone" />
<WebView <WebView
android:id="@+id/webview" android:id="@+id/webview"
android:layout_width="400dp" android:layout_width="400dp"
android:layout_height="200dp" android:layout_height="200dp" />
/>
<androidx.emoji.widget.EmojiTextView <androidx.emoji.widget.EmojiTextView
android:id="@+id/messageAuthor" android:id="@+id/messageAuthor"
@ -84,4 +88,4 @@
app:layout_alignSelf="center" /> app:layout_alignSelf="center" />
</com.google.android.flexbox.FlexboxLayout> </com.google.android.flexbox.FlexboxLayout>
</RelativeLayout> </RelativeLayout>

View file

@ -2,6 +2,8 @@
~ Nextcloud Talk application ~ Nextcloud Talk application
~ ~
~ @author Mario Danic ~ @author Mario Danic
~ @author Andy Scherzinger
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~ ~
~ This program is free software: you can redistribute it and/or modify ~ This program is free software: you can redistribute it and/or modify
@ -47,7 +49,10 @@
app:flexWrap="wrap" app:flexWrap="wrap"
app:justifyContent="flex_end"> app:justifyContent="flex_end">
<include layout="@layout/item_message_quote" android:visibility="gone"/> <include
android:id="@+id/message_quote"
layout="@layout/item_message_quote"
android:visibility="gone" />
<androidx.emoji.widget.EmojiTextView <androidx.emoji.widget.EmojiTextView
android:id="@+id/messageAuthor" android:id="@+id/messageAuthor"

View file

@ -41,13 +41,15 @@
app:flexWrap="wrap" app:flexWrap="wrap"
app:justifyContent="flex_end"> app:justifyContent="flex_end">
<include layout="@layout/item_message_quote" android:visibility="gone"/> <include
android:id="@+id/message_quote"
layout="@layout/item_message_quote"
android:visibility="gone" />
<WebView <WebView
android:id="@+id/webview" android:id="@+id/webview"
android:layout_width="400dp" android:layout_width="400dp"
android:layout_height="200dp" android:layout_height="200dp" />
/>
<androidx.emoji.widget.EmojiTextView <androidx.emoji.widget.EmojiTextView
android:id="@id/messageText" android:id="@id/messageText"

View file

@ -41,7 +41,10 @@
app:flexWrap="wrap" app:flexWrap="wrap"
app:justifyContent="flex_end"> app:justifyContent="flex_end">
<include layout="@layout/item_message_quote" android:visibility="gone"/> <include
android:id="@+id/message_quote"
layout="@layout/item_message_quote"
android:visibility="gone" />
<androidx.emoji.widget.EmojiTextView <androidx.emoji.widget.EmojiTextView
android:id="@id/messageText" android:id="@id/messageText"