diff --git a/app/build.gradle b/app/build.gradle
index 58cc5e064f..570cf611ce 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,7 +27,7 @@ def generateVersionCodeFromVersionName() {
project.android.buildTypes.all { buildType ->
buildType.javaCompileOptions.annotationProcessorOptions.arguments =
[
- validateEpoxyModelUsage : String.valueOf(buildType.name == 'debug')
+ validateEpoxyModelUsage: String.valueOf(buildType.name == 'debug')
]
}
@@ -62,6 +62,8 @@ dependencies {
def arrow_version = "0.8.2"
def coroutines_version = "1.0.1"
def markwon_version = '3.0.0-SNAPSHOT'
+ def big_image_viewer_version = '1.5.6'
+ def glide_version = '4.8.0'
implementation project(":matrix-sdk-android")
implementation project(":matrix-sdk-android-rx")
@@ -96,14 +98,19 @@ dependencies {
implementation "io.arrow-kt:arrow-core:$arrow_version"
// UI
- implementation 'com.github.bumptech.glide:glide:4.8.0'
- kapt 'com.github.bumptech.glide:compiler:4.8.0'
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation 'com.google.android.material:material:1.1.0-alpha02'
implementation 'me.gujun.android:span:1.7'
implementation "ru.noties.markwon:core:$markwon_version"
implementation "ru.noties.markwon:html:$markwon_version"
+ // Image Loading
+ implementation "com.github.piasy:BigImageViewer:$big_image_viewer_version"
+ implementation "com.github.piasy:GlideImageLoader:$big_image_viewer_version"
+ implementation "com.github.piasy:ProgressPieIndicator:$big_image_viewer_version"
+ implementation "com.github.piasy:GlideImageViewFactory:$big_image_viewer_version"
+ implementation "com.github.bumptech.glide:glide:$glide_version"
+ kapt "com.github.bumptech.glide:compiler:$glide_version"
// DI
implementation "org.koin:koin-android:$koin_version"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 05b64b0ee3..5958432633 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -26,6 +26,7 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/Riot.kt b/app/src/main/java/im/vector/riotredesign/Riot.kt
index 9a82a20fec..9332eec737 100644
--- a/app/src/main/java/im/vector/riotredesign/Riot.kt
+++ b/app/src/main/java/im/vector/riotredesign/Riot.kt
@@ -20,6 +20,8 @@ import android.app.Application
import android.content.Context
import androidx.multidex.MultiDex
import com.facebook.stetho.Stetho
+import com.github.piasy.biv.BigImageViewer
+import com.github.piasy.biv.loader.glide.GlideImageLoader
import com.jakewharton.threetenabp.AndroidThreeTen
import im.vector.matrix.android.BuildConfig
import im.vector.riotredesign.core.di.AppModule
@@ -38,6 +40,7 @@ class Riot : Application() {
Stetho.initializeWithDefaults(this)
}
AndroidThreeTen.init(this)
+ BigImageViewer.initialize(GlideImageLoader.with(applicationContext))
val appModule = AppModule(applicationContext).definition
val homeModule = HomeModule().definition
startKoin(listOf(appModule, homeModule), logger = EmptyLogger())
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
index a72758e9b2..4574cdb685 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
@@ -36,6 +36,8 @@ import im.vector.riotredesign.features.home.HomeModule
import im.vector.riotredesign.features.home.HomePermalinkHandler
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotredesign.features.home.room.detail.timeline.animation.TimelineItemAnimator
+import im.vector.riotredesign.features.media.MediaContentRenderer
+import im.vector.riotredesign.features.media.MediaViewerActivity
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_detail.*
import org.koin.android.ext.android.inject
@@ -164,4 +166,9 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
roomDetailViewModel.process(RoomDetailActions.EventDisplayed(event, index))
}
+ override fun onMediaClicked(mediaData: MediaContentRenderer.Data) {
+ val intent = MediaViewerActivity.newIntent(riotActivity, mediaData)
+ startActivity(intent)
+ }
+
}
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt
index ce89fda61f..a18900bac7 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt
@@ -31,6 +31,7 @@ import im.vector.riotredesign.features.home.room.detail.timeline.helper.Timeline
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem_
import im.vector.riotredesign.features.home.room.detail.timeline.paging.PagedListEpoxyController
+import im.vector.riotredesign.features.media.MediaContentRenderer
class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
private val timelineItemFactory: TimelineItemFactory,
@@ -102,6 +103,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
interface Callback {
fun onEventVisible(event: TimelineEvent, index: Int)
fun onUrlClicked(url: String)
+ fun onMediaClicked(mediaData: MediaContentRenderer.Data)
}
}
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt
index 4d3104c8c3..cde54929af 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt
@@ -23,26 +23,16 @@ import im.vector.matrix.android.api.permalinks.MatrixLinkify
import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
-import im.vector.matrix.android.api.session.room.model.message.MessageContent
-import im.vector.matrix.android.api.session.room.model.message.MessageEmoteContent
-import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
-import im.vector.matrix.android.api.session.room.model.message.MessageNoticeContent
-import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
+import im.vector.matrix.android.api.session.room.model.message.*
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
import im.vector.riotredesign.core.extensions.localDateTime
import im.vector.riotredesign.core.resources.ColorProvider
-import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
+import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
-import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem
-import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem_
-import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageItem
-import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageItem_
-import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
-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.home.room.detail.timeline.item.*
import im.vector.riotredesign.features.html.EventHtmlRenderer
import im.vector.riotredesign.features.media.MediaContentRenderer
import me.gujun.android.span.span
@@ -84,7 +74,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
return when (messageContent) {
is MessageTextContent -> buildTextMessageItem(messageContent, informationData, callback)
- is MessageImageContent -> buildImageMessageItem(messageContent, informationData)
+ is MessageImageContent -> buildImageMessageItem(messageContent, informationData, callback)
is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, callback)
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, callback)
else -> buildNotHandledMessageItem(messageContent)
@@ -97,10 +87,12 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
}
private fun buildImageMessageItem(messageContent: MessageImageContent,
- informationData: MessageInformationData): MessageImageItem? {
+ informationData: MessageInformationData,
+ callback: TimelineEventController.Callback?): MessageImageItem? {
val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
val data = MediaContentRenderer.Data(
+ messageContent.body,
url = messageContent.url,
height = messageContent.info?.height,
maxHeight = maxHeight,
@@ -112,6 +104,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
return MessageImageItem_()
.informationData(informationData)
.mediaData(data)
+ .clickListener { callback?.onMediaClicked(data) }
}
private fun buildTextMessageItem(messageContent: MessageTextContent,
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageImageItem.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageImageItem.kt
index 56d06c38dd..2156f48389 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageImageItem.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageImageItem.kt
@@ -28,10 +28,12 @@ abstract class MessageImageItem : AbsMessageItem() {
@EpoxyAttribute lateinit var mediaData: MediaContentRenderer.Data
@EpoxyAttribute override lateinit var informationData: MessageInformationData
+ @EpoxyAttribute var clickListener: (() -> Unit)? = null
override fun bind(holder: Holder) {
super.bind(holder)
MediaContentRenderer.render(mediaData, MediaContentRenderer.Mode.THUMBNAIL, holder.imageView)
+ holder.imageView.setOnClickListener { clickListener?.invoke() }
}
class Holder : AbsMessageItem.Holder() {
diff --git a/app/src/main/java/im/vector/riotredesign/features/media/MediaContentRenderer.kt b/app/src/main/java/im/vector/riotredesign/features/media/MediaContentRenderer.kt
index 9a97ad6b2d..86501199c3 100644
--- a/app/src/main/java/im/vector/riotredesign/features/media/MediaContentRenderer.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/media/MediaContentRenderer.kt
@@ -17,14 +17,20 @@
package im.vector.riotredesign.features.media
import android.media.ExifInterface
+import android.net.Uri
+import android.os.Parcelable
import android.widget.ImageView
+import com.github.piasy.biv.view.BigImageView
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.riotredesign.core.glide.GlideApp
+import kotlinx.android.parcel.Parcelize
object MediaContentRenderer {
+ @Parcelize
data class Data(
+ val filename: String,
val url: String?,
val height: Int?,
val maxHeight: Int,
@@ -32,7 +38,7 @@ object MediaContentRenderer {
val maxWidth: Int,
val orientation: Int?,
val rotation: Int?
- )
+ ) : Parcelable
enum class Mode {
FULL_SIZE,
@@ -43,13 +49,11 @@ object MediaContentRenderer {
val (width, height) = processSize(data, mode)
imageView.layoutParams.height = height
imageView.layoutParams.width = width
-
val contentUrlResolver = Matrix.getInstance().currentSession.contentUrlResolver()
val resolvedUrl = when (mode) {
- Mode.FULL_SIZE -> contentUrlResolver.resolveFullSize(data.url)
- Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE)
- }
- ?: return
+ Mode.FULL_SIZE -> contentUrlResolver.resolveFullSize(data.url)
+ Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE)
+ } ?: return
GlideApp
.with(imageView)
@@ -58,6 +62,17 @@ object MediaContentRenderer {
.into(imageView)
}
+ fun render(data: Data, imageView: BigImageView) {
+ val (width, height) = processSize(data, Mode.THUMBNAIL)
+ val contentUrlResolver = Matrix.getInstance().currentSession.contentUrlResolver()
+ val fullSize = contentUrlResolver.resolveFullSize(data.url)
+ val thumbnail = contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE)
+ imageView.showImage(
+ Uri.parse(thumbnail),
+ Uri.parse(fullSize)
+ )
+ }
+
private fun processSize(data: Data, mode: Mode): Pair {
val maxImageWidth = data.maxWidth
val maxImageHeight = data.maxHeight
diff --git a/app/src/main/java/im/vector/riotredesign/features/media/MediaViewerActivity.kt b/app/src/main/java/im/vector/riotredesign/features/media/MediaViewerActivity.kt
new file mode 100644
index 0000000000..2b3ae6f697
--- /dev/null
+++ b/app/src/main/java/im/vector/riotredesign/features/media/MediaViewerActivity.kt
@@ -0,0 +1,80 @@
+/*
+ *
+ * * 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 android.view.MenuItem
+import androidx.appcompat.widget.Toolbar
+import com.github.piasy.biv.indicator.progresspie.ProgressPieIndicator
+import com.github.piasy.biv.view.GlideImageViewFactory
+import im.vector.riotredesign.core.platform.RiotActivity
+import kotlinx.android.synthetic.main.activity_media_viewer.*
+
+
+class MediaViewerActivity : RiotActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(im.vector.riotredesign.R.layout.activity_media_viewer)
+ val mediaData = intent.getParcelableExtra(EXTRA_MEDIA_DATA)
+ if (mediaData.url.isNullOrEmpty()) {
+ finish()
+ } else {
+ configureToolbar(mediaViewerToolbar, mediaData)
+ mediaViewerImageView.setImageViewFactory(GlideImageViewFactory())
+ mediaViewerImageView.setProgressIndicator(ProgressPieIndicator())
+ MediaContentRenderer.render(mediaData, mediaViewerImageView)
+ }
+ }
+
+ private fun configureToolbar(toolbar: Toolbar, mediaData: MediaContentRenderer.Data) {
+ setSupportActionBar(toolbar)
+ supportActionBar?.apply {
+ title = mediaData.filename
+ setHomeButtonEnabled(true)
+ setDisplayHomeAsUpEnabled(true)
+ }
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ android.R.id.home -> {
+ finish()
+ return true
+ }
+ }
+ return true
+ }
+
+
+ companion object {
+
+ private const val EXTRA_MEDIA_DATA = "EXTRA_MEDIA_DATA"
+
+ fun newIntent(context: Context, mediaData: MediaContentRenderer.Data): Intent {
+ return Intent(context, MediaViewerActivity::class.java).apply {
+ putExtra(EXTRA_MEDIA_DATA, mediaData)
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_media_viewer.xml b/app/src/main/res/layout/activity_media_viewer.xml
new file mode 100644
index 0000000000..b3156f1478
--- /dev/null
+++ b/app/src/main/res/layout/activity_media_viewer.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index af25b46084..226ca00ecb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -19,10 +19,11 @@ buildscript {
allprojects {
repositories {
- google()
- jcenter()
+ maven { url "http://dl.bintray.com/piasy/maven" }
maven { url 'https://jitpack.io' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
+ google()
+ jcenter()
}
}