Display progress in the timeline when uploading file

This commit is contained in:
Benoit Marty 2019-09-25 14:39:33 +02:00
parent f077cc8467
commit 17cba1a432
7 changed files with 37 additions and 12 deletions

View File

@ -24,6 +24,8 @@ import java.io.File
// Implementation should return true in case of success // Implementation should return true in case of success
typealias ActionOnFile = (file: File) -> Boolean typealias ActionOnFile = (file: File) -> Boolean
internal fun String?.isLocalFile() = this != null && File(this).exists()
/* ========================================================================================== /* ==========================================================================================
* Delete * Delete
* ========================================================================================== */ * ========================================================================================== */

View File

@ -42,6 +42,7 @@ import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.DebouncedClickListener import im.vector.riotx.core.utils.DebouncedClickListener
import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.core.utils.containsOnlyEmojis import im.vector.riotx.core.utils.containsOnlyEmojis
import im.vector.riotx.core.utils.isLocalFile
import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
@ -117,6 +118,8 @@ class MessageItemFactory @Inject constructor(
.avatarRenderer(avatarRenderer) .avatarRenderer(avatarRenderer)
.colorProvider(colorProvider) .colorProvider(colorProvider)
.dimensionConverter(dimensionConverter) .dimensionConverter(dimensionConverter)
.izLocalFile(messageContent.getFileUrl().isLocalFile())
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
.informationData(informationData) .informationData(informationData)
.highlighted(highlight) .highlighted(highlight)
.avatarCallback(callback) .avatarCallback(callback)
@ -147,6 +150,8 @@ class MessageItemFactory @Inject constructor(
.avatarRenderer(avatarRenderer) .avatarRenderer(avatarRenderer)
.colorProvider(colorProvider) .colorProvider(colorProvider)
.dimensionConverter(dimensionConverter) .dimensionConverter(dimensionConverter)
.izLocalFile(messageContent.getFileUrl().isLocalFile())
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
.informationData(informationData) .informationData(informationData)
.highlighted(highlight) .highlighted(highlight)
.avatarCallback(callback) .avatarCallback(callback)

View File

@ -27,7 +27,6 @@ import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.resources.ColorProvider import im.vector.riotx.core.resources.ColorProvider
import im.vector.riotx.features.media.ImageContentRenderer
import im.vector.riotx.features.ui.getMessageTextColor import im.vector.riotx.features.ui.getMessageTextColor
import javax.inject.Inject import javax.inject.Inject
@ -37,12 +36,12 @@ class ContentUploadStateTrackerBinder @Inject constructor(private val activeSess
private val updateListeners = mutableMapOf<String, ContentUploadStateTracker.UpdateListener>() private val updateListeners = mutableMapOf<String, ContentUploadStateTracker.UpdateListener>()
fun bind(eventId: String, fun bind(eventId: String,
mediaData: ImageContentRenderer.Data, isLocalFile: Boolean,
progressLayout: ViewGroup) { progressLayout: ViewGroup) {
activeSessionHolder.getActiveSession().also { session -> activeSessionHolder.getActiveSession().also { session ->
val uploadStateTracker = session.contentUploadProgressTracker() val uploadStateTracker = session.contentUploadProgressTracker()
val updateListener = ContentMediaProgressUpdater(progressLayout, mediaData, colorProvider) val updateListener = ContentMediaProgressUpdater(progressLayout, isLocalFile, colorProvider)
updateListeners[eventId] = updateListener updateListeners[eventId] = updateListener
uploadStateTracker.track(eventId, updateListener) uploadStateTracker.track(eventId, updateListener)
} }
@ -60,7 +59,7 @@ class ContentUploadStateTrackerBinder @Inject constructor(private val activeSess
} }
private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup, private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
private val mediaData: ImageContentRenderer.Data, private val isLocalFile: Boolean,
private val colorProvider: ColorProvider) : ContentUploadStateTracker.UpdateListener { private val colorProvider: ColorProvider) : ContentUploadStateTracker.UpdateListener {
override fun onUpdate(state: ContentUploadStateTracker.State) { override fun onUpdate(state: ContentUploadStateTracker.State) {
@ -76,7 +75,7 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
} }
private fun handleIdle(state: ContentUploadStateTracker.State.Idle) { private fun handleIdle(state: ContentUploadStateTracker.State.Idle) {
if (mediaData.isLocalFile()) { if (isLocalFile) {
progressLayout.isVisible = true progressLayout.isVisible = true
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar) val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView) val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)

View File

@ -22,9 +22,11 @@ import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
@EpoxyModelClass(layout = R.layout.item_timeline_event_base) @EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() { abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {
@ -36,19 +38,35 @@ abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {
var iconRes: Int = 0 var iconRes: Int = 0
@EpoxyAttribute @EpoxyAttribute
var clickListener: View.OnClickListener? = null var clickListener: View.OnClickListener? = null
@EpoxyAttribute
var izLocalFile = false
@EpoxyAttribute
lateinit var contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
renderSendState(holder.fileLayout, holder.filenameView) renderSendState(holder.fileLayout, holder.filenameView)
if (!informationData.sendState.hasFailed()) {
contentUploadStateTrackerBinder.bind(informationData.eventId, izLocalFile, holder.progressLayout)
} else {
holder.progressLayout.isVisible = false
}
holder.filenameView.text = filename holder.filenameView.text = filename
holder.fileImageView.setImageResource(iconRes) holder.fileImageView.setImageResource(iconRes)
holder.filenameView.setOnClickListener(clickListener) holder.filenameView.setOnClickListener(clickListener)
holder.filenameView.paintFlags = (holder.filenameView.paintFlags or Paint.UNDERLINE_TEXT_FLAG) holder.filenameView.paintFlags = (holder.filenameView.paintFlags or Paint.UNDERLINE_TEXT_FLAG)
} }
override fun unbind(holder: Holder) {
super.unbind(holder)
contentUploadStateTrackerBinder.unbind(informationData.eventId)
}
override fun getViewType() = STUB_ID override fun getViewType() = STUB_ID
class Holder : AbsMessageItem.Holder(STUB_ID) { class Holder : AbsMessageItem.Holder(STUB_ID) {
val progressLayout by bind<ViewGroup>(R.id.messageFileUploadProgressLayout)
val fileLayout by bind<ViewGroup>(R.id.messageFileLayout) val fileLayout by bind<ViewGroup>(R.id.messageFileLayout)
val fileImageView by bind<ImageView>(R.id.messageFileImageView) val fileImageView by bind<ImageView>(R.id.messageFileImageView)
val filenameView by bind<TextView>(R.id.messageFilenameView) val filenameView by bind<TextView>(R.id.messageFilenameView)

View File

@ -20,6 +20,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R import im.vector.riotx.R
@ -44,11 +45,13 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
super.bind(holder) super.bind(holder)
imageContentRenderer.render(mediaData, ImageContentRenderer.Mode.THUMBNAIL, holder.imageView) imageContentRenderer.render(mediaData, ImageContentRenderer.Mode.THUMBNAIL, holder.imageView)
if (!informationData.sendState.hasFailed()) { if (!informationData.sendState.hasFailed()) {
contentUploadStateTrackerBinder.bind(informationData.eventId, mediaData, holder.progressLayout) contentUploadStateTrackerBinder.bind(informationData.eventId, mediaData.isLocalFile(), holder.progressLayout)
} else {
holder.progressLayout.isVisible = false
} }
holder.imageView.setOnClickListener(clickListener) holder.imageView.setOnClickListener(clickListener)
holder.imageView.setOnLongClickListener(longClickListener) holder.imageView.setOnLongClickListener(longClickListener)
ViewCompat.setTransitionName(holder.imageView,"imagePreview_${id()}") ViewCompat.setTransitionName(holder.imageView, "imagePreview_${id()}")
holder.mediaContentView.setOnClickListener(cellClickListener) holder.mediaContentView.setOnClickListener(cellClickListener)
holder.mediaContentView.setOnLongClickListener(longClickListener) holder.mediaContentView.setOnLongClickListener(longClickListener)
// The sending state color will be apply to the progress text // The sending state color will be apply to the progress text

View File

@ -33,9 +33,9 @@ import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.glide.GlideApp import im.vector.riotx.core.glide.GlideApp
import im.vector.riotx.core.glide.GlideRequest import im.vector.riotx.core.glide.GlideRequest
import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.core.utils.isLocalFile
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import timber.log.Timber import timber.log.Timber
import java.io.File
import javax.inject.Inject import javax.inject.Inject
class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder, class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
@ -54,9 +54,7 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
val rotation: Int? = null val rotation: Int? = null
) : Parcelable { ) : Parcelable {
fun isLocalFile(): Boolean { fun isLocalFile() = url.isLocalFile()
return url != null && File(url).exists()
}
} }
enum class Mode { enum class Mode {

View File

@ -51,7 +51,7 @@
</LinearLayout> </LinearLayout>
<include <include
android:id="@+id/messageMediaUploadProgressLayout" android:id="@+id/messageFileUploadProgressLayout"
layout="@layout/media_upload_download_progress_layout" layout="@layout/media_upload_download_progress_layout"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="46dp" android:layout_height="46dp"