mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 21:48:50 +03:00
Display progress in the timeline when uploading file
This commit is contained in:
parent
f077cc8467
commit
17cba1a432
7 changed files with 37 additions and 12 deletions
|
@ -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
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,7 +45,9 @@ 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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue