mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Simple overlay
This commit is contained in:
parent
2d4a728af4
commit
76133ab55e
8 changed files with 244 additions and 22 deletions
|
@ -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 {
|
||||
|
|
|
@ -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?
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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>'
|
||||
|
|
Loading…
Reference in a new issue