mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Merge develop
This commit is contained in:
commit
220e6224e7
@ -17,9 +17,6 @@
|
||||
package im.vector.matrix.android.api.permalinks
|
||||
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.widget.TextView
|
||||
import im.vector.matrix.android.api.MatrixPatterns
|
||||
|
||||
/**
|
||||
@ -56,37 +53,5 @@ object MatrixLinkify {
|
||||
}
|
||||
return hasMatch
|
||||
}
|
||||
|
||||
fun addLinks(textView: TextView, callback: MatrixPermalinkSpan.Callback?): Boolean {
|
||||
val text = textView.text
|
||||
if (text is Spannable) {
|
||||
if (addLinks(text, callback)) {
|
||||
addLinkMovementMethod(textView)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
} else {
|
||||
val spannableString = SpannableString.valueOf(text)
|
||||
if (addLinks(spannableString, callback)) {
|
||||
addLinkMovementMethod(textView)
|
||||
textView.text = spannableString
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add linkMovementMethod on textview if not already set
|
||||
* @param textView the textView on which the movementMethod is set
|
||||
*/
|
||||
fun addLinkMovementMethod(textView: TextView) {
|
||||
val movementMethod = textView.movementMethod
|
||||
if (movementMethod == null || movementMethod !is LinkMovementMethod) {
|
||||
if (textView.linksClickable) {
|
||||
textView.movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -186,6 +186,7 @@ dependencies {
|
||||
implementation 'me.gujun.android:span:1.7'
|
||||
implementation "ru.noties.markwon:core:$markwon_version"
|
||||
implementation "ru.noties.markwon:html:$markwon_version"
|
||||
implementation 'me.saket:better-link-movement-method:2.2.0'
|
||||
|
||||
implementation 'com.otaliastudios:autocomplete:1.1.0'
|
||||
|
||||
|
@ -23,7 +23,6 @@ import android.text.style.ClickableSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.RelativeSizeSpan
|
||||
import android.view.View
|
||||
import androidx.annotation.ColorRes
|
||||
import im.vector.matrix.android.api.permalinks.MatrixLinkify
|
||||
import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
@ -41,7 +40,6 @@ import im.vector.riotredesign.core.linkify.VectorLinkify
|
||||
import im.vector.riotredesign.core.resources.ColorProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.core.utils.DebouncedClickListener
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
import im.vector.riotredesign.features.home.getColorFromUserId
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
@ -273,7 +271,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
callback: TimelineEventController.Callback?): MessageTextItem? {
|
||||
|
||||
val bodyToUse = messageContent.formattedBody?.let {
|
||||
htmlRenderer.render(it)
|
||||
htmlRenderer.render(it.trim())
|
||||
} ?: messageContent.body
|
||||
|
||||
val linkifiedBody = linkifyBody(bodyToUse, callback)
|
||||
@ -292,10 +290,6 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
.reactionPillCallback(callback)
|
||||
.emojiTypeFace(emojiCompatFontProvider.typeface)
|
||||
//click on the text
|
||||
.clickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
callback?.onEventCellClicked(informationData, messageContent, view)
|
||||
}))
|
||||
.cellClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
callback?.onEventCellClicked(informationData, messageContent, view)
|
||||
|
@ -86,6 +86,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e,"failed to create message item")
|
||||
defaultItemFactory.create(event, e)
|
||||
}
|
||||
return (computedModel ?: EmptyItem_())
|
||||
|
@ -43,6 +43,8 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||
ContentUploadStateTrackerBinder.bind(informationData.eventId, mediaData, holder.progressLayout)
|
||||
holder.imageView.setOnClickListener(clickListener)
|
||||
holder.imageView.setOnLongClickListener(longClickListener)
|
||||
holder.mediaContentView.setOnClickListener(cellClickListener)
|
||||
holder.mediaContentView.setOnLongClickListener(longClickListener)
|
||||
holder.imageView.renderSendState()
|
||||
holder.playContentView.visibility = if (playable) View.VISIBLE else View.GONE
|
||||
}
|
||||
@ -62,6 +64,8 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||
val imageView by bind<ImageView>(R.id.messageThumbnailView)
|
||||
val playContentView by bind<ImageView>(R.id.messageMediaPlayView)
|
||||
|
||||
val mediaContentView by bind<ViewGroup>(R.id.messageContentMedia)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,22 +16,20 @@
|
||||
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.item
|
||||
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.text.PrecomputedTextCompat
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.widget.TextViewCompat
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.matrix.android.api.permalinks.MatrixLinkify
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.utils.DimensionUtils
|
||||
import im.vector.riotredesign.core.utils.containsOnlyEmojis
|
||||
import im.vector.riotredesign.features.html.PillImageSpan
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import me.saket.bettermovementmethod.BetterLinkMovementMethod
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_base)
|
||||
abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
|
||||
@ -40,12 +38,22 @@ abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
|
||||
var message: CharSequence? = null
|
||||
@EpoxyAttribute
|
||||
override lateinit var informationData: MessageInformationData
|
||||
@EpoxyAttribute
|
||||
var clickListener: View.OnClickListener? = null
|
||||
|
||||
val mvmtMethod = BetterLinkMovementMethod.newInstance().also {
|
||||
it.setOnLinkClickListener { textView, url ->
|
||||
//Return false to let android manage the click on the link
|
||||
false
|
||||
}
|
||||
it.setOnLinkLongClickListener { textView, url ->
|
||||
//Long clicks are handled by parent, return true to block android to do something with url
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
MatrixLinkify.addLinkMovementMethod(holder.messageView)
|
||||
holder.messageView.movementMethod = mvmtMethod
|
||||
|
||||
|
||||
val msg = message ?: ""
|
||||
if (msg.length <= 4 && containsOnlyEmojis(msg.toString())) {
|
||||
@ -54,13 +62,13 @@ abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
|
||||
holder.messageView.textSize = 14F
|
||||
}
|
||||
|
||||
val textFuture = PrecomputedTextCompat.getTextFuture(msg,
|
||||
val textFuture = PrecomputedTextCompat.getTextFuture(message ?: "",
|
||||
TextViewCompat.getTextMetricsParams(holder.messageView),
|
||||
null)
|
||||
|
||||
holder.messageView.setTextFuture(textFuture)
|
||||
holder.messageView.renderSendState()
|
||||
holder.messageView.setOnClickListener(clickListener)
|
||||
holder.messageView.setOnClickListener(cellClickListener)
|
||||
holder.messageView.setOnLongClickListener(longClickListener)
|
||||
findPillsAndProcess { it.bind(holder.messageView) }
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
package im.vector.riotredesign.features.html
|
||||
|
||||
import android.content.Context
|
||||
import android.text.style.ClickableSpan
|
||||
import android.text.style.URLSpan
|
||||
import im.vector.matrix.android.api.permalinks.PermalinkData
|
||||
import im.vector.matrix.android.api.permalinks.PermalinkParser
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
@ -82,6 +84,9 @@ private class MatrixPlugin private constructor(private val glideRequests: GlideR
|
||||
.setHandler(
|
||||
"blockquote",
|
||||
BlockquoteHandler())
|
||||
.setHandler(
|
||||
"font",
|
||||
FontTagHandler())
|
||||
.setHandler(
|
||||
"sub",
|
||||
SubScriptHandler())
|
||||
@ -156,6 +161,13 @@ private class MxLinkHandler(private val glideRequests: GlideRequests,
|
||||
tag.start(),
|
||||
tag.end()
|
||||
)
|
||||
//also add clickable span
|
||||
SpannableBuilder.setSpans(
|
||||
visitor.builder(),
|
||||
URLSpan(link),
|
||||
tag.start(),
|
||||
tag.end()
|
||||
)
|
||||
}
|
||||
else -> linkHandler.handle(visitor, renderer, tag)
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.riotredesign.features.html
|
||||
|
||||
import android.graphics.Color
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import ru.noties.markwon.MarkwonConfiguration
|
||||
import ru.noties.markwon.RenderProps
|
||||
import ru.noties.markwon.html.HtmlTag
|
||||
import ru.noties.markwon.html.tag.SimpleTagHandler
|
||||
|
||||
/**
|
||||
* custom to matrix for IRC-style font coloring
|
||||
*/
|
||||
class FontTagHandler : SimpleTagHandler() {
|
||||
override fun getSpans(configuration: MarkwonConfiguration, renderProps: RenderProps, tag: HtmlTag): Any? {
|
||||
val colorString = tag.attributes()["color"]?.let { parseColor(it) } ?: Color.BLACK
|
||||
return ForegroundColorSpan(colorString)
|
||||
}
|
||||
|
||||
private fun parseColor(color_name: String): Int {
|
||||
try {
|
||||
return Color.parseColor(color_name)
|
||||
} catch (e: Exception) {
|
||||
//try other w3c colors?
|
||||
return when (color_name) {
|
||||
"white" -> Color.WHITE
|
||||
"yellow" -> Color.YELLOW
|
||||
"fuchsia" -> Color.parseColor("#FF00FF")
|
||||
"red" -> Color.RED
|
||||
"silver" -> Color.parseColor("#C0C0C0")
|
||||
"gray" -> Color.GRAY
|
||||
"olive" -> Color.parseColor("#808000")
|
||||
"purple" -> Color.parseColor("#800080")
|
||||
"maroon" -> Color.parseColor("#800000")
|
||||
"aqua" -> Color.parseColor("#00FFFF")
|
||||
"lime" -> Color.parseColor("#00FF00")
|
||||
"teal" -> Color.parseColor("#008080")
|
||||
"green" -> Color.GREEN
|
||||
"blue" -> Color.BLUE
|
||||
"orange" -> Color.parseColor("#FFA500")
|
||||
"navy" -> Color.parseColor("#000080")
|
||||
else -> Color.BLACK
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -73,6 +73,7 @@
|
||||
<ViewStub
|
||||
android:id="@+id/messageContentMediaStub"
|
||||
style="@style/TimelineContentStubLayoutParams"
|
||||
android:inflatedId="@+id/messageContentMedia"
|
||||
android:layout="@layout/item_timeline_event_media_message_stub"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user