forked from GitHub-Mirror/riotX-android
Html : continue work on Pills. Still need to find how to handle avatar drawable.
This commit is contained in:
parent
41b06bca60
commit
63bf4355b9
@ -16,16 +16,21 @@
|
|||||||
|
|
||||||
package im.vector.riotredesign.features.home
|
package im.vector.riotredesign.features.home
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.amulyakhare.textdrawable.TextDrawable
|
import com.amulyakhare.textdrawable.TextDrawable
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
|
import com.bumptech.glide.request.target.SimpleTarget
|
||||||
|
import com.bumptech.glide.request.transition.Transition
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.matrix.android.api.MatrixPatterns
|
import im.vector.matrix.android.api.MatrixPatterns
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.glide.GlideApp
|
import im.vector.riotredesign.core.glide.GlideApp
|
||||||
|
import im.vector.riotredesign.core.glide.GlideRequest
|
||||||
|
|
||||||
object AvatarRenderer {
|
object AvatarRenderer {
|
||||||
|
|
||||||
@ -41,19 +46,52 @@ object AvatarRenderer {
|
|||||||
if (name.isNullOrEmpty()) {
|
if (name.isNullOrEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
buildGlideRequest(imageView.context, name, avatarUrl).into(imageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun load(context: Context, avatarUrl: String?, name: String?, callback: Callback) {
|
||||||
|
if (name.isNullOrEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buildGlideRequest(context, name, avatarUrl).into(CallbackTarget(callback))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildGlideRequest(context: Context, name: String, avatarUrl: String?): GlideRequest<Drawable> {
|
||||||
val resolvedUrl = Matrix.getInstance().currentSession.contentUrlResolver().resolveFullSize(avatarUrl)
|
val resolvedUrl = Matrix.getInstance().currentSession.contentUrlResolver().resolveFullSize(avatarUrl)
|
||||||
val avatarColor = ContextCompat.getColor(imageView.context, R.color.pale_teal)
|
val avatarColor = ContextCompat.getColor(context, R.color.pale_teal)
|
||||||
val isNameUserId = MatrixPatterns.isUserId(name)
|
val isNameUserId = MatrixPatterns.isUserId(name)
|
||||||
val firstLetterIndex = if (isNameUserId) 1 else 0
|
val firstLetterIndex = if (isNameUserId) 1 else 0
|
||||||
val firstLetter = name[firstLetterIndex].toString().toUpperCase()
|
val firstLetter = name[firstLetterIndex].toString().toUpperCase()
|
||||||
val fallbackDrawable = TextDrawable.builder().buildRound(firstLetter, avatarColor)
|
val fallbackDrawable = TextDrawable.builder().buildRound(firstLetter, avatarColor)
|
||||||
|
return GlideApp
|
||||||
GlideApp
|
.with(context)
|
||||||
.with(imageView)
|
|
||||||
.load(resolvedUrl)
|
.load(resolvedUrl)
|
||||||
.placeholder(fallbackDrawable)
|
.placeholder(fallbackDrawable)
|
||||||
.apply(RequestOptions.circleCropTransform())
|
.apply(RequestOptions.circleCropTransform())
|
||||||
.into(imageView)
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onDrawableUpdated(drawable: Drawable?)
|
||||||
|
fun onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CallbackTarget(private val callback: Callback) : SimpleTarget<Drawable>() {
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
callback.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||||
|
callback.onDrawableUpdated(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadStarted(placeholder: Drawable?) {
|
||||||
|
callback.onDrawableUpdated(placeholder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
callback.onDrawableUpdated(errorDrawable)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,25 +16,39 @@
|
|||||||
|
|
||||||
package im.vector.riotredesign.features.home
|
package im.vector.riotredesign.features.home
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.*
|
import im.vector.riotredesign.features.home.room.detail.timeline.CallItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.DefaultItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.MessageItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.RoomHistoryVisibilityItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.RoomMemberItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.RoomNameItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.RoomTopicItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineDateFormatter
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineItemFactory
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
import im.vector.riotredesign.features.home.room.list.RoomSummaryComparator
|
import im.vector.riotredesign.features.home.room.list.RoomSummaryComparator
|
||||||
import im.vector.riotredesign.features.home.room.list.RoomSummaryController
|
import im.vector.riotredesign.features.home.room.list.RoomSummaryController
|
||||||
import im.vector.riotredesign.features.markdown.EventHtmlRenderer
|
import im.vector.riotredesign.features.html.EventHtmlRenderer
|
||||||
import org.koin.dsl.module.module
|
import org.koin.dsl.module.module
|
||||||
|
|
||||||
class HomeModule(homeActivity: HomeActivity) {
|
class HomeModule(homeActivity: HomeActivity) {
|
||||||
|
|
||||||
val definition = module(override = true) {
|
val definition = module(override = true) {
|
||||||
|
|
||||||
|
single {
|
||||||
|
Matrix.getInstance().currentSession
|
||||||
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
TimelineDateFormatter(get())
|
TimelineDateFormatter(get())
|
||||||
}
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
EventHtmlRenderer(homeActivity)
|
EventHtmlRenderer(homeActivity, get())
|
||||||
}
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
|
@ -29,7 +29,7 @@ import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
|||||||
import im.vector.riotredesign.core.extensions.localDateTime
|
import im.vector.riotredesign.core.extensions.localDateTime
|
||||||
import im.vector.riotredesign.core.resources.ColorProvider
|
import im.vector.riotredesign.core.resources.ColorProvider
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
import im.vector.riotredesign.features.markdown.EventHtmlRenderer
|
import im.vector.riotredesign.features.html.EventHtmlRenderer
|
||||||
import im.vector.riotredesign.features.media.MediaContentRenderer
|
import im.vector.riotredesign.features.media.MediaContentRenderer
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
|
|
||||||
|
@ -16,14 +16,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotredesign.features.markdown
|
package im.vector.riotredesign.features.html
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.style.ImageSpan
|
import android.text.style.ImageSpan
|
||||||
import com.google.android.material.chip.ChipDrawable
|
|
||||||
import im.vector.matrix.android.api.permalinks.PermalinkData
|
import im.vector.matrix.android.api.permalinks.PermalinkData
|
||||||
import im.vector.matrix.android.api.permalinks.PermalinkParser
|
import im.vector.matrix.android.api.permalinks.PermalinkParser
|
||||||
import im.vector.riotredesign.R
|
import im.vector.matrix.android.api.session.Session
|
||||||
import org.commonmark.node.BlockQuote
|
import org.commonmark.node.BlockQuote
|
||||||
import org.commonmark.node.HtmlBlock
|
import org.commonmark.node.HtmlBlock
|
||||||
import org.commonmark.node.HtmlInline
|
import org.commonmark.node.HtmlInline
|
||||||
@ -50,10 +49,11 @@ import ru.noties.markwon.html.tag.SuperScriptHandler
|
|||||||
import ru.noties.markwon.html.tag.UnderlineHandler
|
import ru.noties.markwon.html.tag.UnderlineHandler
|
||||||
import java.util.Arrays.asList
|
import java.util.Arrays.asList
|
||||||
|
|
||||||
class EventHtmlRenderer(private val context: Context) {
|
class EventHtmlRenderer(private val context: Context,
|
||||||
|
private val session: Session) {
|
||||||
|
|
||||||
private val markwon = Markwon.builder(context)
|
private val markwon = Markwon.builder(context)
|
||||||
.usePlugin(MatrixPlugin.create(context))
|
.usePlugin(MatrixPlugin.create(context, session))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun render(text: String): CharSequence {
|
fun render(text: String): CharSequence {
|
||||||
@ -62,7 +62,8 @@ class EventHtmlRenderer(private val context: Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MatrixPlugin private constructor(private val context: Context) : AbstractMarkwonPlugin() {
|
private class MatrixPlugin private constructor(private val context: Context,
|
||||||
|
private val session: Session) : AbstractMarkwonPlugin() {
|
||||||
|
|
||||||
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
||||||
builder.htmlParser(MarkwonHtmlParserImpl.create())
|
builder.htmlParser(MarkwonHtmlParserImpl.create())
|
||||||
@ -75,7 +76,7 @@ private class MatrixPlugin private constructor(private val context: Context) : A
|
|||||||
ImageHandler.create())
|
ImageHandler.create())
|
||||||
.addHandler(
|
.addHandler(
|
||||||
"a",
|
"a",
|
||||||
MxLinkHandler(context))
|
MxLinkHandler(context, session))
|
||||||
.addHandler(
|
.addHandler(
|
||||||
"blockquote",
|
"blockquote",
|
||||||
BlockquoteHandler())
|
BlockquoteHandler())
|
||||||
@ -127,13 +128,13 @@ private class MatrixPlugin private constructor(private val context: Context) : A
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun create(context: Context): MatrixPlugin {
|
fun create(context: Context, session: Session): MatrixPlugin {
|
||||||
return MatrixPlugin(context)
|
return MatrixPlugin(context, session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MxLinkHandler(private val context: Context) : TagHandler() {
|
private class MxLinkHandler(private val context: Context, private val session: Session) : TagHandler() {
|
||||||
|
|
||||||
private val linkHandler = LinkHandler()
|
private val linkHandler = LinkHandler()
|
||||||
|
|
||||||
@ -143,12 +144,9 @@ private class MxLinkHandler(private val context: Context) : TagHandler() {
|
|||||||
val permalinkData = PermalinkParser.parse(link)
|
val permalinkData = PermalinkParser.parse(link)
|
||||||
when (permalinkData) {
|
when (permalinkData) {
|
||||||
is PermalinkData.UserLink -> {
|
is PermalinkData.UserLink -> {
|
||||||
val chipDrawable = ChipDrawable.createFromResource(context, R.xml.pill_view)
|
val user = session.getUser(permalinkData.userId) ?: return
|
||||||
chipDrawable.setText(permalinkData.userId)
|
val drawable = PillDrawableFactory.create(context, permalinkData.userId, user)
|
||||||
chipDrawable.textEndPadding = 8f
|
val span = ImageSpan(drawable)
|
||||||
chipDrawable.textStartPadding = 8f
|
|
||||||
chipDrawable.setBounds(0, 0, chipDrawable.intrinsicWidth, (chipDrawable.intrinsicHeight / 1.5f).toInt())
|
|
||||||
val span = ImageSpan(chipDrawable)
|
|
||||||
SpannableBuilder.setSpans(
|
SpannableBuilder.setSpans(
|
||||||
visitor.builder(),
|
visitor.builder(),
|
||||||
span,
|
span,
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import com.google.android.material.chip.ChipDrawable
|
||||||
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
object PillDrawableFactory {
|
||||||
|
|
||||||
|
fun create(context: Context, userId: String, user: User?): Drawable {
|
||||||
|
val chipDrawable = ChipDrawable.createFromResource(context, R.xml.pill_view).apply {
|
||||||
|
setText(user?.displayName ?: userId)
|
||||||
|
textEndPadding = 8f
|
||||||
|
textStartPadding = 8f
|
||||||
|
setBounds(0, 0, intrinsicWidth, (intrinsicHeight / 1.5f).toInt())
|
||||||
|
}
|
||||||
|
val avatarRendererCallback = AvatarRendererChipCallback(chipDrawable)
|
||||||
|
// TODO: need to work on getting drawable async
|
||||||
|
//AvatarRenderer.load(context, user?.avatarUrl, user?.displayName, avatarRendererCallback)
|
||||||
|
return chipDrawable
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AvatarRendererChipCallback(chipDrawable: ChipDrawable) : AvatarRenderer.Callback {
|
||||||
|
|
||||||
|
private val weakChipDrawable = WeakReference<ChipDrawable>(chipDrawable)
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
weakChipDrawable.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDrawableUpdated(drawable: Drawable?) {
|
||||||
|
weakChipDrawable.get()?.apply {
|
||||||
|
chipIcon = drawable
|
||||||
|
setBounds(0, 0, intrinsicWidth, (intrinsicHeight / 1.5f).toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user