DroidFS/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt

208 lines
7.3 KiB
Kotlin
Raw Normal View History

2020-07-17 16:35:39 +02:00
package sushi.hardcore.droidfs.file_viewers
2020-08-25 15:43:47 +02:00
import android.content.res.Configuration
2020-07-17 16:35:39 +02:00
import android.graphics.Bitmap
import android.graphics.Matrix
2020-07-18 18:44:53 +02:00
import android.graphics.drawable.Drawable
2020-07-17 16:35:39 +02:00
import android.os.Handler
2020-08-01 16:43:48 +02:00
import android.view.MotionEvent
2020-07-17 16:35:39 +02:00
import android.view.View
2020-08-25 15:43:47 +02:00
import android.widget.Toast
2020-07-18 18:44:53 +02:00
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
2020-07-17 16:35:39 +02:00
import kotlinx.android.synthetic.main.activity_image_viewer.*
2020-08-01 16:43:48 +02:00
import sushi.hardcore.droidfs.ConstValues
2020-07-17 16:35:39 +02:00
import sushi.hardcore.droidfs.R
2020-08-04 11:44:29 +02:00
import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.util.MiscUtils
2020-08-01 16:43:48 +02:00
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
2020-08-25 15:43:47 +02:00
import sushi.hardcore.droidfs.widgets.ZoomableImageView
import java.io.File
2020-07-18 18:44:53 +02:00
import java.security.MessageDigest
2020-08-01 16:43:48 +02:00
import kotlin.math.abs
2020-07-17 16:35:39 +02:00
class ImageViewer: FileViewerActivity() {
companion object {
private const val hideDelay: Long = 3000
2020-08-01 16:43:48 +02:00
private const val MIN_SWIPE_DISTANCE = 150
2020-07-17 16:35:39 +02:00
}
private lateinit var fileName: String
2020-07-18 18:44:53 +02:00
private lateinit var glideImage: RequestBuilder<Drawable>
2020-08-01 16:43:48 +02:00
private var x1 = 0F
private var x2 = 0F
2020-08-04 11:44:29 +02:00
private val mappedImages = mutableListOf<ExplorerElement>()
private lateinit var sortOrder: String
2020-08-01 16:43:48 +02:00
private var wasMapped = false
2020-08-25 15:43:47 +02:00
private var slideshowActive = false
2020-08-01 16:43:48 +02:00
private var currentMappedImageIndex = -1
2020-07-18 18:44:53 +02:00
private var rotationAngle: Float = 0F
2020-07-17 16:35:39 +02:00
private val handler = Handler()
2020-08-25 15:43:47 +02:00
private val hideUI = Runnable {
action_buttons.visibility = View.GONE
action_bar.visibility = View.GONE
}
2020-07-17 16:35:39 +02:00
override fun viewFile() {
setContentView(R.layout.activity_image_viewer)
image_viewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener {
override fun onSingleTap(event: MotionEvent?) {
handler.removeCallbacks(hideUI)
if (action_buttons.visibility == View.GONE) {
action_buttons.visibility = View.VISIBLE
action_bar.visibility = View.VISIBLE
handler.postDelayed(hideUI, hideDelay)
} else {
hideUI.run()
2020-08-01 16:43:48 +02:00
}
}
override fun onTouch(event: MotionEvent?) {
if (!image_viewer.isZoomed) {
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
x1 = event.x
}
MotionEvent.ACTION_UP -> {
x2 = event.x
val deltaX = x2 - x1
if (abs(deltaX) > MIN_SWIPE_DISTANCE) {
swipeImage(deltaX)
2020-08-01 16:43:48 +02:00
}
}
}
}
}
})
loadImage()
handler.postDelayed(hideUI, hideDelay)
}
private fun loadImage(){
loadWholeFile(filePath)?.let {
glideImage = Glide.with(this).load(it)
2020-08-25 15:43:47 +02:00
glideImage.into(image_viewer)
fileName = File(filePath).name
text_filename.text = fileName
rotationAngle = 0F
2020-08-25 15:43:47 +02:00
}
}
override fun onUserInteraction() {
super.onUserInteraction()
handler.removeCallbacks(hideUI)
handler.postDelayed(hideUI, hideDelay)
}
2020-08-25 15:43:47 +02:00
private fun swipeImage(deltaX: Float){
if (!wasMapped){
for (e in gocryptfsVolume.recursiveMapFiles(PathUtils.getParentPath(filePath))){
if (e.isRegularFile && ConstValues.isImage(e.name)){
mappedImages.add(e)
}
}
sortOrder = intent.getStringExtra("sortOrder") ?: "name"
ExplorerElement.sortBy(sortOrder, mappedImages)
for ((i, e) in mappedImages.withIndex()){
if (filePath == e.fullPath){
currentMappedImageIndex = i
break
}
2020-08-01 16:43:48 +02:00
}
2020-08-25 15:43:47 +02:00
wasMapped = true
}
currentMappedImageIndex = if (deltaX < 0){
MiscUtils.incrementIndex(currentMappedImageIndex, mappedImages)
} else {
MiscUtils.decrementIndex(currentMappedImageIndex, mappedImages)
}
filePath = mappedImages[currentMappedImageIndex].fullPath
loadImage()
}
fun onClickDelete(view: View) {
ColoredAlertDialogBuilder(this)
.keepFullScreen()
.setTitle(R.string.warning)
.setPositiveButton(R.string.ok) { _, _ ->
if (gocryptfsVolume.removeFile(filePath)){
currentMappedImageIndex = MiscUtils.decrementIndex(currentMappedImageIndex, mappedImages)
mappedImages.clear()
wasMapped = false
swipeImage(-1F)
} else {
ColoredAlertDialogBuilder(this)
.keepFullScreen()
.setTitle(R.string.error)
.setMessage(getString(R.string.remove_failed, fileName))
.setPositiveButton(R.string.ok, null)
.show()
}
}
.setNegativeButton(R.string.cancel, null)
.setMessage(getString(R.string.single_delete_confirm, fileName))
.show()
2020-08-25 15:43:47 +02:00
}
fun onClickSlideshow(view: View) {
if (!slideshowActive){
slideshowActive = true
Thread {
Thread.sleep(ConstValues.slideshow_delay)
2020-08-25 15:43:47 +02:00
while (slideshowActive){
runOnUiThread { swipeImage(-1F) }
Thread.sleep(ConstValues.slideshow_delay)
}
}.start()
hideUI.run()
Toast.makeText(this, R.string.slideshow_started, Toast.LENGTH_SHORT).show()
} else {
stopSlideshow()
}
}
private fun stopSlideshow(){
slideshowActive = false
Toast.makeText(this, R.string.slideshow_stopped, Toast.LENGTH_SHORT).show()
}
override fun onBackPressed() {
if (slideshowActive){
stopSlideshow()
2020-08-25 15:43:47 +02:00
} else {
super.onBackPressed()
2020-08-01 16:43:48 +02:00
}
}
2020-07-18 18:44:53 +02:00
class RotateTransformation(private val rotationAngle: Float): BitmapTransformation() {
override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
val matrix = Matrix()
matrix.postRotate(rotationAngle)
return Bitmap.createBitmap(toTransform, 0, 0, toTransform.width, toTransform.height, matrix, true)
2020-07-17 16:35:39 +02:00
}
2020-07-18 18:44:53 +02:00
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update("rotate$rotationAngle".toByteArray())
2020-07-17 16:35:39 +02:00
}
}
2020-07-18 18:44:53 +02:00
private fun rotateImage(){
2020-08-01 16:43:48 +02:00
image_viewer.restoreZoomNormal()
2020-07-18 18:44:53 +02:00
glideImage.transform(RotateTransformation(rotationAngle)).into(image_viewer)
2020-07-17 16:35:39 +02:00
}
fun onCLickRotateRight(view: View){
2020-07-18 18:44:53 +02:00
rotationAngle += 90
rotateImage()
2020-07-17 16:35:39 +02:00
}
fun onClickRotateLeft(view: View){
2020-07-18 18:44:53 +02:00
rotationAngle -= 90
rotateImage()
2020-07-17 16:35:39 +02:00
}
2020-08-25 15:43:47 +02:00
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
image_viewer.restoreZoomNormal()
2020-07-17 16:35:39 +02:00
}
}