differ between incoming and outcoming messages for location

logic was copied from:
- MagicIncomingTextMessageViewHolder.kt
- MagicOutcomingTextMessageViewHolder.kt

xml design was copied from:
- item_custom_incoming_text_message.xml
- item_custom_outcoming_text_message.xml

... and extended for location related things.

because of copying there is now quite a lot of redundant code! But ViewHolders should generally be refactored in the future.. (better inheritance(?) and analyze which of Marios changes to the Chatkit lib were really necessary or if this can be done in an other way..)

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2021-05-29 23:39:34 +02:00 committed by Andy Scherzinger
parent 7540e57dd8
commit 1aa15ebd95
No known key found for this signature in database
GPG Key ID: 6CADC7E3523C308B
9 changed files with 785 additions and 190 deletions

View File

@ -0,0 +1,322 @@
package com.nextcloud.talk.adapters.messages
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.net.Uri
import android.text.Spannable
import android.text.SpannableString
import android.text.TextUtils
import android.util.Log
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.emoji.widget.EmojiTextView
import autodagger.AutoInjector
import butterknife.BindView
import butterknife.ButterKnife
import coil.load
import com.amulyakhare.textdrawable.TextDrawable
import com.facebook.drawee.view.SimpleDraweeView
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.utils.ApiUtils
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.net.URLEncoder
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders
.IncomingTextMessageViewHolder<ChatMessage>(incomingView) {
private val TAG = "LocationMessageViewHolder"
var mapProviderUrl: String = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
var mapProviderAttribution: String = "OpenStreetMap contributors"
var locationLon: String? = ""
var locationLat: String? = ""
var locationName: 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
@Inject
var context: Context? = null
@JvmField
@Inject
var appPreferences: AppPreferences? = null
@JvmField
@BindView(R.id.webview)
var webview: WebView? = null
init {
ButterKnife.bind(
this,
itemView
)
}
@SuppressLint("SetTextI18n", "SetJavaScriptEnabled", "ClickableViewAccessibility")
override fun onBind(message: ChatMessage) {
super.onBind(message)
sharedApplication!!.componentApplication.inject(this)
val author: String = message.actorDisplayName
if (!TextUtils.isEmpty(author)) {
messageAuthor!!.text = author
} else {
messageAuthor!!.setText(R.string.nc_nick_guest)
}
if (!message.isGrouped && !message.isOneToOneConversation) {
messageUserAvatarView!!.visibility = View.VISIBLE
if (message.actorType == "guests") {
// do nothing, avatar is set
} else if (message.actorType == "bots" && message.actorId == "changelog") {
val layers = arrayOfNulls<Drawable>(2)
layers[0] = context?.getDrawable(R.drawable.ic_launcher_background)
layers[1] = context?.getDrawable(R.drawable.ic_launcher_foreground)
val layerDrawable = LayerDrawable(layers)
messageUserAvatarView?.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
} else if (message.actorType == "bots") {
val drawable = TextDrawable.builder()
.beginConfig()
.bold()
.endConfig()
.buildRound(
">",
context!!.resources.getColor(R.color.black)
)
messageUserAvatarView!!.visibility = View.VISIBLE
messageUserAvatarView?.setImageDrawable(drawable)
}
} else {
if (message.isOneToOneConversation) {
messageUserAvatarView!!.visibility = View.GONE
} else {
messageUserAvatarView!!.visibility = View.INVISIBLE
}
messageAuthor!!.visibility = View.GONE
}
val resources = itemView.resources
val bgBubbleColor = if (message.isDeleted) {
resources.getColor(R.color.bg_message_list_incoming_bubble_deleted)
} else {
resources.getColor(R.color.bg_message_list_incoming_bubble)
}
var bubbleResource = R.drawable.shape_incoming_message
if (message.isGrouped) {
bubbleResource = R.drawable.shape_grouped_incoming_message
}
val bubbleDrawable = DisplayUtils.getMessageSelector(
bgBubbleColor,
resources.getColor(R.color.transparent),
bgBubbleColor, bubbleResource
)
ViewCompat.setBackground(bubble, bubbleDrawable)
val messageParameters = message.messageParameters
itemView.isSelected = false
messageTimeView!!.setTextColor(context?.resources!!.getColor(R.color.warm_grey_four))
var messageString: Spannable = SpannableString(message.text)
var textSize = context?.resources!!.getDimension(R.dimen.chat_text_size)
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(
messageText!!.context,
messageString,
individualHashMap["id"]!!,
individualHashMap["name"]!!,
individualHashMap["type"]!!,
message.activeUser!!,
R.xml.chip_you
)
} else {
messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
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)
}
}
}
}
} else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
textSize = (textSize * 2.5).toFloat()
itemView.isSelected = true
messageAuthor!!.visibility = View.GONE
}
messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
messageText!!.text = messageString
// parent message handling
if (!message.isDeleted && message.parentMessage != null) {
var parentChatMessage = message.parentMessage
parentChatMessage.activeUser = message.activeUser
parentChatMessage.imageUrl?.let {
quotedMessagePreview?.visibility = View.VISIBLE
quotedMessagePreview?.load(it) {
addHeader(
"Authorization",
ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
)
}
} ?: run {
quotedMessagePreview?.visibility = View.GONE
}
quotedUserName?.text = parentChatMessage.actorDisplayName
?: context!!.getText(R.string.nc_nick_guest)
quotedMessage?.text = parentChatMessage.text
quotedUserName?.setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast))
if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
quoteColoredView?.setBackgroundResource(R.color.colorPrimary)
} else {
quoteColoredView?.setBackgroundResource(R.color.textColorMaxContrast)
}
quotedChatMessageView?.visibility = View.VISIBLE
} else {
quotedChatMessageView?.visibility = View.GONE
}
// geo-location
if (message.messageParameters != null && message.messageParameters.size > 0) {
for (key in message.messageParameters.keys) {
val individualHashMap: Map<String, String> = message.messageParameters[key]!!
if (individualHashMap["type"] == "geo-location") {
locationLon = individualHashMap["longitude"]
locationLat = individualHashMap["latitude"]
locationName = individualHashMap["name"]
locationGeoLink = individualHashMap["id"]
}
}
}
webview?.settings?.javaScriptEnabled = true
webview?.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return if (url != null && (url.startsWith("http://") || url.startsWith("https://"))
) {
view?.context?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
true
} else {
false
}
}
}
val urlStringBuffer = StringBuffer("file:///android_asset/leafletMapMessagePreview.html")
urlStringBuffer.append("?mapProviderUrl=" + URLEncoder.encode(mapProviderUrl))
urlStringBuffer.append("&mapProviderAttribution=" + URLEncoder.encode(mapProviderAttribution))
urlStringBuffer.append("&locationLat=" + URLEncoder.encode(locationLat))
urlStringBuffer.append("&locationLon=" + URLEncoder.encode(locationLon))
urlStringBuffer.append("&locationName=" + URLEncoder.encode(locationName))
urlStringBuffer.append("&locationGeoLink=" + URLEncoder.encode(locationGeoLink))
webview?.loadUrl(urlStringBuffer.toString())
webview?.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_UP -> openGeoLink()
}
return v?.onTouchEvent(event) ?: true
}
})
}
private fun openGeoLink() {
if (!locationGeoLink.isNullOrEmpty()) {
val geoLinkWithMarker = addMarkerToGeoLink(locationGeoLink!!)
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(geoLinkWithMarker))
context!!.startActivity(browserIntent)
} else {
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
Log.e(TAG, "locationGeoLink was null or empty")
}
}
private fun addMarkerToGeoLink(locationGeoLink: String): String {
return locationGeoLink.replace("geo:", "geo:0,0?q=")
}
}

View File

@ -1,128 +0,0 @@
package com.nextcloud.talk.adapters.messages
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.TextView
import android.widget.Toast
import autodagger.AutoInjector
import butterknife.BindView
import butterknife.ButterKnife
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.models.json.chat.ChatMessage
import com.stfalcon.chatkit.messages.MessageHolders
import java.net.URLEncoder
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class LocationMessageViewHolder(incomingView: View) : MessageHolders
.IncomingTextMessageViewHolder<ChatMessage>(incomingView) {
private val TAG = "LocationMessageViewHolder"
var mapProviderUrl: String = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
var mapProviderAttribution: String = "OpenStreetMap contributors"
var locationLon: String? = ""
var locationLat: String? = ""
var locationName: String? = ""
var locationGeoLink: String? = ""
@JvmField
@BindView(R.id.locationText)
var messageText: TextView? = null
@JvmField
@BindView(R.id.webview)
var webview: WebView? = null
@JvmField
@Inject
var context: Context? = null
init {
ButterKnife.bind(
this,
itemView
)
}
@SuppressLint("SetTextI18n", "SetJavaScriptEnabled", "ClickableViewAccessibility")
override fun onBind(message: ChatMessage) {
super.onBind(message)
sharedApplication!!.componentApplication.inject(this)
// if (message.messageType == ChatMessage.MessageType.SINGLE_NC_GEOLOCATION_MESSAGE) {
// Log.d(TAG, "handle geolocation here")
// messageText!!.text = "geolocation..."
// }
if (message.messageParameters != null && message.messageParameters.size > 0) {
for (key in message.messageParameters.keys) {
val individualHashMap: Map<String, String> = message.messageParameters[key]!!
if (individualHashMap["type"] == "geo-location") {
locationLon = individualHashMap["longitude"]
locationLat = individualHashMap["latitude"]
locationName = individualHashMap["name"]
locationGeoLink = individualHashMap["id"]
}
}
}
webview?.settings?.javaScriptEnabled = true
webview?.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return if (url != null && (url.startsWith("http://") || url.startsWith("https://"))
) {
view?.context?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
true
} else {
false
}
}
}
val urlStringBuffer = StringBuffer("file:///android_asset/leafletMapMessagePreview.html")
urlStringBuffer.append("?mapProviderUrl=" + URLEncoder.encode(mapProviderUrl))
urlStringBuffer.append("&mapProviderAttribution=" + URLEncoder.encode(mapProviderAttribution))
urlStringBuffer.append("&locationLat=" + URLEncoder.encode(locationLat))
urlStringBuffer.append("&locationLon=" + URLEncoder.encode(locationLon))
urlStringBuffer.append("&locationName=" + URLEncoder.encode(locationName))
urlStringBuffer.append("&locationGeoLink=" + URLEncoder.encode(locationGeoLink))
webview?.loadUrl(urlStringBuffer.toString())
webview?.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_UP -> openGeoLink()
}
return v?.onTouchEvent(event) ?: true
}
})
}
private fun openGeoLink() {
if (!locationGeoLink.isNullOrEmpty()) {
val geoLinkWithMarker = addMarkerToGeoLink(locationGeoLink!!)
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(geoLinkWithMarker))
context!!.startActivity(browserIntent)
} else {
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
Log.e(TAG, "locationGeoLink was null or empty")
}
}
private fun addMarkerToGeoLink(locationGeoLink: String): String {
return locationGeoLink.replace("geo:", "geo:0,0?q=")
}
}

