mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-21 05:38:49 +03:00
Refactoring
Remove glide dependency + protect against cell reuse bugs
This commit is contained in:
parent
bf2d937ad6
commit
aa3e68f3fd
9 changed files with 279 additions and 189 deletions
attachment-viewer
build.gradle
src/main/java/im/vector/riotx/attachmentviewer
vector/src/main/java/im/vector/riotx/features/media
|
@ -58,9 +58,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// implementation 'com.github.MikeOrtiz:TouchImageView:3.0.2'
|
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
|
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
|
||||||
implementation "com.github.bumptech.glide:glide:4.10.0"
|
|
||||||
|
|
||||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||||
|
|
|
@ -16,16 +16,9 @@
|
||||||
|
|
||||||
package im.vector.riotx.attachmentviewer
|
package im.vector.riotx.attachmentviewer
|
||||||
|
|
||||||
import android.graphics.drawable.Animatable
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import com.bumptech.glide.request.target.CustomViewTarget
|
|
||||||
import com.bumptech.glide.request.transition.Transition
|
|
||||||
|
|
||||||
class AnimatedImageViewHolder constructor(itemView: View) :
|
class AnimatedImageViewHolder constructor(itemView: View) :
|
||||||
BaseViewHolder(itemView) {
|
BaseViewHolder(itemView) {
|
||||||
|
@ -33,34 +26,5 @@ class AnimatedImageViewHolder constructor(itemView: View) :
|
||||||
val touchImageView: ImageView = itemView.findViewById(R.id.imageView)
|
val touchImageView: ImageView = itemView.findViewById(R.id.imageView)
|
||||||
val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress)
|
val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress)
|
||||||
|
|
||||||
val customTargetView = object : CustomViewTarget<ImageView, Drawable>(touchImageView) {
|
internal val target = DefaultImageLoaderTarget(this, this.touchImageView)
|
||||||
|
|
||||||
override fun onResourceLoading(placeholder: Drawable?) {
|
|
||||||
imageLoaderProgress.isVisible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
|
||||||
imageLoaderProgress.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResourceCleared(placeholder: Drawable?) {
|
|
||||||
touchImageView.setImageDrawable(placeholder)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
|
||||||
imageLoaderProgress.isVisible = false
|
|
||||||
// Glide mess up the view size :/
|
|
||||||
touchImageView.updateLayoutParams {
|
|
||||||
width = LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
height = LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
}
|
|
||||||
touchImageView.setImageDrawable(resource)
|
|
||||||
if (resource is Animatable) {
|
|
||||||
resource.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun bind(attachmentInfo: AttachmentInfo) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,15 +19,12 @@ package im.vector.riotx.attachmentviewer
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
||||||
sealed class AttachmentInfo {
|
sealed class AttachmentInfo(open val uid: String) {
|
||||||
data class Image(val url: String, val data: Any?) : AttachmentInfo()
|
data class Image(override val uid: String, val url: String, val data: Any?) : AttachmentInfo(uid)
|
||||||
data class AnimatedImage(val url: String, val data: Any?) : AttachmentInfo()
|
data class AnimatedImage(override val uid: String, val url: String, val data: Any?) : AttachmentInfo(uid)
|
||||||
data class Video(val url: String, val data: Any, val thumbnail: Image?) : AttachmentInfo()
|
data class Video(override val uid: String, val url: String, val data: Any, val thumbnail: Image?) : AttachmentInfo(uid)
|
||||||
data class Audio(val url: String, val data: Any) : AttachmentInfo()
|
data class Audio(override val uid: String, val url: String, val data: Any) : AttachmentInfo(uid)
|
||||||
data class File(val url: String, val data: Any) : AttachmentInfo()
|
data class File(override val uid: String, val url: String, val data: Any) : AttachmentInfo(uid)
|
||||||
|
|
||||||
fun bind() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AttachmentSourceProvider {
|
interface AttachmentSourceProvider {
|
||||||
|
@ -36,11 +33,13 @@ interface AttachmentSourceProvider {
|
||||||
|
|
||||||
fun getAttachmentInfoAt(position: Int): AttachmentInfo
|
fun getAttachmentInfoAt(position: Int): AttachmentInfo
|
||||||
|
|
||||||
fun loadImage(holder: ZoomableImageViewHolder, info: AttachmentInfo.Image)
|
fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.Image)
|
||||||
|
|
||||||
fun loadImage(holder: AnimatedImageViewHolder, info: AttachmentInfo.AnimatedImage)
|
fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.AnimatedImage)
|
||||||
|
|
||||||
fun loadVideo(holder: VideoViewHolder, info: AttachmentInfo.Video)
|
fun loadVideo(target: VideoLoaderTarget, info: AttachmentInfo.Video)
|
||||||
|
|
||||||
fun overlayViewAtPosition(context: Context, position: Int) : View?
|
fun overlayViewAtPosition(context: Context, position: Int): View?
|
||||||
|
|
||||||
|
fun clear(id: String)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,10 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
abstract class BaseViewHolder constructor(itemView: View) :
|
abstract class BaseViewHolder constructor(itemView: View) :
|
||||||
RecyclerView.ViewHolder(itemView) {
|
RecyclerView.ViewHolder(itemView) {
|
||||||
|
|
||||||
open fun bind(attachmentInfo: AttachmentInfo) {}
|
open fun onRecycled() {
|
||||||
open fun onRecycled() {}
|
boundResourceUid = null
|
||||||
|
}
|
||||||
|
|
||||||
open fun onAttached() {}
|
open fun onAttached() {}
|
||||||
open fun onDetached() {}
|
open fun onDetached() {}
|
||||||
open fun entersBackground() {}
|
open fun entersBackground() {}
|
||||||
|
@ -33,16 +35,17 @@ abstract class BaseViewHolder constructor(itemView: View) :
|
||||||
open fun onSelected(selected: Boolean) {}
|
open fun onSelected(selected: Boolean) {}
|
||||||
|
|
||||||
open fun handleCommand(commands: AttachmentCommands) {}
|
open fun handleCommand(commands: AttachmentCommands) {}
|
||||||
}
|
|
||||||
|
|
||||||
class AttachmentViewHolder constructor(itemView: View) :
|
var boundResourceUid: String? = null
|
||||||
BaseViewHolder(itemView) {
|
|
||||||
|
|
||||||
override fun bind(attachmentInfo: AttachmentInfo) {
|
open fun bind(attachmentInfo: AttachmentInfo) {
|
||||||
|
boundResourceUid = attachmentInfo.uid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// class AttachmentsAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {
|
class AttachmentViewHolder constructor(itemView: View) :
|
||||||
|
BaseViewHolder(itemView)
|
||||||
|
|
||||||
class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
|
class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
|
||||||
|
|
||||||
var attachmentSourceProvider: AttachmentSourceProvider? = null
|
var attachmentSourceProvider: AttachmentSourceProvider? = null
|
||||||
|
@ -65,21 +68,21 @@ class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
val itemView = inflater.inflate(viewType, parent, false)
|
val itemView = inflater.inflate(viewType, parent, false)
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
R.layout.item_image_attachment -> ZoomableImageViewHolder(itemView)
|
R.layout.item_image_attachment -> ZoomableImageViewHolder(itemView)
|
||||||
R.layout.item_animated_image_attachment -> AnimatedImageViewHolder(itemView)
|
R.layout.item_animated_image_attachment -> AnimatedImageViewHolder(itemView)
|
||||||
R.layout.item_video_attachment -> VideoViewHolder(itemView)
|
R.layout.item_video_attachment -> VideoViewHolder(itemView)
|
||||||
else -> AttachmentViewHolder(itemView)
|
else -> AttachmentViewHolder(itemView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
val info = attachmentSourceProvider!!.getAttachmentInfoAt(position)
|
val info = attachmentSourceProvider!!.getAttachmentInfoAt(position)
|
||||||
return when (info) {
|
return when (info) {
|
||||||
is AttachmentInfo.Image -> R.layout.item_image_attachment
|
is AttachmentInfo.Image -> R.layout.item_image_attachment
|
||||||
is AttachmentInfo.Video -> R.layout.item_video_attachment
|
is AttachmentInfo.Video -> R.layout.item_video_attachment
|
||||||
is AttachmentInfo.AnimatedImage -> R.layout.item_animated_image_attachment
|
is AttachmentInfo.AnimatedImage -> R.layout.item_animated_image_attachment
|
||||||
is AttachmentInfo.Audio -> TODO()
|
is AttachmentInfo.Audio -> TODO()
|
||||||
is AttachmentInfo.File -> TODO()
|
is AttachmentInfo.File -> TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,16 +94,17 @@ class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
|
||||||
attachmentSourceProvider?.getAttachmentInfoAt(position)?.let {
|
attachmentSourceProvider?.getAttachmentInfoAt(position)?.let {
|
||||||
holder.bind(it)
|
holder.bind(it)
|
||||||
when (it) {
|
when (it) {
|
||||||
is AttachmentInfo.Image -> {
|
is AttachmentInfo.Image -> {
|
||||||
attachmentSourceProvider?.loadImage(holder as ZoomableImageViewHolder, it)
|
attachmentSourceProvider?.loadImage((holder as ZoomableImageViewHolder).target, it)
|
||||||
}
|
}
|
||||||
is AttachmentInfo.AnimatedImage -> {
|
is AttachmentInfo.AnimatedImage -> {
|
||||||
attachmentSourceProvider?.loadImage(holder as AnimatedImageViewHolder, it)
|
attachmentSourceProvider?.loadImage((holder as AnimatedImageViewHolder).target, it)
|
||||||
}
|
}
|
||||||
is AttachmentInfo.Video -> {
|
is AttachmentInfo.Video -> {
|
||||||
attachmentSourceProvider?.loadVideo(holder as VideoViewHolder, it)
|
attachmentSourceProvider?.loadVideo((holder as VideoViewHolder).target, it)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
}
|
}
|
||||||
else -> {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,35 +138,4 @@ class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
|
||||||
val holder = recyclerView?.findViewHolderForAdapterPosition(position) as? BaseViewHolder
|
val holder = recyclerView?.findViewHolderForAdapterPosition(position) as? BaseViewHolder
|
||||||
holder?.entersForeground()
|
holder?.entersForeground()
|
||||||
}
|
}
|
||||||
// override fun getItemCount(): Int {
|
|
||||||
// return 8
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun createFragment(position: Int): Fragment {
|
|
||||||
// // Return a NEW fragment instance in createFragment(int)
|
|
||||||
// val fragment = DemoObjectFragment()
|
|
||||||
// fragment.arguments = Bundle().apply {
|
|
||||||
// // Our object is just an integer :-P
|
|
||||||
// putInt(ARG_OBJECT, position + 1)
|
|
||||||
// }
|
|
||||||
// return fragment
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private const val ARG_OBJECT = "object"
|
|
||||||
//
|
|
||||||
// // Instances of this class are fragments representing a single
|
|
||||||
// // object in our collection.
|
|
||||||
// class DemoObjectFragment : Fragment() {
|
|
||||||
//
|
|
||||||
// override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
|
||||||
// return inflater.inflate(R.layout.view_image_attachment, container, false)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
// arguments?.takeIf { it.containsKey(ARG_OBJECT) }?.apply {
|
|
||||||
// val textView: TextView = view.findViewById(R.id.testPage)
|
|
||||||
// textView.text = getInt(ARG_OBJECT).toString()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.riotx.attachmentviewer
|
||||||
|
|
||||||
|
import android.graphics.drawable.Animatable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
|
|
||||||
|
interface ImageLoaderTarget {
|
||||||
|
|
||||||
|
fun contextView(): ImageView
|
||||||
|
|
||||||
|
fun onResourceLoading(uid: String, placeholder: Drawable?)
|
||||||
|
|
||||||
|
fun onLoadFailed(uid: String, errorDrawable: Drawable?)
|
||||||
|
|
||||||
|
fun onResourceCleared(uid: String, placeholder: Drawable?)
|
||||||
|
|
||||||
|
fun onResourceReady(uid: String, resource: Drawable)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultImageLoaderTarget(val holder: AnimatedImageViewHolder, private val contextView: ImageView)
|
||||||
|
: ImageLoaderTarget {
|
||||||
|
override fun contextView(): ImageView {
|
||||||
|
return contextView
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceLoading(uid: String, placeholder: Drawable?) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.imageLoaderProgress.isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadFailed(uid: String, errorDrawable: Drawable?) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.imageLoaderProgress.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceCleared(uid: String, placeholder: Drawable?) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.touchImageView.setImageDrawable(placeholder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(uid: String, resource: Drawable) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.imageLoaderProgress.isVisible = false
|
||||||
|
// Glide mess up the view size :/
|
||||||
|
holder.touchImageView.updateLayoutParams {
|
||||||
|
width = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
|
height = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
|
}
|
||||||
|
holder.touchImageView.setImageDrawable(resource)
|
||||||
|
if (resource is Animatable) {
|
||||||
|
resource.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ZoomableImageTarget(val holder: ZoomableImageViewHolder, private val contextView: ImageView) : ImageLoaderTarget {
|
||||||
|
override fun contextView() = contextView
|
||||||
|
|
||||||
|
override fun onResourceLoading(uid: String, placeholder: Drawable?) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.imageLoaderProgress.isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadFailed(uid: String, errorDrawable: Drawable?) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.imageLoaderProgress.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceCleared(uid: String, placeholder: Drawable?) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.touchImageView.setImageDrawable(placeholder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(uid: String, resource: Drawable) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.imageLoaderProgress.isVisible = false
|
||||||
|
// Glide mess up the view size :/
|
||||||
|
holder.touchImageView.updateLayoutParams {
|
||||||
|
width = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
|
height = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
|
}
|
||||||
|
holder.touchImageView.setImageDrawable(resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.riotx.attachmentviewer
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
interface VideoLoaderTarget {
|
||||||
|
fun contextView(): ImageView
|
||||||
|
|
||||||
|
fun onThumbnailResourceLoading(uid: String, placeholder: Drawable?)
|
||||||
|
|
||||||
|
fun onThumbnailLoadFailed(uid: String, errorDrawable: Drawable?)
|
||||||
|
|
||||||
|
fun onThumbnailResourceCleared(uid: String, placeholder: Drawable?)
|
||||||
|
|
||||||
|
fun onThumbnailResourceReady(uid: String, resource: Drawable)
|
||||||
|
|
||||||
|
fun onVideoFileLoading(uid: String)
|
||||||
|
fun onVideoFileLoadFailed(uid: String)
|
||||||
|
fun onVideoFileReady(uid: String, file: File)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultVideoLoaderTarget(val holder: VideoViewHolder, private val contextView: ImageView) : VideoLoaderTarget {
|
||||||
|
override fun contextView(): ImageView = contextView
|
||||||
|
|
||||||
|
override fun onThumbnailResourceLoading(uid: String, placeholder: Drawable?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onThumbnailLoadFailed(uid: String, errorDrawable: Drawable?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onThumbnailResourceCleared(uid: String, placeholder: Drawable?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onThumbnailResourceReady(uid: String, resource: Drawable) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.thumbnailImage.setImageDrawable(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onVideoFileLoading(uid: String) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.thumbnailImage.isVisible = true
|
||||||
|
holder.loaderProgressBar.isVisible = true
|
||||||
|
holder.videoView.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onVideoFileLoadFailed(uid: String) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.videoFileLoadError()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onVideoFileReady(uid: String, file: File) {
|
||||||
|
if (holder.boundResourceUid != uid) return
|
||||||
|
holder.thumbnailImage.isVisible = false
|
||||||
|
holder.loaderProgressBar.isVisible = false
|
||||||
|
holder.videoView.isVisible = true
|
||||||
|
holder.videoReady(file)
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,38 +44,13 @@ class VideoViewHolder constructor(itemView: View) :
|
||||||
|
|
||||||
var eventListener: WeakReference<AttachmentEventListener>? = null
|
var eventListener: WeakReference<AttachmentEventListener>? = null
|
||||||
|
|
||||||
// interface Target {
|
|
||||||
// fun onResourceLoading(progress: Int, total: Int)
|
|
||||||
// fun onLoadFailed()
|
|
||||||
// fun onResourceReady(file: File)
|
|
||||||
// fun onThumbnailReady(thumbnail: Drawable?)
|
|
||||||
// }
|
|
||||||
|
|
||||||
init {
|
|
||||||
}
|
|
||||||
|
|
||||||
val thumbnailImage: ImageView = itemView.findViewById(R.id.videoThumbnailImage)
|
val thumbnailImage: ImageView = itemView.findViewById(R.id.videoThumbnailImage)
|
||||||
val videoView: VideoView = itemView.findViewById(R.id.videoView)
|
val videoView: VideoView = itemView.findViewById(R.id.videoView)
|
||||||
val loaderProgressBar: ProgressBar = itemView.findViewById(R.id.videoLoaderProgress)
|
val loaderProgressBar: ProgressBar = itemView.findViewById(R.id.videoLoaderProgress)
|
||||||
val videoControlIcon: ImageView = itemView.findViewById(R.id.videoControlIcon)
|
val videoControlIcon: ImageView = itemView.findViewById(R.id.videoControlIcon)
|
||||||
val errorTextView: TextView = itemView.findViewById(R.id.videoMediaViewerErrorView)
|
val errorTextView: TextView = itemView.findViewById(R.id.videoMediaViewerErrorView)
|
||||||
|
|
||||||
// val videoTarget = object : Target {
|
internal val target = DefaultVideoLoaderTarget(this, thumbnailImage)
|
||||||
// override fun onResourceLoading(progress: Int, total: Int) {
|
|
||||||
// videoView.isVisible = false
|
|
||||||
// loaderProgressBar.isVisible = true
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onLoadFailed() {
|
|
||||||
// loaderProgressBar.isVisible = false
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onResourceReady(file: File) {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onThumbnailReady(thumbnail: Drawable?) {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
override fun onRecycled() {
|
override fun onRecycled() {
|
||||||
super.onRecycled()
|
super.onRecycled()
|
||||||
|
@ -91,6 +66,9 @@ class VideoViewHolder constructor(itemView: View) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun videoFileLoadError() {
|
||||||
|
}
|
||||||
|
|
||||||
override fun entersBackground() {
|
override fun entersBackground() {
|
||||||
if (videoView.isPlaying) {
|
if (videoView.isPlaying) {
|
||||||
progress = videoView.currentPosition
|
progress = videoView.currentPosition
|
||||||
|
@ -162,7 +140,7 @@ class VideoViewHolder constructor(itemView: View) :
|
||||||
wasPaused = true
|
wasPaused = true
|
||||||
videoView.pause()
|
videoView.pause()
|
||||||
}
|
}
|
||||||
is AttachmentCommands.SeekTo -> {
|
is AttachmentCommands.SeekTo -> {
|
||||||
val duration = videoView.duration
|
val duration = videoView.duration
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
val seekDuration = duration * (commands.percentProgress / 100f)
|
val seekDuration = duration * (commands.percentProgress / 100f)
|
||||||
|
@ -173,6 +151,7 @@ class VideoViewHolder constructor(itemView: View) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(attachmentInfo: AttachmentInfo) {
|
override fun bind(attachmentInfo: AttachmentInfo) {
|
||||||
|
super.bind(attachmentInfo)
|
||||||
progress = 0
|
progress = 0
|
||||||
wasPaused = false
|
wasPaused = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,9 @@
|
||||||
|
|
||||||
package im.vector.riotx.attachmentviewer
|
package im.vector.riotx.attachmentviewer
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import com.bumptech.glide.request.target.CustomViewTarget
|
|
||||||
import com.bumptech.glide.request.transition.Transition
|
|
||||||
import com.github.chrisbanes.photoview.PhotoView
|
import com.github.chrisbanes.photoview.PhotoView
|
||||||
|
|
||||||
class ZoomableImageViewHolder constructor(itemView: View) :
|
class ZoomableImageViewHolder constructor(itemView: View) :
|
||||||
|
@ -45,31 +39,5 @@ class ZoomableImageViewHolder constructor(itemView: View) :
|
||||||
touchImageView.setAllowParentInterceptOnEdge(true)
|
touchImageView.setAllowParentInterceptOnEdge(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val customTargetView = object : CustomViewTarget<PhotoView, Drawable>(touchImageView) {
|
internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, touchImageView)
|
||||||
|
|
||||||
override fun onResourceLoading(placeholder: Drawable?) {
|
|
||||||
imageLoaderProgress.isVisible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
|
||||||
imageLoaderProgress.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResourceCleared(placeholder: Drawable?) {
|
|
||||||
touchImageView.setImageDrawable(placeholder)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
|
||||||
imageLoaderProgress.isVisible = false
|
|
||||||
// Glide mess up the view size :/
|
|
||||||
touchImageView.updateLayoutParams {
|
|
||||||
width = LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
height = LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
}
|
|
||||||
touchImageView.setImageDrawable(resource)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun bind(attachmentInfo: AttachmentInfo) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,11 +35,10 @@ import im.vector.matrix.android.api.session.room.model.message.MessageWithAttach
|
||||||
import im.vector.matrix.android.api.session.room.model.message.getFileUrl
|
import im.vector.matrix.android.api.session.room.model.message.getFileUrl
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt
|
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt
|
||||||
import im.vector.riotx.attachmentviewer.AnimatedImageViewHolder
|
|
||||||
import im.vector.riotx.attachmentviewer.AttachmentInfo
|
import im.vector.riotx.attachmentviewer.AttachmentInfo
|
||||||
import im.vector.riotx.attachmentviewer.AttachmentSourceProvider
|
import im.vector.riotx.attachmentviewer.AttachmentSourceProvider
|
||||||
import im.vector.riotx.attachmentviewer.VideoViewHolder
|
import im.vector.riotx.attachmentviewer.ImageLoaderTarget
|
||||||
import im.vector.riotx.attachmentviewer.ZoomableImageViewHolder
|
import im.vector.riotx.attachmentviewer.VideoLoaderTarget
|
||||||
import im.vector.riotx.core.date.VectorDateFormatter
|
import im.vector.riotx.core.date.VectorDateFormatter
|
||||||
import im.vector.riotx.core.extensions.localDateTime
|
import im.vector.riotx.core.extensions.localDateTime
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -86,13 +85,15 @@ class RoomAttachmentProvider(
|
||||||
)
|
)
|
||||||
if (content.mimeType == "image/gif") {
|
if (content.mimeType == "image/gif") {
|
||||||
AttachmentInfo.AnimatedImage(
|
AttachmentInfo.AnimatedImage(
|
||||||
content.url ?: "",
|
uid = it.eventId,
|
||||||
data
|
url = content.url ?: "",
|
||||||
|
data = data
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
AttachmentInfo.Image(
|
AttachmentInfo.Image(
|
||||||
content.url ?: "",
|
uid = it.eventId,
|
||||||
data
|
url = content.url ?: "",
|
||||||
|
data = data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if (content is MessageVideoContent) {
|
} else if (content is MessageVideoContent) {
|
||||||
|
@ -117,9 +118,11 @@ class RoomAttachmentProvider(
|
||||||
thumbnailMediaData = thumbnailData
|
thumbnailMediaData = thumbnailData
|
||||||
)
|
)
|
||||||
AttachmentInfo.Video(
|
AttachmentInfo.Video(
|
||||||
content.getFileUrl() ?: "",
|
uid = it.eventId,
|
||||||
data,
|
url = content.getFileUrl() ?: "",
|
||||||
AttachmentInfo.Image(
|
data = data,
|
||||||
|
thumbnail = AttachmentInfo.Image(
|
||||||
|
uid = it.eventId,
|
||||||
url = content.videoInfo?.thumbnailFile?.url
|
url = content.videoInfo?.thumbnailFile?.url
|
||||||
?: content.videoInfo?.thumbnailUrl ?: "",
|
?: content.videoInfo?.thumbnailUrl ?: "",
|
||||||
data = thumbnailData
|
data = thumbnailData
|
||||||
|
@ -128,49 +131,72 @@ class RoomAttachmentProvider(
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
AttachmentInfo.Image(
|
AttachmentInfo.Image(
|
||||||
"",
|
uid = it.eventId,
|
||||||
null
|
url = "",
|
||||||
|
data = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadImage(holder: ZoomableImageViewHolder, info: AttachmentInfo.Image) {
|
override fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.Image) {
|
||||||
(info.data as? ImageContentRenderer.Data)?.let {
|
(info.data as? ImageContentRenderer.Data)?.let {
|
||||||
imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>)
|
imageContentRenderer.render(it, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(target.contextView()) {
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
target.onLoadFailed(info.uid, errorDrawable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceCleared(placeholder: Drawable?) {
|
||||||
|
target.onResourceCleared(info.uid, placeholder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||||
|
target.onResourceReady(info.uid, resource)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadImage(holder: AnimatedImageViewHolder, info: AttachmentInfo.AnimatedImage) {
|
override fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.AnimatedImage) {
|
||||||
(info.data as? ImageContentRenderer.Data)?.let {
|
(info.data as? ImageContentRenderer.Data)?.let {
|
||||||
imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>)
|
imageContentRenderer.render(it, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(target.contextView()) {
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
target.onLoadFailed(info.uid, errorDrawable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceCleared(placeholder: Drawable?) {
|
||||||
|
target.onResourceCleared(info.uid, placeholder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||||
|
target.onResourceReady(info.uid, resource)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadVideo(holder: VideoViewHolder, info: AttachmentInfo.Video) {
|
override fun loadVideo(target: VideoLoaderTarget, info: AttachmentInfo.Video) {
|
||||||
val data = info.data as? VideoContentRenderer.Data ?: return
|
val data = info.data as? VideoContentRenderer.Data ?: return
|
||||||
// videoContentRenderer.render(data,
|
// videoContentRenderer.render(data,
|
||||||
// holder.thumbnailImage,
|
// holder.thumbnailImage,
|
||||||
// holder.loaderProgressBar,
|
// holder.loaderProgressBar,
|
||||||
// holder.videoView,
|
// holder.videoView,
|
||||||
// holder.errorTextView)
|
// holder.errorTextView)
|
||||||
imageContentRenderer.render(data.thumbnailMediaData, holder.thumbnailImage, object : CustomViewTarget<ImageView, Drawable>(holder.thumbnailImage) {
|
imageContentRenderer.render(data.thumbnailMediaData, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(target.contextView()) {
|
||||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
holder.thumbnailImage.setImageDrawable(errorDrawable)
|
target.onThumbnailLoadFailed(info.uid, errorDrawable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResourceCleared(placeholder: Drawable?) {
|
override fun onResourceCleared(placeholder: Drawable?) {
|
||||||
|
target.onThumbnailResourceCleared(info.uid, placeholder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||||
holder.thumbnailImage.setImageDrawable(resource)
|
target.onThumbnailResourceReady(info.uid, resource)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
holder.thumbnailImage.isVisible = false
|
target.onVideoFileLoading(info.uid)
|
||||||
holder.loaderProgressBar.isVisible = false
|
|
||||||
holder.videoView.isVisible = false
|
|
||||||
|
|
||||||
fileService.downloadFile(
|
fileService.downloadFile(
|
||||||
downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE,
|
downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE,
|
||||||
id = data.eventId,
|
id = data.eventId,
|
||||||
|
@ -180,11 +206,11 @@ class RoomAttachmentProvider(
|
||||||
url = data.url,
|
url = data.url,
|
||||||
callback = object : MatrixCallback<File> {
|
callback = object : MatrixCallback<File> {
|
||||||
override fun onSuccess(data: File) {
|
override fun onSuccess(data: File) {
|
||||||
holder.videoReady(data)
|
target.onVideoFileReady(info.uid, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
holder.videoView.isVisible = false
|
target.onVideoFileLoadFailed(info.uid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -214,6 +240,10 @@ class RoomAttachmentProvider(
|
||||||
overlayView?.videoControlsGroup?.isVisible = item.root.isVideoMessage()
|
overlayView?.videoControlsGroup?.isVisible = item.root.isVideoMessage()
|
||||||
return overlayView
|
return overlayView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun clear(id: String) {
|
||||||
|
// TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoomAttachmentProviderFactory @Inject constructor(
|
class RoomAttachmentProviderFactory @Inject constructor(
|
||||||
|
|
Loading…
Add table
Reference in a new issue