Timeline : start to handle video media. Probably to amend

This commit is contained in:
ganfra 2019-04-12 13:46:59 +02:00
parent 657f4d3e9c
commit 2c83ba0824
11 changed files with 202 additions and 19 deletions

View File

@ -24,8 +24,11 @@ import im.vector.matrix.android.api.session.content.ContentAttachmentData
import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toContent import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent
import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.matrix.android.api.session.room.model.message.MessageFileContent
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent 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.internal.di.MatrixKoinComponent import im.vector.matrix.android.internal.di.MatrixKoinComponent
import im.vector.matrix.android.internal.session.room.send.SendEventWorker import im.vector.matrix.android.internal.session.room.send.SendEventWorker
import im.vector.matrix.android.internal.util.WorkerParamsFactory import im.vector.matrix.android.internal.util.WorkerParamsFactory
@ -69,6 +72,9 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters)
val messageContent: MessageContent = event.content.toModel() ?: return event val messageContent: MessageContent = event.content.toModel() ?: return event
val updatedContent = when (messageContent) { val updatedContent = when (messageContent) {
is MessageImageContent -> messageContent.update(url) is MessageImageContent -> messageContent.update(url)
is MessageVideoContent -> messageContent.update(url)
is MessageFileContent -> messageContent.update(url)
is MessageAudioContent -> messageContent.update(url)
else -> messageContent else -> messageContent
} }
return event.copy(content = updatedContent.toContent()) return event.copy(content = updatedContent.toContent())
@ -78,6 +84,18 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters)
return copy(url = url) return copy(url = url)
} }


private fun MessageVideoContent.update(url: String): MessageVideoContent {
return copy(url = url)
}

private fun MessageFileContent.update(url: String): MessageFileContent {
return copy(url = url)
}

private fun MessageAudioContent.update(url: String): MessageAudioContent {
return copy(url = url)
}



} }



View File

@ -187,6 +187,7 @@ dependencies {
implementation "com.github.piasy:GlideImageViewFactory:$big_image_viewer_version" implementation "com.github.piasy:GlideImageViewFactory:$big_image_viewer_version"
implementation "com.github.bumptech.glide:glide:$glide_version" implementation "com.github.bumptech.glide:glide:$glide_version"
kapt "com.github.bumptech.glide:compiler:$glide_version" kapt "com.github.bumptech.glide:compiler:$glide_version"
implementation 'com.danikula:videocache:2.7.1'


// Badge for compatibility // Badge for compatibility
implementation 'me.leolin:ShortcutBadger:1.1.2@aar' implementation 'me.leolin:ShortcutBadger:1.1.2@aar'

View File

@ -29,7 +29,7 @@


<activity android:name=".features.home.HomeActivity" /> <activity android:name=".features.home.HomeActivity" />
<activity android:name=".features.login.LoginActivity" /> <activity android:name=".features.login.LoginActivity" />
<activity android:name=".features.media.MediaViewerActivity" /> <activity android:name=".features.media.ImageMediaViewerActivity" />
<activity <activity
android:name=".features.rageshake.BugReportActivity" android:name=".features.rageshake.BugReportActivity"
android:label="@string/title_activity_bug_report" /> android:label="@string/title_activity_bug_report" />
@ -37,6 +37,7 @@
android:name=".features.settings.VectorSettingsActivity" android:name=".features.settings.VectorSettingsActivity"
android:label="@string/title_activity_settings" android:label="@string/title_activity_settings"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity android:name=".features.media.VideoMediaViewerActivity" />


<service <service
android:name=".core.services.CallService" android:name=".core.services.CallService"

View File

@ -70,7 +70,9 @@ import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventCo
import im.vector.riotredesign.features.home.room.detail.timeline.helper.EndlessRecyclerViewScrollListener import im.vector.riotredesign.features.home.room.detail.timeline.helper.EndlessRecyclerViewScrollListener
import im.vector.riotredesign.features.html.PillImageSpan import im.vector.riotredesign.features.html.PillImageSpan
import im.vector.riotredesign.features.media.ImageContentRenderer import im.vector.riotredesign.features.media.ImageContentRenderer
import im.vector.riotredesign.features.media.MediaViewerActivity import im.vector.riotredesign.features.media.ImageMediaViewerActivity
import im.vector.riotredesign.features.media.VideoContentRenderer
import im.vector.riotredesign.features.media.VideoMediaViewerActivity
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_detail.* import kotlinx.android.synthetic.main.fragment_room_detail.*
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -384,12 +386,13 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
} }


override fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) { override fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) {
val intent = MediaViewerActivity.newIntent(vectorBaseActivity, mediaData) val intent = ImageMediaViewerActivity.newIntent(vectorBaseActivity, mediaData)
startActivity(intent) startActivity(intent)
} }


override fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: ImageContentRenderer.Data, view: View) { override fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View) {
vectorBaseActivity.notImplemented() val intent = VideoMediaViewerActivity.newIntent(vectorBaseActivity, mediaData)
startActivity(intent)
} }


override fun onFileMessageClicked(messageFileContent: MessageFileContent) { override fun onFileMessageClicked(messageFileContent: MessageFileContent) {

View File

@ -42,6 +42,7 @@ import im.vector.riotredesign.features.home.room.detail.timeline.helper.Timeline
import im.vector.riotredesign.features.home.room.detail.timeline.helper.nextDisplayableEvent import im.vector.riotredesign.features.home.room.detail.timeline.helper.nextDisplayableEvent
import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem_ import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem_
import im.vector.riotredesign.features.media.ImageContentRenderer import im.vector.riotredesign.features.media.ImageContentRenderer
import im.vector.riotredesign.features.media.VideoContentRenderer


class TimelineEventController(private val dateFormatter: TimelineDateFormatter, class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
private val timelineItemFactory: TimelineItemFactory, private val timelineItemFactory: TimelineItemFactory,
@ -53,7 +54,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
fun onEventVisible(event: TimelineEvent) fun onEventVisible(event: TimelineEvent)
fun onUrlClicked(url: String) fun onUrlClicked(url: String)
fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View)
fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: ImageContentRenderer.Data, view: View) fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View)
fun onFileMessageClicked(messageFileContent: MessageFileContent) fun onFileMessageClicked(messageFileContent: MessageFileContent)
fun onAudioMessageClicked(messageAudioContent: MessageAudioContent) fun onAudioMessageClicked(messageAudioContent: MessageAudioContent)
} }

View File

@ -51,6 +51,7 @@ import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTex
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_ import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_
import im.vector.riotredesign.features.html.EventHtmlRenderer import im.vector.riotredesign.features.html.EventHtmlRenderer
import im.vector.riotredesign.features.media.ImageContentRenderer import im.vector.riotredesign.features.media.ImageContentRenderer
import im.vector.riotredesign.features.media.VideoContentRenderer
import me.gujun.android.span.span import me.gujun.android.span.span


class MessageItemFactory(private val colorProvider: ColorProvider, class MessageItemFactory(private val colorProvider: ColorProvider,
@ -157,7 +158,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
callback: TimelineEventController.Callback?): MessageImageVideoItem? { callback: TimelineEventController.Callback?): MessageImageVideoItem? {


val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize() val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
val data = ImageContentRenderer.Data( val thumbnailData = ImageContentRenderer.Data(
filename = messageContent.body, filename = messageContent.body,
url = messageContent.info?.thumbnailUrl, url = messageContent.info?.thumbnailUrl,
height = messageContent.info?.height, height = messageContent.info?.height,
@ -165,11 +166,18 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
width = messageContent.info?.width, width = messageContent.info?.width,
maxWidth = maxWidth maxWidth = maxWidth
) )

val videoData = VideoContentRenderer.Data(
filename = messageContent.body,
videoUrl = messageContent.url,
thumbnailMediaData = thumbnailData
)

return MessageImageVideoItem_() return MessageImageVideoItem_()
.playable(true) .playable(true)
.informationData(informationData) .informationData(informationData)
.mediaData(data) .mediaData(thumbnailData)
.clickListener { view -> callback?.onVideoMessageClicked(messageContent, data, view) } .clickListener { view -> callback?.onVideoMessageClicked(messageContent, videoData, view) }
} }