View File

@ -101,10 +101,6 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
@Inject
var appPreferences: AppPreferences? = null
init {
ButterKnife.bind(this, itemView)
}
override fun onBind(message: ChatMessage) {
super.onBind(message)
sharedApplication!!.componentApplication.inject(this)
@ -258,4 +254,8 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders
itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
}
init {
ButterKnife.bindthis, itemView)
}
}

View File

@ -177,8 +177,6 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Error when checking if worker already exists", e);
}
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_NC_GEOLOCATION_MESSAGE) {
Log.d(TAG, "handle geolocation here");
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_GIPHY_MESSAGE) {
messageText.setText("GIPHY");
DisplayUtils.setClickableString("GIPHY", "https://giphy.com", messageText);

View File

@ -0,0 +1,285 @@
package com.nextcloud.talk.adapters.messages
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.PorterDuff
import android.net.Uri
import android.text.Spannable
import android.text.SpannableString
import android.util.Log
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.emoji.widget.EmojiTextView
import autodagger.AutoInjector
import butterknife.BindView
import butterknife.ButterKnife
import coil.load
import com.google.android.flexbox.FlexboxLayout
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.models.json.chat.ReadStatus
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.TextMatchers
import com.stfalcon.chatkit.messages.MessageHolders
import java.net.URLEncoder
import java.util.HashMap
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class OutcomingLocationMessageViewHolder(incomingView: View) : MessageHolders
.OutcomingTextMessageViewHolder<ChatMessage>(incomingView) {
private val TAG = "LocationMessageViewHolder"
var mapProviderUrl: String = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
var mapProviderAttribution: String = "OpenStreetMap contributors"
var locationLon: String? = ""
var locationLat: String? = ""
var locationName: 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
@Inject
var context: Context? = null
@JvmField
@BindView(R.id.webview)
var webview: WebView? = null
private val realView: View
@SuppressLint("SetTextI18n", "SetJavaScriptEnabled", "ClickableViewAccessibility")
override fun onBind(message: ChatMessage) {
super.onBind(message)
sharedApplication!!.componentApplication.inject(this)
val messageParameters: HashMap<String, HashMap<String, String>>? = message.messageParameters
var messageString: Spannable = SpannableString(message.text)
realView.isSelected = false
messageTimeView!!.setTextColor(context!!.resources.getColor(R.color.white60))
val layoutParams = messageTimeView!!.layoutParams as FlexboxLayout.LayoutParams
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 = DisplayUtils.searchAndReplaceWithMentionSpan(
messageText!!.context,
messageString,
individualHashMap["id"]!!,
individualHashMap["name"]!!,
individualHashMap["type"]!!,
message.activeUser,
R.xml.chip_others
)
} else if (individualHashMap["type"] == "file") {
realView.setOnClickListener(
View.OnClickListener { v: View? ->
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
context!!.startActivity(browserIntent)
}
)
}
}
}
} else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
textSize = (textSize * 2.5).toFloat()
layoutParams.isWrapBefore = true
messageTimeView!!.setTextColor(context!!.resources.getColor(R.color.warm_grey_four))
realView.isSelected = true
}
val resources = sharedApplication!!.resources
val bgBubbleColor = if (message.isDeleted) {
resources.getColor(R.color.bg_message_list_outcoming_bubble_deleted)
} else {
resources.getColor(R.color.bg_message_list_outcoming_bubble)
}
if (message.isGrouped) {
val bubbleDrawable = DisplayUtils.getMessageSelector(
bgBubbleColor,
resources.getColor(R.color.transparent),
bgBubbleColor,
R.drawable.shape_grouped_outcoming_message
)
ViewCompat.setBackground(bubble, bubbleDrawable)
} else {
val bubbleDrawable = DisplayUtils.getMessageSelector(
bgBubbleColor,
resources.getColor(R.color.transparent),
bgBubbleColor,
R.drawable.shape_outcoming_message
)
ViewCompat.setBackground(bubble, bubbleDrawable)
}
messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
messageTimeView!!.layoutParams = layoutParams
messageText!!.text = messageString
// parent message handling
if (!message.isDeleted && message.parentMessage != null) {
var parentChatMessage = message.parentMessage
parentChatMessage.activeUser = message.activeUser
parentChatMessage.imageUrl?.let {
quotedMessagePreview?.visibility = View.VISIBLE
quotedMessagePreview?.load(it) {
addHeader(
"Authorization",
ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
)
}
} ?: run {
quotedMessagePreview?.visibility = View.GONE
}
quotedUserName?.text = parentChatMessage.actorDisplayName
?: context!!.getText(R.string.nc_nick_guest)
quotedMessage?.text = parentChatMessage.text
quotedMessage?.setTextColor(context!!.resources.getColor(R.color.nc_outcoming_text_default))
quotedUserName?.setTextColor(context!!.resources.getColor(R.color.nc_grey))
quoteColoredView?.setBackgroundResource(R.color.white)
quotedChatMessageView?.visibility = View.VISIBLE
} else {
quotedChatMessageView?.visibility = View.GONE
}
val readStatusDrawableInt = when (message.readStatus) {
ReadStatus.READ -> R.drawable.ic_check_all
ReadStatus.SENT -> R.drawable.ic_check
else -> null
}
val readStatusContentDescriptionString = when (message.readStatus) {
ReadStatus.READ -> context?.resources?.getString(R.string.nc_message_read)
ReadStatus.SENT -> context?.resources?.getString(R.string.nc_message_sent)
else -> null
}
readStatusDrawableInt?.let { drawableInt ->
context?.resources?.getDrawable(drawableInt, null)?.let {
it.setColorFilter(context?.resources!!.getColor(R.color.white60), PorterDuff.Mode.SRC_ATOP)
checkMark?.setImageDrawable(it)
}
}
checkMark?.setContentDescription(readStatusContentDescriptionString)
// geo-location
if (message.messageParameters != null && message.messageParameters.size > 0) {
for (key in message.messageParameters.keys) {
val individualHashMap: Map<String, String> = message.messageParameters[key]!!
if (individualHashMap["type"] == "geo-location") {
locationLon = individualHashMap["longitude"]
locationLat = individualHashMap["latitude"]
locationName = individualHashMap["name"]
locationGeoLink = individualHashMap["id"]
}
}
}
webview?.settings?.javaScriptEnabled = true
webview?.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return if (url != null && (url.startsWith("http://") || url.startsWith("https://"))
) {
view?.context?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
true
} else {
false
}
}
}
val urlStringBuffer = StringBuffer("file:///android_asset/leafletMapMessagePreview.html")
urlStringBuffer.append("?mapProviderUrl=" + URLEncoder.encode(mapProviderUrl))
urlStringBuffer.append("&mapProviderAttribution=" + URLEncoder.encode(mapProviderAttribution))
urlStringBuffer.append("&locationLat=" + URLEncoder.encode(locationLat))
urlStringBuffer.append("&locationLon=" + URLEncoder.encode(locationLon))
urlStringBuffer.append("&locationName=" + URLEncoder.encode(locationName))
urlStringBuffer.append("&locationGeoLink=" + URLEncoder.encode(locationGeoLink))
webview?.loadUrl(urlStringBuffer.toString())
webview?.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_UP -> openGeoLink()
}
return v?.onTouchEvent(event) ?: true
}
})
}
private fun openGeoLink() {
if (!locationGeoLink.isNullOrEmpty()) {
val geoLinkWithMarker = addMarkerToGeoLink(locationGeoLink!!)
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(geoLinkWithMarker))
context!!.startActivity(browserIntent)
} else {
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
Log.e(TAG, "locationGeoLink was null or empty")
}
}
private fun addMarkerToGeoLink(locationGeoLink: String): String {
return locationGeoLink.replace("geo:", "geo:0,0?q=")
}
init {
ButterKnife.bind(this, itemView)
this.realView = itemView
}
}

