ImageViewer: delete button & ui behavior improvements
This commit is contained in:
parent
c82d6c0e36
commit
bad270851f
@ -42,7 +42,7 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
implementation "androidx.core:core-ktx:1.3.1"
|
implementation "androidx.core:core-ktx:1.3.1"
|
||||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.0.0"
|
implementation "androidx.constraintlayout:constraintlayout:2.0.1"
|
||||||
|
|
||||||
implementation "androidx.sqlite:sqlite:2.1.0"
|
implementation "androidx.sqlite:sqlite:2.1.0"
|
||||||
implementation "androidx.preference:preference:1.1.1"
|
implementation "androidx.preference:preference:1.1.1"
|
||||||
|
@ -15,9 +15,10 @@ import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
|||||||
import kotlinx.android.synthetic.main.activity_image_viewer.*
|
import kotlinx.android.synthetic.main.activity_image_viewer.*
|
||||||
import sushi.hardcore.droidfs.ConstValues
|
import sushi.hardcore.droidfs.ConstValues
|
||||||
import sushi.hardcore.droidfs.R
|
import sushi.hardcore.droidfs.R
|
||||||
import sushi.hardcore.droidfs.util.MiscUtils
|
|
||||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||||
|
import sushi.hardcore.droidfs.util.MiscUtils
|
||||||
import sushi.hardcore.droidfs.util.PathUtils
|
import sushi.hardcore.droidfs.util.PathUtils
|
||||||
|
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||||
import sushi.hardcore.droidfs.widgets.ZoomableImageView
|
import sushi.hardcore.droidfs.widgets.ZoomableImageView
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
@ -28,6 +29,7 @@ class ImageViewer: FileViewerActivity() {
|
|||||||
private const val hideDelay: Long = 3000
|
private const val hideDelay: Long = 3000
|
||||||
private const val MIN_SWIPE_DISTANCE = 150
|
private const val MIN_SWIPE_DISTANCE = 150
|
||||||
}
|
}
|
||||||
|
private lateinit var fileName: String
|
||||||
private lateinit var glideImage: RequestBuilder<Drawable>
|
private lateinit var glideImage: RequestBuilder<Drawable>
|
||||||
private var x1 = 0F
|
private var x1 = 0F
|
||||||
private var x2 = 0F
|
private var x2 = 0F
|
||||||
@ -43,13 +45,11 @@ class ImageViewer: FileViewerActivity() {
|
|||||||
action_bar.visibility = View.GONE
|
action_bar.visibility = View.GONE
|
||||||
}
|
}
|
||||||
override fun viewFile() {
|
override fun viewFile() {
|
||||||
val imageBuff = loadWholeFile(filePath)
|
|
||||||
if (imageBuff != null){
|
|
||||||
setContentView(R.layout.activity_image_viewer)
|
setContentView(R.layout.activity_image_viewer)
|
||||||
image_viewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener{
|
image_viewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener {
|
||||||
override fun onSingleTap(event: MotionEvent?) {
|
override fun onSingleTap(event: MotionEvent?) {
|
||||||
handler.removeCallbacks(hideUI)
|
handler.removeCallbacks(hideUI)
|
||||||
if (action_buttons.visibility == View.GONE){
|
if (action_buttons.visibility == View.GONE) {
|
||||||
action_buttons.visibility = View.VISIBLE
|
action_buttons.visibility = View.VISIBLE
|
||||||
action_bar.visibility = View.VISIBLE
|
action_bar.visibility = View.VISIBLE
|
||||||
handler.postDelayed(hideUI, hideDelay)
|
handler.postDelayed(hideUI, hideDelay)
|
||||||
@ -57,16 +57,17 @@ class ImageViewer: FileViewerActivity() {
|
|||||||
hideUI.run()
|
hideUI.run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTouch(event: MotionEvent?) {
|
override fun onTouch(event: MotionEvent?) {
|
||||||
if (!image_viewer.isZoomed){
|
if (!image_viewer.isZoomed) {
|
||||||
when(event?.action){
|
when (event?.action) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
x1 = event.x
|
x1 = event.x
|
||||||
}
|
}
|
||||||
MotionEvent.ACTION_UP -> {
|
MotionEvent.ACTION_UP -> {
|
||||||
x2 = event.x
|
x2 = event.x
|
||||||
val deltaX = x2 - x1
|
val deltaX = x2 - x1
|
||||||
if (abs(deltaX) > MIN_SWIPE_DISTANCE){
|
if (abs(deltaX) > MIN_SWIPE_DISTANCE) {
|
||||||
swipeImage(deltaX)
|
swipeImage(deltaX)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,11 +75,24 @@ class ImageViewer: FileViewerActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
glideImage = Glide.with(this).load(imageBuff)
|
loadImage()
|
||||||
glideImage.into(image_viewer)
|
|
||||||
text_filename.text = File(filePath).name
|
|
||||||
handler.postDelayed(hideUI, hideDelay)
|
handler.postDelayed(hideUI, hideDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadImage(){
|
||||||
|
loadWholeFile(filePath)?.let {
|
||||||
|
glideImage = Glide.with(this).load(it)
|
||||||
|
glideImage.into(image_viewer)
|
||||||
|
fileName = File(filePath).name
|
||||||
|
text_filename.text = fileName
|
||||||
|
rotationAngle = 0F
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUserInteraction() {
|
||||||
|
super.onUserInteraction()
|
||||||
|
handler.removeCallbacks(hideUI)
|
||||||
|
handler.postDelayed(hideUI, hideDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun swipeImage(deltaX: Float){
|
private fun swipeImage(deltaX: Float){
|
||||||
@ -103,27 +117,62 @@ class ImageViewer: FileViewerActivity() {
|
|||||||
} else {
|
} else {
|
||||||
MiscUtils.decrementIndex(currentMappedImageIndex, mappedImages)
|
MiscUtils.decrementIndex(currentMappedImageIndex, mappedImages)
|
||||||
}
|
}
|
||||||
loadWholeFile(mappedImages[currentMappedImageIndex].fullPath)?.let {
|
filePath = mappedImages[currentMappedImageIndex].fullPath
|
||||||
glideImage = Glide.with(applicationContext).load(it)
|
loadImage()
|
||||||
glideImage.into(image_viewer)
|
|
||||||
text_filename.text = File(mappedImages[currentMappedImageIndex].fullPath).name
|
|
||||||
rotationAngle = 0F
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClickSlideshow(view: View) {
|
fun onClickSlideshow(view: View) {
|
||||||
if (!slideshowActive){
|
if (!slideshowActive){
|
||||||
slideshowActive = true
|
slideshowActive = true
|
||||||
Thread {
|
Thread {
|
||||||
|
Thread.sleep(ConstValues.slideshow_delay)
|
||||||
while (slideshowActive){
|
while (slideshowActive){
|
||||||
runOnUiThread { swipeImage(-1F) }
|
runOnUiThread { swipeImage(-1F) }
|
||||||
Thread.sleep(ConstValues.slideshow_delay)
|
Thread.sleep(ConstValues.slideshow_delay)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
|
hideUI.run()
|
||||||
|
Toast.makeText(this, R.string.slideshow_started, Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
|
stopSlideshow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopSlideshow(){
|
||||||
slideshowActive = false
|
slideshowActive = false
|
||||||
Toast.makeText(this, R.string.slideshow_stopped, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.slideshow_stopped, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
if (slideshowActive){
|
||||||
|
stopSlideshow()
|
||||||
|
} else {
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RotateTransformation(private val rotationAngle: Float): BitmapTransformation() {
|
class RotateTransformation(private val rotationAngle: Float): BitmapTransformation() {
|
||||||
|
@ -2,10 +2,19 @@ package sushi.hardcore.droidfs.widgets
|
|||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.view.WindowManager
|
||||||
|
|
||||||
class ColoredAlertDialogBuilder: AlertDialog.Builder {
|
class ColoredAlertDialogBuilder: AlertDialog.Builder {
|
||||||
constructor(context: Context): super(context)
|
constructor(context: Context): super(context)
|
||||||
constructor(context: Context, themeResId: Int): super(context, themeResId)
|
constructor(context: Context, themeResId: Int): super(context, themeResId)
|
||||||
|
|
||||||
|
private var keepFullScreen = false
|
||||||
|
|
||||||
|
fun keepFullScreen(): AlertDialog.Builder {
|
||||||
|
keepFullScreen = true
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
private fun applyColor(dialog: AlertDialog){
|
private fun applyColor(dialog: AlertDialog){
|
||||||
dialog.setOnShowListener{
|
dialog.setOnShowListener{
|
||||||
val themeColor = ThemeColor.getThemeColor(context)
|
val themeColor = ThemeColor.getThemeColor(context)
|
||||||
@ -14,16 +23,19 @@ class ColoredAlertDialogBuilder: AlertDialog.Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun show(): AlertDialog? {
|
|
||||||
val dialog = super.create()
|
override fun show(): AlertDialog {
|
||||||
applyColor(dialog)
|
val dialog = create()
|
||||||
dialog.show()
|
dialog.show()
|
||||||
return null
|
return dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun create(): AlertDialog {
|
override fun create(): AlertDialog {
|
||||||
val dialog = super.create()
|
val dialog = super.create()
|
||||||
applyColor(dialog)
|
applyColor(dialog)
|
||||||
|
if (keepFullScreen){
|
||||||
|
dialog.window?.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
|
||||||
|
}
|
||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,8 +27,21 @@
|
|||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:layout_marginEnd="40dp"
|
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_toStartOf="@id/image_delete"
|
||||||
|
android:layout_centerVertical="true"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/image_delete"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:background="#00000000"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@drawable/icon_delete"
|
||||||
|
android:onClick="onClickDelete"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_toStartOf="@id/image_button_slideshow"
|
||||||
android:layout_centerVertical="true"/>
|
android:layout_centerVertical="true"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -136,7 +136,7 @@
|
|||||||
<string name="query_cursor_null_error_msg">Unable to access this file</string>
|
<string name="query_cursor_null_error_msg">Unable to access this file</string>
|
||||||
<string name="about">About</string>
|
<string name="about">About</string>
|
||||||
<string name="github">GitHub</string>
|
<string name="github">GitHub</string>
|
||||||
<string name="github_summary">Want to read the documentation, request feature, report bug, read the source code… Check the DroidFS\'s repository !</string>
|
<string name="github_summary">Want to read the documentation, review the source code, request feature, report bug… Check the DroidFS\'s repository !</string>
|
||||||
<string name="share">Share</string>
|
<string name="share">Share</string>
|
||||||
<string name="decrypt_files">Export/Decrypt</string>
|
<string name="decrypt_files">Export/Decrypt</string>
|
||||||
<string name="loading_msg_copy">Copying selected items…</string>
|
<string name="loading_msg_copy">Copying selected items…</string>
|
||||||
@ -172,4 +172,5 @@
|
|||||||
<string name="change_pwd_cant_write_error_msg">DroidFS doesn\'t have write access to this path. You can try to move the volume to a writable location.</string>
|
<string name="change_pwd_cant_write_error_msg">DroidFS doesn\'t have write access to this path. You can try to move the volume to a writable location.</string>
|
||||||
<string name="change_pwd_on_sdcard_error_msg">DroidFS can\'t write on removable SD cards, please move the volume to internal storage.</string>
|
<string name="change_pwd_on_sdcard_error_msg">DroidFS can\'t write on removable SD cards, please move the volume to internal storage.</string>
|
||||||
<string name="slideshow_stopped">Slideshow stopped</string>
|
<string name="slideshow_stopped">Slideshow stopped</string>
|
||||||
|
<string name="slideshow_started">Slideshow started</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user