Open album in full screen

This commit is contained in:
Matthieu 2022-06-09 19:29:26 +02:00
parent 52cefe63aa
commit 4806dc4a06
11 changed files with 222 additions and 257 deletions

View File

@ -142,6 +142,8 @@ dependencies {
// CameraX View class
implementation "androidx.camera:camera-view:$cameraX_version"
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"

View File

@ -6,7 +6,6 @@ import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.openLinkWithText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition
import androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition
@ -24,9 +23,6 @@ import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
import org.junit.rules.Timeout
import org.junit.runner.Description
import org.junit.runner.RunWith
import org.junit.runners.model.Statement
@ -68,22 +64,22 @@ class HomeFeedTest {
@RepeatTest
fun clickingTabOnAlbumShowsNextPhoto() {
//Wait for the feed to load
waitForView(R.id.postPager)
waitForView(R.id.albumPager)
activityScenario.onActivity {
a -> run {
//Pick the second photo
a.findViewById<ViewPager2>(R.id.postPager).currentItem = 2
a.findViewById<ViewPager2>(R.id.albumPager).currentItem = 2
}
}
onView(first(withId(R.id.postPager))).check(matches(isDisplayed()))
onView(first(withId(R.id.albumPager))).check(matches(isDisplayed()))
}
@Test
@RepeatTest
fun tabReClickScrollUp() {
//Wait for the feed to load
waitForView(R.id.postPager)
waitForView(R.id.albumPager)
onView(withId(R.id.list)).perform(scrollToPosition<StatusViewHolder>(4))
@ -97,7 +93,7 @@ class HomeFeedTest {
@RepeatTest
fun hashtag() {
//Wait for the feed to load
waitForView(R.id.postPager)
waitForView(R.id.albumPager)
onView(allOf(withClassName(endsWith("RecyclerView")), not(withId(R.id.material_drawer_recycler_view))))
.perform(

View File

@ -23,9 +23,13 @@
android:theme="@style/AppTheme"
tools:replace="android:allowBackup">
<activity
android:name=".posts.MediaViewerActivity"
android:name=".posts.AlbumActivity"
android:exported="false"
android:theme="@style/AppTheme.ActionBar.Transparent"/>
<activity
android:name=".posts.MediaViewerActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="false"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".postCreation.camera.CameraActivity" />
<activity

View File

@ -0,0 +1,38 @@
package org.pixeldroid.app.posts
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import org.pixeldroid.app.databinding.ActivityAlbumBinding
import org.pixeldroid.app.utils.BaseActivity
import org.pixeldroid.app.utils.api.objects.Attachment
class AlbumActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityAlbumBinding.inflate(layoutInflater)
setContentView(binding.root)
val mediaAttachments = intent.getSerializableExtra("images") as ArrayList<Attachment>
binding.albumPager.adapter = AlbumViewPagerAdapter(mediaAttachments,
sensitive = false,
opened = true)
if(mediaAttachments.size == 1){
binding.albumPager.isUserInputEnabled = false
}
else if((mediaAttachments.size) > 1) {
binding.postIndicator.setViewPager(binding.albumPager)
binding.postIndicator.visibility = View.VISIBLE
} else {
binding.postIndicator.visibility = View.GONE
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
supportActionBar?.setBackgroundDrawable(null)
window.statusBarColor = ContextCompat.getColor(this,android.R.color.transparent);
}
}

View File

@ -7,6 +7,7 @@ import android.media.AudioManager.STREAM_MUSIC
import android.os.Bundle
import androidx.core.net.toUri
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat.getInsetsController
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.media.AudioAttributesCompat
@ -50,19 +51,19 @@ class MediaViewerActivity : BaseActivity() {
mediaPlayer.setMediaItem(mediaItem)
binding.videoView.mediaControlView?.setOnFullScreenListener{ view, fullscreen ->
val windowInsetsController = ViewCompat.getWindowInsetsController(window.decorView)
val windowInsetsController = getInsetsController(window, window.decorView)
if (!fullscreen) {
// Configure the behavior of the hidden system bars
windowInsetsController?.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Hide both the status bar and the navigation bar
windowInsetsController?.show(WindowInsetsCompat.Type.systemBars())
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
supportActionBar?.show()
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
} else {
// Configure the behavior of the hidden system bars
windowInsetsController?.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Hide both the status bar and the navigation bar
windowInsetsController?.hide(WindowInsetsCompat.Type.systemBars())
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
requestedOrientation =
if (mediaPlayer.videoSize.height < mediaPlayer.videoSize.width) {

View File

@ -1,32 +1,17 @@
/*
* Copyright 2019 The Android Open Source Project
*
* 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 org.pixeldroid.app.posts
import android.content.Context
import android.content.Intent
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import android.widget.Toast
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.GestureDetectorCompat
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
import org.pixeldroid.app.utils.api.objects.Attachment
import kotlin.math.absoluteValue
import kotlin.math.sign
@ -53,6 +38,7 @@ class NestedScrollableHost(context: Context, attrs: AttributeSet? = null) :
}
var images: ArrayList<Attachment> = ArrayList();
var doubleTapCallback: (() -> Unit)? = null
private val child: View? get() = if (childCount > 0) getChildAt(0) else null
@ -96,8 +82,16 @@ class NestedScrollableHost(context: Context, attrs: AttributeSet? = null) :
}
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
//TODO open image full screen
Toast.makeText(this@NestedScrollableHost.context, "yay you did it", Toast.LENGTH_SHORT).show()
// Disable opening AlbumActivity if the only image is a video (let the video open directly)
if(images.size == 1 && images.first().type == Attachment.AttachmentType.video){
return super.onSingleTapConfirmed(e)
}
val intent = Intent(context, AlbumActivity::class.java)
intent.putExtra("images", images)
context.startActivity(intent)
return super.onSingleTapConfirmed(e)
}
override fun onScroll(

View File

@ -1,27 +1,46 @@
package org.pixeldroid.app.posts
import android.Manifest
import android.app.Activity
import android.app.AlertDialog
import android.content.Intent
import android.graphics.Typeface
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
import android.net.Uri
import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.recyclerview.widget.RecyclerView
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import androidx.viewbinding.ViewBinding
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.target.CustomViewTarget
import com.bumptech.glide.request.transition.Transition
import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.snackbar.Snackbar
import com.karumi.dexter.Dexter
import com.karumi.dexter.listener.PermissionDeniedResponse
import com.karumi.dexter.listener.PermissionGrantedResponse
import com.karumi.dexter.listener.single.BasePermissionListener
import kotlinx.coroutines.launch
import org.pixeldroid.app.R
import org.pixeldroid.app.databinding.AlbumImageViewBinding
import org.pixeldroid.app.databinding.OpenedAlbumBinding
import org.pixeldroid.app.databinding.PostFragmentBinding
import org.pixeldroid.app.posts.MediaViewerActivity.Companion.openActivity
import org.pixeldroid.app.utils.BlurHashDecoder
import org.pixeldroid.app.utils.ImageConverter
import org.pixeldroid.app.utils.api.PixelfedAPI
@ -32,15 +51,8 @@ import org.pixeldroid.app.utils.api.objects.Status.Companion.POST_TAG
import org.pixeldroid.app.utils.api.objects.Status.Companion.VIEW_COMMENTS_TAG
import org.pixeldroid.app.utils.db.AppDatabase
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
import com.karumi.dexter.Dexter
import com.karumi.dexter.listener.PermissionDeniedResponse
import com.karumi.dexter.listener.PermissionGrantedResponse
import com.karumi.dexter.listener.single.BasePermissionListener
import kotlinx.coroutines.launch
import org.pixeldroid.app.posts.MediaViewerActivity.Companion.VIDEO_DESCRIPTION_TAG
import org.pixeldroid.app.posts.MediaViewerActivity.Companion.VIDEO_URL_TAG
import org.pixeldroid.app.posts.MediaViewerActivity.Companion.openActivity
import retrofit2.HttpException
import java.io.File
import java.io.IOException
import kotlin.math.roundToInt
@ -88,7 +100,7 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
private fun setupPost(
request: RequestBuilder<Drawable>,
domain: String,
isActivity: Boolean
isActivity: Boolean,
) {
//Setup username as a button that opens the profile
binding.username.apply {
@ -148,9 +160,9 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
binding.postPager.visibility = View.VISIBLE
//Attach the given tabs to the view pager
binding.postPager.adapter = AlbumViewPagerAdapter(status?.media_attachments ?: emptyList(), status?.sensitive)
binding.postPager.adapter = AlbumViewPagerAdapter(status?.media_attachments ?: emptyList(), status?.sensitive, false)
if(status?.media_attachments?.size ?: 0 > 1) {
if((status?.media_attachments?.size ?: 0) > 1) {
binding.postIndicator.setViewPager(binding.postPager)
binding.postIndicator.visibility = View.VISIBLE
} else {
@ -206,7 +218,7 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
apiHolder: PixelfedAPIHolder,
db: AppDatabase,
lifecycleScope: LifecycleCoroutineScope,
isActivity: Boolean
isActivity: Boolean,
){
//Set the special HTML text
setDescription(apiHolder, lifecycleScope)
@ -459,7 +471,7 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
}
}
//Activate double tap liking
//Activate tap interactions (double and single)
binding.postPagerHost.doubleTapCallback = {
lifecycleScope.launchWhenCreated {
//Check that the post isn't hidden
@ -479,6 +491,8 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
}
}
}
status?.media_attachments?.let { binding.postPagerHost.images = ArrayList(it) }
}
private fun ImageView.animateView() {
visibility = View.VISIBLE
@ -534,8 +548,8 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
//endregion
private fun showComments(
lifecycleScope: LifecycleCoroutineScope,
isActivity: Boolean
lifecycleScope: LifecycleCoroutineScope,
isActivity: Boolean,
) {
//Show number of comments on the post
if (status?.replies_count == 0) {
@ -574,14 +588,20 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
}
}
private class AlbumViewPagerAdapter(private val media_attachments: List<Attachment>, private var sensitive: Boolean?) :
class AlbumViewPagerAdapter(
private val media_attachments: List<Attachment>, private var sensitive: Boolean?,
private val opened: Boolean, //TODO if opened don't open again, and use PhotoView instead of shite
) :
RecyclerView.Adapter<AlbumViewPagerAdapter.ViewHolder>() {
private var isActionBarHidden: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemBinding = AlbumImageViewBinding.inflate(
return if(!opened) ViewHolderClosed(AlbumImageViewBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return ViewHolder(itemBinding)
)) else ViewHolderOpen(OpenedAlbumBinding.inflate(
LayoutInflater.from(parent.context), parent, false
))
}
override fun getItemCount() = media_attachments.size
@ -598,19 +618,53 @@ private class AlbumViewPagerAdapter(private val media_attachments: List<Attachme
}
if (sensitive == false) {
val imageUrl = if(video) preview_url else url
Glide.with(holder.binding.root)
if(opened){
Glide.with(holder.binding.root)
.download(GlideUrl(imageUrl))
.into(object : CustomViewTarget<SubsamplingScaleImageView, File>((holder.image as SubsamplingScaleImageView)) {
override fun onResourceReady(resource: File, t: Transition<in File>?) =
view.setImage(ImageSource.uri(Uri.fromFile(resource)))
override fun onLoadFailed(errorDrawable: Drawable?) {}
override fun onResourceCleared(placeholder: Drawable?) {}
})
(holder.image as SubsamplingScaleImageView).apply {
setMinimumDpi(80)
setDoubleTapZoomDpi(240)
resetScaleAndCenter()
}
holder.image.setOnClickListener {
val windowInsetsController = WindowCompat.getInsetsController((it.context as Activity).window, it)
// Configure the behavior of the hidden system bars
if (isActionBarHidden) {
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Hide both the status bar and the navigation bar
(it.context as AppCompatActivity).supportActionBar?.show()
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
isActionBarHidden = false
} else {
// Configure the behavior of the hidden system bars
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Hide both the status bar and the navigation bar
(it.context as AppCompatActivity).supportActionBar?.hide()
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
isActionBarHidden = true
}
}
}
else Glide.with(holder.binding.root)
.asDrawable().fitCenter()
.placeholder(blurhashBitMap)
.load(imageUrl).into(holder.image)
} else {
.load(imageUrl).into(holder.image as ImageView)
} else if(!opened){
Glide.with(holder.binding.root)
.asDrawable().fitCenter()
.load(blurhashBitMap).into(holder.image)
.load(blurhashBitMap).into(holder.image as ImageView)
}
holder.videoPlayButton.visibility = if(video) View.VISIBLE else View.GONE
if(video){
if(video && (opened || media_attachments.size == 1)){
holder.videoPlayButton.setOnClickListener {
openActivity(holder.binding.root.context, url, description)
}
@ -636,9 +690,17 @@ private class AlbumViewPagerAdapter(private val media_attachments: List<Attachme
sensitive = false
notifyDataSetChanged()
}
abstract class ViewHolder(open val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root){
abstract val image: View
abstract val videoPlayButton: ImageView
}
class ViewHolder(val binding: AlbumImageViewBinding) : RecyclerView.ViewHolder(binding.root){
val image: ImageView = binding.imageImageView
val videoPlayButton: ImageView = binding.videoPlayButton
class ViewHolderOpen(override val binding: OpenedAlbumBinding) : ViewHolder(binding) {
override val image: SubsamplingScaleImageView = binding.imageImageView
override val videoPlayButton: ImageView = binding.videoPlayButton
}
class ViewHolderClosed(override val binding: AlbumImageViewBinding) : ViewHolder(binding) {
override val image: ImageView = binding.imageImageView
override val videoPlayButton: ImageView = binding.videoPlayButton
}
}

View File

@ -1,196 +0,0 @@
package org.pixeldroid.app.posts
import android.content.Context
import android.graphics.Matrix
import androidx.appcompat.widget.AppCompatImageView
import android.graphics.PointF
import android.view.ScaleGestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener
import android.util.AttributeSet
import android.util.Log
import kotlin.math.abs
import kotlin.math.min
// See https://stackoverflow.com/a/29030243
class TouchImageView(context: Context, attrs: AttributeSet? = null) :
AppCompatImageView(context, attrs) {
var touchMatrix: Matrix? = Matrix()
var mode = NONE
// Remember some things for zooming
var last = PointF()
var start = PointF()
var minScale = 1f
var maxScale = 3f
var m: FloatArray = FloatArray(9)
var viewWidth = 0
var viewHeight = 0
var saveScale = 1f
private var origWidth = 0f
private var origHeight = 0f
var oldMeasuredWidth = 0
var oldMeasuredHeight = 0
var mScaleDetector: ScaleGestureDetector? = null
init {
super.setClickable(true)
mScaleDetector = ScaleGestureDetector(context, ScaleListener())
imageMatrix = touchMatrix
scaleType = ScaleType.MATRIX
setOnTouchListener { _, event ->
mScaleDetector!!.onTouchEvent(event)
val curr = PointF(event.x, event.y)
when (event.action) {
MotionEvent.ACTION_MOVE -> if (mode == DRAG) {
val deltaX = curr.x - last.x
val deltaY = curr.y - last.y
val fixTransX =
getFixDragTrans(deltaX, viewWidth.toFloat(), origWidth * saveScale)
val fixTransY =
getFixDragTrans(deltaY, viewHeight.toFloat(), origHeight * saveScale)
touchMatrix!!.postTranslate(fixTransX, fixTransY)
fixTrans()
last[curr.x] = curr.y
val transX = m[Matrix.MTRANS_X]
if ((getFixTrans(transX,
viewWidth.toFloat(),
origWidth * saveScale) + fixTransX).toInt() == 0
) startInterceptEvent() else stopInterceptEvent()
}
MotionEvent.ACTION_DOWN -> {
last.set(curr)
start.set(last)
mode = DRAG
stopInterceptEvent()
}
MotionEvent.ACTION_UP -> {
mode = NONE
val xDiff = abs(curr.x - start.x).toInt()
val yDiff = abs(curr.y - start.y).toInt()
if (xDiff < CLICK && yDiff < CLICK) performClick()
startInterceptEvent()
}
MotionEvent.ACTION_POINTER_UP -> mode = NONE
}
imageMatrix = touchMatrix
invalidate()
true // indicate event was handled
}
}
private fun startInterceptEvent() {
parent.requestDisallowInterceptTouchEvent(false)
}
private fun stopInterceptEvent() {
parent.requestDisallowInterceptTouchEvent(true)
}
fun setMaxZoom(x: Float) {
maxScale = x
}
private inner class ScaleListener : SimpleOnScaleGestureListener() {
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
mode = ZOOM
return true
}
override fun onScale(detector: ScaleGestureDetector): Boolean {
var mScaleFactor = detector.scaleFactor
val origScale = saveScale
saveScale *= mScaleFactor
if (saveScale > maxScale) {
saveScale = maxScale
mScaleFactor = maxScale / origScale
} else if (saveScale < minScale) {
saveScale = minScale
mScaleFactor = minScale / origScale
}
if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight) touchMatrix!!.postScale(
mScaleFactor,
mScaleFactor,
(viewWidth / 2).toFloat(),
(viewHeight / 2).toFloat()) else touchMatrix!!.postScale(mScaleFactor,
mScaleFactor,
detector.focusX,
detector.focusY)
fixTrans()
return true
}
}
fun fixTrans() {
touchMatrix!!.getValues(m)
val transX = m[Matrix.MTRANS_X]
val transY = m[Matrix.MTRANS_Y]
val fixTransX = getFixTrans(transX, viewWidth.toFloat(), origWidth * saveScale)
val fixTransY = getFixTrans(transY, viewHeight.toFloat(), origHeight * saveScale)
if (fixTransX != 0f || fixTransY != 0f) touchMatrix!!.postTranslate(fixTransX, fixTransY)
}
fun getFixTrans(trans: Float, viewSize: Float, contentSize: Float): Float {
val minTrans: Float
val maxTrans: Float
if (contentSize <= viewSize) {
minTrans = 0f
maxTrans = viewSize - contentSize
} else {
minTrans = viewSize - contentSize
maxTrans = 0f
}
if (trans < minTrans) return -trans + minTrans
return if (trans > maxTrans) -trans + maxTrans else 0f
}
fun getFixDragTrans(delta: Float, viewSize: Float, contentSize: Float): Float {
return if (contentSize <= viewSize) {
0f
} else delta
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
viewWidth = MeasureSpec.getSize(widthMeasureSpec)
viewHeight = MeasureSpec.getSize(heightMeasureSpec)
// Rescales image on rotation
if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0) return
oldMeasuredHeight = viewHeight
oldMeasuredWidth = viewWidth
if (saveScale == 1f) {
//Fit to screen.
val scale: Float
val drawable = drawable
if (drawable == null || drawable.intrinsicWidth == 0 || drawable.intrinsicHeight == 0) return
val bmWidth = drawable.intrinsicWidth
val bmHeight = drawable.intrinsicHeight
Log.d("bmSize", "bmWidth: $bmWidth bmHeight : $bmHeight")
val scaleX = viewWidth.toFloat() / bmWidth.toFloat()
val scaleY = viewHeight.toFloat() / bmHeight.toFloat()
scale = min(scaleX, scaleY)
touchMatrix!!.setScale(scale, scale)
// Center the image
var redundantYSpace = viewHeight.toFloat() - scale * bmHeight.toFloat()
var redundantXSpace = viewWidth.toFloat() - scale * bmWidth.toFloat()
redundantYSpace /= 2f
redundantXSpace /= 2f
touchMatrix!!.postTranslate(redundantXSpace, redundantYSpace)
origWidth = viewWidth - 2 * redundantXSpace
origHeight = viewHeight - 2 * redundantYSpace
imageMatrix = touchMatrix
}
fixTrans()
}
companion object {
// We can be in one of these 3 states
const val NONE = 0
const val DRAG = 1
const val ZOOM = 2
const val CLICK = 3
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:background="@android:color/black">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/albumPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:orientation="horizontal" />
<me.relex.circleindicator.CircleIndicator3
android:id="@+id/postIndicator"
android:layout_width="wrap_content"
android:layout_height="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
android:id="@+id/imageImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="ContentDescription" />
<ImageButton
android:id="@+id/videoPlayButton"
android:visibility="gone"
android:background="?attr/selectableItemBackgroundBorderless"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:src="@drawable/play_circle_filled"
android:contentDescription="@string/play_video" />
</FrameLayout>

View File

@ -21,6 +21,19 @@
<item name="android:textAppearance">@android:style/TextAppearance.Large</item>
</style>
<style name="AppTheme.ActionBar.Transparent" parent="AppTheme">
<item name="colorPrimary">@android:color/transparent</item>
<item name="colorPrimaryDark">@android:color/transparent</item>
<item name="colorPrimaryVariant">@android:color/transparent</item>
<item name="colorAccent">@android:color/transparent</item>
<item name="colorSecondary">@android:color/transparent</item>
<item name="statusBarForeground">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowLightStatusBar">true</item>
<item name="statusBarBackground">@android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>