View File

@ -78,12 +78,13 @@ import com.facebook.imagepipeline.image.CloseableImage
import com.google.android.flexbox.FlexboxLayout
import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MagicCallActivity
import com.nextcloud.talk.adapters.messages.LocationMessageViewHolder
import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder
import com.nextcloud.talk.adapters.messages.MagicIncomingTextMessageViewHolder
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.MagicUnreadNoticeMessageViewHolder
import com.nextcloud.talk.adapters.messages.OutcomingLocationMessageViewHolder
import com.nextcloud.talk.adapters.messages.TalkMessagesListAdapter
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
@ -437,10 +438,10 @@ class ChatController(args: Bundle) :
messageHolders.registerContentType(
CONTENT_TYPE_LOCATION,
LocationMessageViewHolder::class.java,
R.layout.item_custom_location_message,
LocationMessageViewHolder::class.java,
R.layout.item_custom_location_message,
IncomingLocationMessageViewHolder::class.java,
R.layout.item_custom_incoming_location_message,
OutcomingLocationMessageViewHolder::class.java,
R.layout.item_custom_outcoming_location_message,
this
)

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ @author Marcel Hibbe
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.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/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="2dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="2dp">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@id/messageUserAvatar"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentTop="true"
android:layout_marginEnd="8dp"
app:roundAsCircle="true" />
<com.google.android.flexbox.FlexboxLayout
android:id="@id/bubble"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/message_incoming_bubble_margin_right"
android:layout_toEndOf="@id/messageUserAvatar"
android:orientation="vertical"
app:alignContent="stretch"
app:alignItems="stretch"
app:flexWrap="wrap"
app:justifyContent="flex_end">
<include layout="@layout/item_message_quote" android:visibility="gone"/>
<WebView
android:id="@+id/webview"
android:layout_width="400dp"
android:layout_height="200dp"
/>
<androidx.emoji.widget.EmojiTextView
android:id="@+id/messageAuthor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:textColor="@color/textColorMaxContrast"
android:textSize="12sp" />
<androidx.emoji.widget.EmojiTextView
android:id="@id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingMultiplier="1.2"
android:textIsSelectable="true"
app:layout_alignSelf="flex_start"
app:layout_flexGrow="1"
app:layout_wrapBefore="true" />
<TextView
android:id="@id/messageTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/messageText"
android:layout_marginStart="8dp"
app:layout_alignSelf="center" />
</com.google.android.flexbox.FlexboxLayout>
</RelativeLayout>

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ @author Marcel Hibbe
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.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/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="200dp"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="@+id/locationText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/warm_grey_four"
android:textSize="12sp"
tools:text="17:30"
android:layout_marginStart="8dp"
app:layout_alignSelf="center"
app:layout_flexGrow="1"
app:layout_wrapBefore="false"/>
</RelativeLayout>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ @author Andy Scherzinger
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~
~ 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/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="2dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="2dp">
<com.google.android.flexbox.FlexboxLayout
android:id="@id/bubble"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_marginStart="@dimen/message_outcoming_bubble_margin_left"
app:alignContent="stretch"
app:alignItems="stretch"
app:flexWrap="wrap"
app:justifyContent="flex_end">
<include layout="@layout/item_message_quote" android:visibility="gone"/>
<WebView
android:id="@+id/webview"
android:layout_width="400dp"
android:layout_height="200dp"
/>
<androidx.emoji.widget.EmojiTextView
android:id="@id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignWithParentIfMissing="true"
android:lineSpacingMultiplier="1.2"
android:textColorHighlight="@color/nc_grey"
android:textIsSelectable="true"
tools:text="Talk to ayou later!" />
<TextView
android:id="@id/messageTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/messageText"
android:layout_marginStart="8dp"
app:layout_alignSelf="center"
tools:text="10:35" />
<ImageView
android:id="@+id/checkMark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/messageTime"
android:layout_marginStart="8dp"
app:layout_alignSelf="center"
android:contentDescription="@null" />
</com.google.android.flexbox.FlexboxLayout>
</RelativeLayout>