private fun buildTextMessageItem(messageContent: MessageTextContent, private fun buildTextMessageItem(messageContent: MessageTextContent,

View File

@ -25,22 +25,22 @@ import androidx.appcompat.widget.Toolbar
import com.github.piasy.biv.indicator.progresspie.ProgressPieIndicator import com.github.piasy.biv.indicator.progresspie.ProgressPieIndicator
import com.github.piasy.biv.view.GlideImageViewFactory import com.github.piasy.biv.view.GlideImageViewFactory
import im.vector.riotredesign.core.platform.VectorBaseActivity import im.vector.riotredesign.core.platform.VectorBaseActivity
import kotlinx.android.synthetic.main.activity_media_viewer.* import kotlinx.android.synthetic.main.activity_image_media_viewer.*




class MediaViewerActivity : VectorBaseActivity() { class ImageMediaViewerActivity : VectorBaseActivity() {


override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(im.vector.riotredesign.R.layout.activity_media_viewer) setContentView(im.vector.riotredesign.R.layout.activity_image_media_viewer)
val mediaData = intent.getParcelableExtra<ImageContentRenderer.Data>(EXTRA_MEDIA_DATA) val mediaData = intent.getParcelableExtra<ImageContentRenderer.Data>(EXTRA_MEDIA_DATA)
if (mediaData.url.isNullOrEmpty()) { if (mediaData.url.isNullOrEmpty()) {
finish() finish()
} else { } else {
configureToolbar(mediaViewerToolbar, mediaData) configureToolbar(imageMediaViewerToolbar, mediaData)
mediaViewerImageView.setImageViewFactory(GlideImageViewFactory()) imageMediaViewerImageView.setImageViewFactory(GlideImageViewFactory())
mediaViewerImageView.setProgressIndicator(ProgressPieIndicator()) imageMediaViewerImageView.setProgressIndicator(ProgressPieIndicator())
ImageContentRenderer.render(mediaData, mediaViewerImageView) ImageContentRenderer.render(mediaData, imageMediaViewerImageView)
} }
} }


@ -58,7 +58,7 @@ class MediaViewerActivity : VectorBaseActivity() {
private const val EXTRA_MEDIA_DATA = "EXTRA_MEDIA_DATA" private const val EXTRA_MEDIA_DATA = "EXTRA_MEDIA_DATA"


fun newIntent(context: Context, mediaData: ImageContentRenderer.Data): Intent { fun newIntent(context: Context, mediaData: ImageContentRenderer.Data): Intent {
return Intent(context, MediaViewerActivity::class.java).apply { return Intent(context, ImageMediaViewerActivity::class.java).apply {
putExtra(EXTRA_MEDIA_DATA, mediaData) putExtra(EXTRA_MEDIA_DATA, mediaData)
} }
} }

View File

@ -0,0 +1,41 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.riotredesign.features.media

import android.os.Parcelable
import android.widget.ImageView
import android.widget.VideoView
import im.vector.matrix.android.api.Matrix
import kotlinx.android.parcel.Parcelize

object VideoContentRenderer {

@Parcelize
data class Data(
val filename: String,
val videoUrl: String?,
val thumbnailMediaData: ImageContentRenderer.Data
) : Parcelable

fun render(data: Data, thumbnailView: ImageView, videoView: VideoView) {
val contentUrlResolver = Matrix.getInstance().currentSession!!.contentUrlResolver()
val resolvedUrl = contentUrlResolver.resolveFullSize(data.videoUrl)
videoView.setVideoPath(resolvedUrl)
videoView.start()
}

}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.riotredesign.features.media

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.widget.Toolbar
import im.vector.riotredesign.core.platform.VectorBaseActivity
import kotlinx.android.synthetic.main.activity_video_media_viewer.*


class VideoMediaViewerActivity : VectorBaseActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(im.vector.riotredesign.R.layout.activity_video_media_viewer)
val mediaData = intent.getParcelableExtra<VideoContentRenderer.Data>(EXTRA_MEDIA_DATA)
if (mediaData.videoUrl.isNullOrEmpty()) {
finish()
} else {
configureToolbar(videoMediaViewerToolbar, mediaData)
VideoContentRenderer.render(mediaData, videoMediaViewerThumbnailView, videoMediaViewerVideoView)
}
}

private fun configureToolbar(toolbar: Toolbar, mediaData: VideoContentRenderer.Data) {
setSupportActionBar(toolbar)
supportActionBar?.apply {
title = mediaData.filename
setHomeButtonEnabled(true)
setDisplayHomeAsUpEnabled(true)
}
}

companion object {

private const val EXTRA_MEDIA_DATA = "EXTRA_MEDIA_DATA"

fun newIntent(context: Context, mediaData: VideoContentRenderer.Data): Intent {
return Intent(context, VideoMediaViewerActivity::class.java).apply {
putExtra(EXTRA_MEDIA_DATA, mediaData)
}
}
}


}

View File

@ -6,7 +6,7 @@
android:orientation="vertical"> android:orientation="vertical">


<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/mediaViewerToolbar" android:id="@+id/imageMediaViewerToolbar"
style="@style/VectorToolbarStyle" style="@style/VectorToolbarStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
@ -15,7 +15,7 @@
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />


<com.github.piasy.biv.view.BigImageView <com.github.piasy.biv.view.BigImageView
android:id="@+id/mediaViewerImageView" android:id="@+id/imageMediaViewerImageView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:failureImageInitScaleType="center" app:failureImageInitScaleType="center"

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2019 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<androidx.appcompat.widget.Toolbar
android:id="@+id/videoMediaViewerToolbar"
style="@style/VectorToolbarStyle"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:id="@+id/videoMediaViewerThumbnailView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<VideoView
android:id="@+id/videoMediaViewerVideoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</FrameLayout>

</LinearLayout>