mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Support open from upload media tab
This commit is contained in:
parent
e38cb7c1a6
commit
195e2703b9
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.features.media
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import com.bumptech.glide.request.target.CustomViewTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.riotx.attachmentviewer.AttachmentInfo
|
||||
import im.vector.riotx.attachmentviewer.AttachmentSourceProvider
|
||||
import im.vector.riotx.attachmentviewer.ImageLoaderTarget
|
||||
import im.vector.riotx.attachmentviewer.VideoLoaderTarget
|
||||
import java.io.File
|
||||
|
||||
abstract class BaseAttachmentProvider(val imageContentRenderer: ImageContentRenderer, val fileService: FileService) : AttachmentSourceProvider {
|
||||
|
||||
interface InteractionListener {
|
||||
fun onDismissTapped()
|
||||
fun onShareTapped()
|
||||
fun onPlayPause(play: Boolean)
|
||||
fun videoSeekTo(percent: Int)
|
||||
}
|
||||
|
||||
var interactionListener: InteractionListener? = null
|
||||
|
||||
protected var overlayView: AttachmentOverlayView? = null
|
||||
|
||||
override fun overlayViewAtPosition(context: Context, position: Int): View? {
|
||||
if (position == -1) return null
|
||||
if (overlayView == null) {
|
||||
overlayView = AttachmentOverlayView(context)
|
||||
overlayView?.onBack = {
|
||||
interactionListener?.onDismissTapped()
|
||||
}
|
||||
overlayView?.onShareCallback = {
|
||||
interactionListener?.onShareTapped()
|
||||
}
|
||||
overlayView?.onPlayPause = { play ->
|
||||
interactionListener?.onPlayPause(play)
|
||||
}
|
||||
overlayView?.videoSeekTo = { percent ->
|
||||
interactionListener?.videoSeekTo(percent)
|
||||
}
|
||||
}
|
||||
return overlayView
|
||||
}
|
||||
|
||||
override fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.Image) {
|
||||
(info.data as? ImageContentRenderer.Data)?.let {
|
||||
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(target: ImageLoaderTarget, info: AttachmentInfo.AnimatedImage) {
|
||||
(info.data as? ImageContentRenderer.Data)?.let {
|
||||
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(target: VideoLoaderTarget, info: AttachmentInfo.Video) {
|
||||
val data = info.data as? VideoContentRenderer.Data ?: return
|
||||
// videoContentRenderer.render(data,
|
||||
// holder.thumbnailImage,
|
||||
// holder.loaderProgressBar,
|
||||
// holder.videoView,
|
||||
// holder.errorTextView)
|
||||
imageContentRenderer.render(data.thumbnailMediaData, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(target.contextView()) {
|
||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||
target.onThumbnailLoadFailed(info.uid, errorDrawable)
|
||||
}
|
||||
|
||||
override fun onResourceCleared(placeholder: Drawable?) {
|
||||
target.onThumbnailResourceCleared(info.uid, placeholder)
|
||||
}
|
||||
|
||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||
target.onThumbnailResourceReady(info.uid, resource)
|
||||
}
|
||||
})
|
||||
|
||||
target.onVideoFileLoading(info.uid)
|
||||
fileService.downloadFile(
|
||||
downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE,
|
||||
id = data.eventId,
|
||||
mimeType = data.mimeType,
|
||||
elementToDecrypt = data.elementToDecrypt,
|
||||
fileName = data.filename,
|
||||
url = data.url,
|
||||
callback = object : MatrixCallback<File> {
|
||||
override fun onSuccess(data: File) {
|
||||
target.onVideoFileReady(info.uid, data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
target.onVideoFileLoadFailed(info.uid)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun clear(id: String) {
|
||||
// TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
abstract fun getFileForSharing(position: Int, callback: ((File?) -> Unit))
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.features.media
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.events.model.isVideoMessage
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.riotx.attachmentviewer.AttachmentInfo
|
||||
import im.vector.riotx.core.date.VectorDateFormatter
|
||||
import im.vector.riotx.core.extensions.localDateTime
|
||||
import java.io.File
|
||||
|
||||
class DataAttachmentRoomProvider(
|
||||
private val attachments: List<AttachmentData>,
|
||||
private val room: Room?,
|
||||
private val initialIndex: Int,
|
||||
imageContentRenderer: ImageContentRenderer,
|
||||
private val dateFormatter: VectorDateFormatter,
|
||||
fileService: FileService) : BaseAttachmentProvider(imageContentRenderer, fileService) {
|
||||
|
||||
override fun getItemCount(): Int = attachments.size
|
||||
|
||||
override fun getAttachmentInfoAt(position: Int): AttachmentInfo {
|
||||
return attachments[position].let {
|
||||
when (it) {
|
||||
is ImageContentRenderer.Data -> {
|
||||
if (it.mimeType == "image/gif") {
|
||||
AttachmentInfo.AnimatedImage(
|
||||
uid = it.eventId,
|
||||
url = it.url ?: "",
|
||||
data = it
|
||||
)
|
||||
} else {
|
||||
AttachmentInfo.Image(
|
||||
uid = it.eventId,
|
||||
url = it.url ?: "",
|
||||
data = it
|
||||
)
|
||||
}
|
||||
}
|
||||
is VideoContentRenderer.Data -> {
|
||||
AttachmentInfo.Video(
|
||||
uid = it.eventId,
|
||||
url = it.url ?: "",
|
||||
data = it,
|
||||
thumbnail = AttachmentInfo.Image(
|
||||
uid = it.eventId,
|
||||
url = it.thumbnailMediaData.url ?: "",
|
||||
data = it.thumbnailMediaData
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun overlayViewAtPosition(context: Context, position: Int): View? {
|
||||
super.overlayViewAtPosition(context, position)
|
||||
val item = attachments[position]
|
||||
val timeLineEvent = room?.getTimeLineEvent(item.eventId)
|
||||
if (timeLineEvent != null) {
|
||||
val dateString = timeLineEvent.root.localDateTime().let {
|
||||
"${dateFormatter.formatMessageDay(it)} at ${dateFormatter.formatMessageHour(it)} "
|
||||
}
|
||||
overlayView?.updateWith("${position + 1} of ${attachments.size}", "${timeLineEvent.senderInfo.displayName} $dateString")
|
||||
overlayView?.videoControlsGroup?.isVisible = timeLineEvent.root.isVideoMessage()
|
||||
} else {
|
||||
overlayView?.updateWith("", "")
|
||||
}
|
||||
return overlayView
|
||||
}
|
||||
|
||||
override fun getFileForSharing(position: Int, callback: (File?) -> Unit) {
|
||||
val item = attachments[position]
|
||||
fileService.downloadFile(
|
||||
downloadMode = FileService.DownloadMode.FOR_EXTERNAL_SHARE,
|
||||
id = item.eventId,
|
||||
fileName = item.filename,
|
||||
mimeType = item.mimeType,
|
||||
url = item.url ?: "",
|
||||
elementToDecrypt = item.elementToDecrypt,
|
||||
callback = object : MatrixCallback<File> {
|
||||
override fun onSuccess(data: File) {
|
||||
callback(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback(null)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@ -17,17 +17,14 @@
|
||||
package im.vector.riotx.features.media
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.core.view.isVisible
|
||||
import com.bumptech.glide.request.target.CustomViewTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.events.model.isVideoMessage
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||
@ -36,33 +33,18 @@ 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.internal.crypto.attachments.toElementToDecrypt
|
||||
import im.vector.riotx.attachmentviewer.AttachmentInfo
|
||||
import im.vector.riotx.attachmentviewer.AttachmentSourceProvider
|
||||
import im.vector.riotx.attachmentviewer.ImageLoaderTarget
|
||||
import im.vector.riotx.attachmentviewer.VideoLoaderTarget
|
||||
import im.vector.riotx.core.date.VectorDateFormatter
|
||||
import im.vector.riotx.core.extensions.localDateTime
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomAttachmentProvider(
|
||||
class RoomEventsAttachmentProvider(
|
||||
private val attachments: List<TimelineEvent>,
|
||||
private val initialIndex: Int,
|
||||
private val imageContentRenderer: ImageContentRenderer,
|
||||
private val videoContentRenderer: VideoContentRenderer,
|
||||
imageContentRenderer: ImageContentRenderer,
|
||||
private val dateFormatter: VectorDateFormatter,
|
||||
private val fileService: FileService
|
||||
) : AttachmentSourceProvider {
|
||||
|
||||
interface InteractionListener {
|
||||
fun onDismissTapped()
|
||||
fun onShareTapped()
|
||||
fun onPlayPause(play: Boolean)
|
||||
fun videoSeekTo(percent: Int)
|
||||
}
|
||||
|
||||
var interactionListener: InteractionListener? = null
|
||||
|
||||
private var overlayView: AttachmentOverlayView? = null
|
||||
fileService: FileService
|
||||
) : BaseAttachmentProvider(imageContentRenderer, fileService) {
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return attachments.size
|
||||
@ -139,99 +121,8 @@ class RoomAttachmentProvider(
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.Image) {
|
||||
(info.data as? ImageContentRenderer.Data)?.let {
|
||||
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(target: ImageLoaderTarget, info: AttachmentInfo.AnimatedImage) {
|
||||
(info.data as? ImageContentRenderer.Data)?.let {
|
||||
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(target: VideoLoaderTarget, info: AttachmentInfo.Video) {
|
||||
val data = info.data as? VideoContentRenderer.Data ?: return
|
||||
// videoContentRenderer.render(data,
|
||||
// holder.thumbnailImage,
|
||||
// holder.loaderProgressBar,
|
||||
// holder.videoView,
|
||||
// holder.errorTextView)
|
||||
imageContentRenderer.render(data.thumbnailMediaData, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(target.contextView()) {
|
||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||
target.onThumbnailLoadFailed(info.uid, errorDrawable)
|
||||
}
|
||||
|
||||
override fun onResourceCleared(placeholder: Drawable?) {
|
||||
target.onThumbnailResourceCleared(info.uid, placeholder)
|
||||
}
|
||||
|
||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||
target.onThumbnailResourceReady(info.uid, resource)
|
||||
}
|
||||
})
|
||||
|
||||
target.onVideoFileLoading(info.uid)
|
||||
fileService.downloadFile(
|
||||
downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE,
|
||||
id = data.eventId,
|
||||
mimeType = data.mimeType,
|
||||
elementToDecrypt = data.elementToDecrypt,
|
||||
fileName = data.filename,
|
||||
url = data.url,
|
||||
callback = object : MatrixCallback<File> {
|
||||
override fun onSuccess(data: File) {
|
||||
target.onVideoFileReady(info.uid, data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
target.onVideoFileLoadFailed(info.uid)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun overlayViewAtPosition(context: Context, position: Int): View? {
|
||||
if (overlayView == null) {
|
||||
overlayView = AttachmentOverlayView(context)
|
||||
overlayView?.onBack = {
|
||||
interactionListener?.onDismissTapped()
|
||||
}
|
||||
overlayView?.onShareCallback = {
|
||||
interactionListener?.onShareTapped()
|
||||
}
|
||||
overlayView?.onPlayPause = { play ->
|
||||
interactionListener?.onPlayPause(play)
|
||||
}
|
||||
overlayView?.videoSeekTo = { percent ->
|
||||
interactionListener?.videoSeekTo(percent)
|
||||
}
|
||||
}
|
||||
super.overlayViewAtPosition(context, position)
|
||||
val item = attachments[position]
|
||||
val dateString = item.root.localDateTime().let {
|
||||
"${dateFormatter.formatMessageDay(it)} at ${dateFormatter.formatMessageHour(it)} "
|
||||
@ -241,19 +132,44 @@ class RoomAttachmentProvider(
|
||||
return overlayView
|
||||
}
|
||||
|
||||
override fun clear(id: String) {
|
||||
// TODO("Not yet implemented")
|
||||
override fun getFileForSharing(position: Int, callback: (File?) -> Unit) {
|
||||
attachments[position].let { timelineEvent ->
|
||||
|
||||
val messageContent = timelineEvent.root.getClearContent().toModel<MessageContent>()
|
||||
as? MessageWithAttachmentContent
|
||||
?: return@let
|
||||
fileService.downloadFile(
|
||||
downloadMode = FileService.DownloadMode.FOR_EXTERNAL_SHARE,
|
||||
id = timelineEvent.eventId,
|
||||
fileName = messageContent.body,
|
||||
mimeType = messageContent.mimeType,
|
||||
url = messageContent.getFileUrl(),
|
||||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||
callback = object : MatrixCallback<File> {
|
||||
override fun onSuccess(data: File) {
|
||||
callback(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback(null)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RoomAttachmentProviderFactory @Inject constructor(
|
||||
class AttachmentProviderFactory @Inject constructor(
|
||||
private val imageContentRenderer: ImageContentRenderer,
|
||||
private val vectorDateFormatter: VectorDateFormatter,
|
||||
private val videoContentRenderer: VideoContentRenderer,
|
||||
private val session: Session
|
||||
) {
|
||||
|
||||
fun createProvider(attachments: List<TimelineEvent>, initialIndex: Int): RoomAttachmentProvider {
|
||||
return RoomAttachmentProvider(attachments, initialIndex, imageContentRenderer, videoContentRenderer, vectorDateFormatter, session.fileService())
|
||||
fun createProvider(attachments: List<TimelineEvent>, initialIndex: Int): RoomEventsAttachmentProvider {
|
||||
return RoomEventsAttachmentProvider(attachments, initialIndex, imageContentRenderer, vectorDateFormatter, session.fileService())
|
||||
}
|
||||
|
||||
fun createProvider(attachments: List<AttachmentData>, room: Room?, initialIndex: Int): DataAttachmentRoomProvider {
|
||||
return DataAttachmentRoomProvider(attachments, room, initialIndex, imageContentRenderer, vectorDateFormatter, session.fileService())
|
||||
}
|
||||
}
|
@ -30,14 +30,6 @@ import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.transition.Transition
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageWithAttachmentContent
|
||||
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.internal.crypto.attachments.toElementToDecrypt
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.attachmentviewer.AttachmentCommands
|
||||
import im.vector.riotx.attachmentviewer.AttachmentViewerActivity
|
||||
@ -52,11 +44,10 @@ import im.vector.riotx.features.themes.ActivityOtherThemes
|
||||
import im.vector.riotx.features.themes.ThemeUtils
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
class VectorAttachmentViewerActivity : AttachmentViewerActivity(), RoomAttachmentProvider.InteractionListener {
|
||||
class VectorAttachmentViewerActivity : AttachmentViewerActivity(), BaseAttachmentProvider.InteractionListener {
|
||||
|
||||
@Parcelize
|
||||
data class Args(
|
||||
@ -69,7 +60,7 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), RoomAttachmen
|
||||
lateinit var sessionHolder: ActiveSessionHolder
|
||||
|
||||
@Inject
|
||||
lateinit var dataSourceFactory: RoomAttachmentProviderFactory
|
||||
lateinit var dataSourceFactory: AttachmentProviderFactory
|
||||
|
||||
@Inject
|
||||
lateinit var imageContentRenderer: ImageContentRenderer
|
||||
@ -78,7 +69,8 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), RoomAttachmen
|
||||
|
||||
private var initialIndex = 0
|
||||
private var isAnimatingOut = false
|
||||
private var eventList: List<TimelineEvent>? = null
|
||||
|
||||
var currentSourceProvider: BaseAttachmentProvider? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -92,13 +84,6 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), RoomAttachmen
|
||||
ThemeUtils.setActivityTheme(this, getOtherThemes())
|
||||
|
||||
val args = args() ?: throw IllegalArgumentException("Missing arguments")
|
||||
val session = sessionHolder.getSafeActiveSession() ?: return Unit.also { finish() }
|
||||
|
||||
val room = args.roomId?.let { session.getRoom(it) }
|
||||
val events = room?.getAttachmentMessages() ?: emptyList()
|
||||
eventList = events
|
||||
val index = events.indexOfFirst { it.eventId == args.eventId }
|
||||
initialIndex = index
|
||||
|
||||
if (savedInstanceState == null && addTransitionListener()) {
|
||||
args.sharedTransitionName?.let {
|
||||
@ -127,14 +112,41 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), RoomAttachmen
|
||||
}
|
||||
}
|
||||
|
||||
val sourceProvider = dataSourceFactory.createProvider(events, index)
|
||||
sourceProvider.interactionListener = this
|
||||
setSourceProvider(sourceProvider)
|
||||
if (savedInstanceState == null) {
|
||||
pager2.setCurrentItem(index, false)
|
||||
// The page change listener is not notified of the change...
|
||||
pager2.post {
|
||||
onSelectedPositionChanged(index)
|
||||
val session = sessionHolder.getSafeActiveSession() ?: return Unit.also { finish() }
|
||||
|
||||
val room = args.roomId?.let { session.getRoom(it) }
|
||||
|
||||
val inMemoryData = intent.getParcelableArrayListExtra<AttachmentData>(EXTRA_IN_MEMORY_DATA)
|
||||
if (inMemoryData != null) {
|
||||
val sourceProvider = dataSourceFactory.createProvider(inMemoryData, room, initialIndex)
|
||||
val index = inMemoryData.indexOfFirst { it.eventId == args.eventId }
|
||||
initialIndex = index
|
||||
sourceProvider.interactionListener = this
|
||||
setSourceProvider(sourceProvider)
|
||||
this.currentSourceProvider = sourceProvider
|
||||
if (savedInstanceState == null) {
|
||||
pager2.setCurrentItem(index, false)
|
||||
// The page change listener is not notified of the change...
|
||||
pager2.post {
|
||||
onSelectedPositionChanged(index)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val events = room?.getAttachmentMessages()
|
||||
?: emptyList()
|
||||
val index = events.indexOfFirst { it.eventId == args.eventId }
|
||||
initialIndex = index
|
||||
|
||||
val sourceProvider = dataSourceFactory.createProvider(events, index)
|
||||
sourceProvider.interactionListener = this
|
||||
setSourceProvider(sourceProvider)
|
||||
this.currentSourceProvider = sourceProvider
|
||||
if (savedInstanceState == null) {
|
||||
pager2.setCurrentItem(index, false)
|
||||
// The page change listener is not notified of the change...
|
||||
pager2.post {
|
||||
onSelectedPositionChanged(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,14 +240,19 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), RoomAttachmen
|
||||
|
||||
const val EXTRA_ARGS = "EXTRA_ARGS"
|
||||
const val EXTRA_IMAGE_DATA = "EXTRA_IMAGE_DATA"
|
||||
const val EXTRA_IN_MEMORY_DATA = "EXTRA_IN_MEMORY_DATA"
|
||||
|
||||
fun newIntent(context: Context,
|
||||
mediaData: AttachmentData,
|
||||
roomId: String?,
|
||||
eventId: String,
|
||||
inMemoryData: List<AttachmentData>?,
|
||||
sharedTransitionName: String?) = Intent(context, VectorAttachmentViewerActivity::class.java).also {
|
||||
it.putExtra(EXTRA_ARGS, Args(roomId, eventId, sharedTransitionName))
|
||||
it.putExtra(EXTRA_IMAGE_DATA, mediaData)
|
||||
if (inMemoryData != null) {
|
||||
it.putParcelableArrayListExtra(EXTRA_IN_MEMORY_DATA, ArrayList(inMemoryData))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,27 +269,10 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), RoomAttachmen
|
||||
}
|
||||
|
||||
override fun onShareTapped() {
|
||||
// Share
|
||||
eventList?.get(currentPosition)?.let { timelineEvent ->
|
||||
|
||||
val messageContent = timelineEvent.root.getClearContent().toModel<MessageContent>()
|
||||
as? MessageWithAttachmentContent
|
||||
?: return@let
|
||||
sessionHolder.getSafeActiveSession()?.fileService()?.downloadFile(
|
||||
downloadMode = FileService.DownloadMode.FOR_EXTERNAL_SHARE,
|
||||
id = timelineEvent.eventId,
|
||||
fileName = messageContent.body,
|
||||
mimeType = messageContent.mimeType,
|
||||
url = messageContent.getFileUrl(),
|
||||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||
callback = object : MatrixCallback<File> {
|
||||
override fun onSuccess(data: File) {
|
||||
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
|
||||
shareMedia(this@VectorAttachmentViewerActivity, data, getMimeTypeFromUri(this@VectorAttachmentViewerActivity, data.toUri()))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
this.currentSourceProvider?.getFileForSharing(currentPosition) { data ->
|
||||
if (data != null && lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
|
||||
shareMedia(this@VectorAttachmentViewerActivity, data, getMimeTypeFromUri(this@VectorAttachmentViewerActivity, data.toUri()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -246,20 +246,25 @@ class DefaultNavigator @Inject constructor(
|
||||
}
|
||||
|
||||
override fun openImageViewer(activity: Activity,
|
||||
roomId: String?,
|
||||
roomId: String,
|
||||
mediaData: AttachmentData,
|
||||
view: View,
|
||||
inMemory: List<AttachmentData>?,
|
||||
options: ((MutableList<Pair<View, String>>) -> Unit)?) {
|
||||
VectorAttachmentViewerActivity.newIntent(activity, mediaData, roomId, mediaData.eventId, ViewCompat.getTransitionName(view)).let { intent ->
|
||||
VectorAttachmentViewerActivity.newIntent(activity,
|
||||
mediaData,
|
||||
roomId,
|
||||
mediaData.eventId,
|
||||
inMemory,
|
||||
ViewCompat.getTransitionName(view)).let { intent ->
|
||||
val pairs = ArrayList<Pair<View, String>>()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
activity.window.decorView.findViewById<View>(android.R.id.statusBarBackground)?.let {
|
||||
pairs.add(Pair(it, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME))
|
||||
}
|
||||
activity.window.decorView.findViewById<View>(android.R.id.navigationBarBackground)?.let {
|
||||
pairs.add(Pair(it, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME))
|
||||
}
|
||||
activity.window.decorView.findViewById<View>(android.R.id.statusBarBackground)?.let {
|
||||
pairs.add(Pair(it, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME))
|
||||
}
|
||||
activity.window.decorView.findViewById<View>(android.R.id.navigationBarBackground)?.let {
|
||||
pairs.add(Pair(it, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME))
|
||||
}
|
||||
|
||||
pairs.add(Pair(view, ViewCompat.getTransitionName(view) ?: ""))
|
||||
options?.invoke(pairs)
|
||||
|
||||
@ -284,12 +289,18 @@ class DefaultNavigator @Inject constructor(
|
||||
}
|
||||
|
||||
override fun openVideoViewer(activity: Activity,
|
||||
roomId: String?, mediaData: VideoContentRenderer.Data,
|
||||
roomId: String, mediaData: VideoContentRenderer.Data,
|
||||
view: View,
|
||||
inMemory: List<AttachmentData>?,
|
||||
options: ((MutableList<Pair<View, String>>) -> Unit)?) {
|
||||
// val intent = VideoMediaViewerActivity.newIntent(activity, mediaData)
|
||||
// activity.startActivity(intent)
|
||||
VectorAttachmentViewerActivity.newIntent(activity, mediaData, roomId, mediaData.eventId, ViewCompat.getTransitionName(view)).let { intent ->
|
||||
VectorAttachmentViewerActivity.newIntent(activity,
|
||||
mediaData,
|
||||
roomId,
|
||||
mediaData.eventId,
|
||||
inMemory,
|
||||
ViewCompat.getTransitionName(view)).let { intent ->
|
||||
val pairs = ArrayList<Pair<View, String>>()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
activity.window.decorView.findViewById<View>(android.R.id.statusBarBackground)?.let {
|
||||
|
@ -92,13 +92,15 @@ interface Navigator {
|
||||
fun openRoomWidget(context: Context, roomId: String, widget: Widget)
|
||||
|
||||
fun openImageViewer(activity: Activity,
|
||||
roomId: String?,
|
||||
roomId: String,
|
||||
mediaData: AttachmentData,
|
||||
view: View,
|
||||
inMemory: List<AttachmentData>? = null,
|
||||
options: ((MutableList<Pair<View, String>>) -> Unit)?)
|
||||
|
||||
fun openVideoViewer(activity: Activity,
|
||||
roomId: String?, mediaData: VideoContentRenderer.Data,
|
||||
roomId: String, mediaData: VideoContentRenderer.Data,
|
||||
view: View,
|
||||
inMemory: List<AttachmentData>? = null,
|
||||
options: ((MutableList<Pair<View, String>>) -> Unit)?)
|
||||
}
|
||||
|
@ -20,23 +20,34 @@ import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.util.Pair
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.getFileUrl
|
||||
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.cleanup
|
||||
import im.vector.riotx.core.extensions.trackItemsVisibilityChange
|
||||
import im.vector.riotx.core.platform.StateView
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.core.utils.DimensionConverter
|
||||
import im.vector.riotx.features.media.AttachmentData
|
||||
import im.vector.riotx.features.media.ImageContentRenderer
|
||||
import im.vector.riotx.features.media.VideoContentRenderer
|
||||
import im.vector.riotx.features.roomprofile.uploads.RoomUploadsAction
|
||||
import im.vector.riotx.features.roomprofile.uploads.RoomUploadsFragment
|
||||
import im.vector.riotx.features.roomprofile.uploads.RoomUploadsViewModel
|
||||
import im.vector.riotx.features.roomprofile.uploads.RoomUploadsViewState
|
||||
import kotlinx.android.synthetic.main.fragment_generic_state_view_recycler.*
|
||||
import kotlinx.android.synthetic.main.fragment_room_uploads.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomUploadsMediaFragment @Inject constructor(
|
||||
@ -76,13 +87,75 @@ class RoomUploadsMediaFragment @Inject constructor(
|
||||
controller.listener = null
|
||||
}
|
||||
|
||||
override fun onOpenImageClicked(view: View, mediaData: ImageContentRenderer.Data) {
|
||||
navigator.openImageViewer(requireActivity(), null, mediaData, view, null)
|
||||
// It's very strange i can't just access
|
||||
// the app bar using find by id...
|
||||
private fun trickFindAppBar() : AppBarLayout? {
|
||||
return activity?.supportFragmentManager?.fragments
|
||||
?.filterIsInstance<RoomUploadsFragment>()
|
||||
?.firstOrNull()
|
||||
?.roomUploadsAppBar
|
||||
}
|
||||
|
||||
override fun onOpenVideoClicked(view: View, mediaData: VideoContentRenderer.Data) {
|
||||
// TODO
|
||||
// navigator.openVideoViewer(requireActivity(), mediaData, null, )
|
||||
override fun onOpenImageClicked(view: View, mediaData: ImageContentRenderer.Data) = withState(uploadsViewModel) { state ->
|
||||
|
||||
val inMemory = getItemsArgs(state)
|
||||
navigator.openImageViewer(requireActivity(), state.roomId, mediaData, view, inMemory) { pairs ->
|
||||
trickFindAppBar()?.let {
|
||||
pairs.add(Pair(it, ViewCompat.getTransitionName(it) ?: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getItemsArgs(state: RoomUploadsViewState): List<AttachmentData> {
|
||||
return state.mediaEvents.mapNotNull {
|
||||
when (val content = it.contentWithAttachmentContent) {
|
||||
is MessageImageContent -> {
|
||||
ImageContentRenderer.Data(
|
||||
eventId = it.eventId,
|
||||
filename = content.body,
|
||||
mimeType = content.mimeType,
|
||||
url = content.getFileUrl(),
|
||||
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
||||
maxHeight = -1,
|
||||
maxWidth = -1,
|
||||
width = null,
|
||||
height = null
|
||||
)
|
||||
}
|
||||
is MessageVideoContent -> {
|
||||
val thumbnailData = ImageContentRenderer.Data(
|
||||
eventId = it.eventId,
|
||||
filename = content.body,
|
||||
mimeType = content.mimeType,
|
||||
url = content.videoInfo?.thumbnailFile?.url
|
||||
?: content.videoInfo?.thumbnailUrl,
|
||||
elementToDecrypt = content.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
||||
height = content.videoInfo?.height,
|
||||
maxHeight = -1,
|
||||
width = content.videoInfo?.width,
|
||||
maxWidth = -1
|
||||
)
|
||||
VideoContentRenderer.Data(
|
||||
eventId = it.eventId,
|
||||
filename = content.body,
|
||||
mimeType = content.mimeType,
|
||||
url = content.getFileUrl(),
|
||||
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
||||
thumbnailMediaData = thumbnailData
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOpenVideoClicked(view: View, mediaData: VideoContentRenderer.Data) = withState(uploadsViewModel) { state ->
|
||||
val inMemory = getItemsArgs(state)
|
||||
navigator.openVideoViewer(requireActivity(), state.roomId, mediaData, view, inMemory) { pairs ->
|
||||
trickFindAppBar()?.let {
|
||||
pairs.add(Pair(it, ViewCompat.getTransitionName(it) ?: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadMore() {
|
||||
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.roomprofile.uploads.media
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.core.view.ViewCompat
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
@ -37,6 +38,7 @@ abstract class UploadsImageItem : VectorEpoxyModel<UploadsImageItem.Holder>() {
|
||||
super.bind(holder)
|
||||
holder.view.setOnClickListener { listener?.onItemClicked(holder.imageView, data) }
|
||||
imageContentRenderer.render(data, holder.imageView, IMAGE_SIZE_DP)
|
||||
ViewCompat.setTransitionName(holder.imageView, "imagePreview_${id()}")
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.roomprofile.uploads.media
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.core.view.ViewCompat
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
@ -38,6 +39,7 @@ abstract class UploadsVideoItem : VectorEpoxyModel<UploadsVideoItem.Holder>() {
|
||||
super.bind(holder)
|
||||
holder.view.setOnClickListener { listener?.onItemClicked(holder.imageView, data) }
|
||||
imageContentRenderer.render(data.thumbnailMediaData, holder.imageView, IMAGE_SIZE_DP)
|
||||
ViewCompat.setTransitionName(holder.imageView, "videoPreview_${id()}")
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
style="@style/VectorAppBarLayoutStyle"
|
||||
android:id="@+id/roomUploadsAppBar"
|
||||
android:transitionName="toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="4dp">
|
||||
|
Loading…
Reference in New Issue
Block a user