Simple overlay

This commit is contained in:
Valere 2020-07-06 15:47:15 +02:00
parent 2d4a728af4
commit 76133ab55e
8 changed files with 244 additions and 22 deletions

View file

@ -34,16 +34,12 @@ buildscript {
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {

View file

@ -16,6 +16,9 @@
package im.vector.riotx.attachment_viewer
import android.content.Context
import android.view.View
sealed class AttachmentInfo {
data class Image(val url: String, val data: Any?) : AttachmentInfo()
data class AnimatedImage(val url: String, val data: Any?) : AttachmentInfo()
@ -34,5 +37,8 @@ interface AttachmentSourceProvider {
fun getAttachmentInfoAt(position: Int): AttachmentInfo
fun loadImage(holder: ZoomableImageViewHolder, info: AttachmentInfo.Image)
fun loadImage(holder: AnimatedImageViewHolder, info: AttachmentInfo.AnimatedImage)
fun overlayViewAtPosition(context: Context, position: Int) : View?
}

View file

@ -25,7 +25,9 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.viewpager2.widget.ViewPager2
import kotlinx.android.synthetic.main.activity_attachment_viewer.*
import kotlin.math.abs
@ -36,8 +38,16 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
lateinit var imageTransitionView: ImageView
lateinit var transitionImageContainer: ViewGroup
// TODO
var topInset = 0
private var overlayView: View? = null
set(value) {
if (value == overlayView) return
overlayView?.let { rootContainer.removeView(it) }
rootContainer.addView(value)
value?.updatePadding(top = topInset)
field = value
}
private lateinit var swipeDismissHandler: SwipeToDismissHandler
private lateinit var directionDetector: SwipeDirectionDetector
@ -53,6 +63,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
private var wasScaled: Boolean = false
private var isSwipeToDismissAllowed: Boolean = true
private lateinit var attachmentsAdapter: AttachmentsAdapter
private var isOverlayWasClicked = false
// private val shouldDismissToBottom: Boolean
// get() = e == null
@ -67,6 +78,20 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This is important for the dispatchTouchEvent, if not we must correct
// the touch coordinates
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
// // clear FLAG_TRANSLUCENT_STATUS flag:
// window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//
//// add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
setContentView(R.layout.activity_attachment_viewer)
attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL
attachmentsAdapter = AttachmentsAdapter()
@ -83,6 +108,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
override fun onPageSelected(position: Int) {
currentPosition = position
overlayView = attachmentsAdapter.attachmentSourceProvider?.overlayViewAtPosition(this@AttachmentViewerActivity, position)
}
})
@ -92,6 +118,13 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
scaleDetector = createScaleGestureDetector()
ViewCompat.setOnApplyWindowInsetsListener(rootContainer) { _, insets ->
overlayView?.updatePadding(top = insets.systemWindowInsetTop)
topInset = insets.systemWindowInsetTop
insets
}
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
@ -99,9 +132,9 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
// The zoomable view is configured to disallow interception when image is zoomed
// Check if the overlay is visible, and wants to handle the click
// if (overlayView.isVisible && overlayView?.dispatchTouchEvent(event) == true) {
// return true
// }
if (overlayView?.isVisible == true && overlayView?.dispatchTouchEvent(ev) == true) {
return true
}
Log.v("ATTACHEMENTS", "================\ndispatchTouchEvent $ev")
@ -143,14 +176,14 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
attachmentPager.dispatchTouchEvent(event)
swipeDismissHandler.onTouch(rootContainer, event)
// isOverlayWasClicked = dispatchOverlayTouch(event)
isOverlayWasClicked = dispatchOverlayTouch(event)
}
private fun handleEventActionUp(event: MotionEvent) {
// wasDoubleTapped = false
swipeDismissHandler.onTouch(rootContainer, event)
attachmentPager.dispatchTouchEvent(event)
// isOverlayWasClicked = dispatchOverlayTouch(event)
isOverlayWasClicked = dispatchOverlayTouch(event)
}
private fun handleTouchIfNotScaled(event: MotionEvent): Boolean {
@ -159,7 +192,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
directionDetector.handleTouchEvent(event)
return when (swipeDirection) {
SwipeDirection.Up, SwipeDirection.Down -> {
SwipeDirection.Up, SwipeDirection.Down -> {
if (isSwipeToDismissAllowed && !wasScaled && isImagePagerIdle) {
swipeDismissHandler.onTouch(rootContainer, event)
} else true
@ -167,7 +200,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity() {
SwipeDirection.Left, SwipeDirection.Right -> {
attachmentPager.dispatchTouchEvent(event)
}
else -> true
else -> true
}
}

View file

@ -0,0 +1,58 @@
/*
* 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.Color
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import im.vector.riotx.R
import im.vector.riotx.attachment_viewer.AttachmentInfo
class AttachmentOverlayView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
var onShareCallback: (() -> Unit) ? = null
var onBack: (() -> Unit) ? = null
private val counterTextView: TextView
private val infoTextView: TextView
private val shareImage: ImageView
init {
View.inflate(context, R.layout.merge_image_attachment_overlay, this)
setBackgroundColor(Color.TRANSPARENT)
counterTextView = findViewById(R.id.overlayCounterText)
infoTextView = findViewById(R.id.overlayInfoText)
shareImage = findViewById(R.id.overlayShareButton)
findViewById<ImageView>(R.id.overlayBackButton).setOnClickListener {
onBack?.invoke()
}
}
fun updateWith(counter: String, senderInfo : String) {
counterTextView.text = counter
infoTextView.text = senderInfo
}
}

View file

@ -16,7 +16,9 @@
package im.vector.riotx.features.media
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.View
import com.bumptech.glide.request.target.CustomViewTarget
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.MessageContent
@ -28,14 +30,26 @@ import im.vector.riotx.attachment_viewer.AnimatedImageViewHolder
import im.vector.riotx.attachment_viewer.AttachmentInfo
import im.vector.riotx.attachment_viewer.AttachmentSourceProvider
import im.vector.riotx.attachment_viewer.ZoomableImageViewHolder
import im.vector.riotx.core.date.VectorDateFormatter
import im.vector.riotx.core.extensions.localDateTime
import javax.inject.Inject
class RoomAttachmentProvider(
private val attachments: List<TimelineEvent>,
private val initialIndex: Int,
private val imageContentRenderer: ImageContentRenderer
private val imageContentRenderer: ImageContentRenderer,
private val dateFormatter: VectorDateFormatter
) : AttachmentSourceProvider {
interface InteractionListener {
fun onDismissTapped()
fun onShareTapped()
}
var interactionListener: InteractionListener? = null
private var overlayView: AttachmentOverlayView? = null
override fun getItemCount(): Int {
return attachments.size
}
@ -79,6 +93,26 @@ class RoomAttachmentProvider(
imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>)
}
}
override fun overlayViewAtPosition(context: Context, position: Int): View? {
if (overlayView == null) {
overlayView = AttachmentOverlayView(context)
overlayView?.onBack = {
interactionListener?.onDismissTapped()
}
overlayView?.onShareCallback = {
interactionListener?.onShareTapped()
}
}
val item = attachments[position]
val dateString = item.root.localDateTime().let {
"${dateFormatter.formatMessageDay(it)} at ${dateFormatter.formatMessageHour(it)} "
}
overlayView?.updateWith("${position + 1} of ${attachments.size}","${item.senderInfo.displayName} $dateString" )
return overlayView
}
// override fun loadImage(holder: ImageViewHolder, info: AttachmentInfo.Image) {
// (info.data as? ImageContentRenderer.Data)?.let {
// imageContentRenderer.render(it, ImageContentRenderer.Mode.FULL_SIZE, holder.touchImageView)
@ -87,10 +121,11 @@ class RoomAttachmentProvider(
}
class RoomAttachmentProviderFactory @Inject constructor(
private val imageContentRenderer: ImageContentRenderer
private val imageContentRenderer: ImageContentRenderer,
private val vectorDateFormatter: VectorDateFormatter
) {
fun createProvider(attachments: List<TimelineEvent>, initialIndex: Int): RoomAttachmentProvider {
return RoomAttachmentProvider(attachments, initialIndex, imageContentRenderer)
return RoomAttachmentProvider(attachments, initialIndex, imageContentRenderer, vectorDateFormatter)
}
}

View file

@ -22,17 +22,15 @@ import android.os.Parcelable
import android.view.View
import android.view.ViewTreeObserver
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.transition.addListener
import androidx.core.view.ViewCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.transition.Transition
import im.vector.riotx.R
import im.vector.riotx.attachment_viewer.AttachmentViewerActivity
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.di.DaggerScreenComponent
import im.vector.riotx.core.di.HasVectorInjector
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.di.VectorComponent
import im.vector.riotx.core.di.*
import im.vector.riotx.features.themes.ActivityOtherThemes
import im.vector.riotx.features.themes.ThemeUtils
import kotlinx.android.parcel.Parcelize
@ -40,7 +38,7 @@ import timber.log.Timber
import javax.inject.Inject
import kotlin.system.measureTimeMillis
class VectorAttachmentViewerActivity : AttachmentViewerActivity() {
class VectorAttachmentViewerActivity : AttachmentViewerActivity(), RoomAttachmentProvider.InteractionListener {
@Parcelize
data class Args(
@ -103,11 +101,15 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity() {
}
}
setSourceProvider(dataSourceFactory.createProvider(events, index))
val sourceProvider = dataSourceFactory.createProvider(events, index)
sourceProvider.interactionListener = this
setSourceProvider(sourceProvider)
if (savedInstanceState == null) {
pager2.setCurrentItem(index, false)
}
window.statusBarColor = ContextCompat.getColor(this, R.color.black_alpha)
}
private fun getOtherThemes() = ActivityOtherThemes.VectorAttachmentsPreview
@ -204,4 +206,12 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity() {
}
}
override fun onDismissTapped() {
animateClose()
}
override fun onShareTapped() {
TODO("Not yet implemented")
}
}

View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<View
android:id="@+id/overlayTopBackground"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@color/black_alpha">
</View>
<ImageView
android:id="@+id/overlayBackButton"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:scaleType="centerInside"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/share"
android:padding="6dp"
android:tint="@color/white"
app:layout_constraintBottom_toBottomOf="@id/overlayTopBackground"
app:layout_constraintStart_toStartOf="@id/overlayTopBackground"
app:layout_constraintTop_toTopOf="@id/overlayTopBackground"
app:srcCompat="@drawable/ic_back_24dp" />
<TextView
android:id="@+id/overlayCounterText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/overlayInfoText"
app:layout_constraintEnd_toStartOf="@id/overlayShareButton"
app:layout_constraintStart_toEndOf="@id/overlayBackButton"
app:layout_constraintTop_toTopOf="@id/overlayTopBackground"
app:layout_constraintVertical_chainStyle="packed"
tools:text="1 of 200" />
<TextView
android:id="@+id/overlayInfoText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@id/overlayTopBackground"
app:layout_constraintEnd_toStartOf="@id/overlayShareButton"
app:layout_constraintStart_toStartOf="@id/overlayCounterText"
app:layout_constraintTop_toBottomOf="@id/overlayCounterText"
tools:text="Bill 29 Jun at 19:42" />
<ImageView
android:id="@+id/overlayShareButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/share"
android:padding="6dp"
android:tint="@color/white"
app:layout_constraintBottom_toBottomOf="@id/overlayTopBackground"
app:layout_constraintEnd_toEndOf="@id/overlayTopBackground"
app:layout_constraintTop_toTopOf="@id/overlayTopBackground"
app:srcCompat="@drawable/ic_share" />
</merge>

View file

@ -40,6 +40,7 @@
<!-- Other usefull color -->
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="black_alpha">#55000000</color>
<!-- Palette: format fo naming:
'riotx_<name in the palette snake case>_<theme>'