diff --git a/app/build.gradle b/app/build.gradle
index 20b225e..1522041 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -4,7 +4,7 @@ apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
- buildToolsVersion "30.0.0"
+ buildToolsVersion "30.0.2"
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
@@ -14,8 +14,8 @@ android {
applicationId "sushi.hardcore.droidfs"
minSdkVersion 21
targetSdkVersion 29
- versionCode 2
- versionName "1.1.7"
+ versionCode 3
+ versionName "1.1.8"
ndk {
abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a'
diff --git a/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt
index 5d8bc79..9bb36a4 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt
@@ -13,9 +13,9 @@ import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_change_password.*
import kotlinx.android.synthetic.main.activity_change_password.checkbox_remember_path
import kotlinx.android.synthetic.main.activity_change_password.checkbox_save_password
-import kotlinx.android.synthetic.main.activity_change_password.edit_volume_path
import kotlinx.android.synthetic.main.activity_change_password.saved_path_listview
import kotlinx.android.synthetic.main.toolbar.*
+import kotlinx.android.synthetic.main.volume_path_section.*
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver
import sushi.hardcore.droidfs.util.*
diff --git a/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt
index d9b9081..3eeac35 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt
@@ -9,6 +9,7 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_create.*
import kotlinx.android.synthetic.main.toolbar.*
+import kotlinx.android.synthetic.main.volume_path_section.*
import sushi.hardcore.droidfs.explorers.ExplorerActivity
import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver
import sushi.hardcore.droidfs.util.*
@@ -16,7 +17,6 @@ import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import java.io.File
import java.util.*
-
class CreateActivity : BaseActivity() {
companion object {
private const val PICK_DIRECTORY_REQUEST_CODE = 1
diff --git a/app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt
index ea1b912..cd820df 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt
@@ -9,15 +9,9 @@ import android.view.View
import android.widget.AdapterView.OnItemClickListener
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_change_password.*
-import kotlinx.android.synthetic.main.activity_create.*
import kotlinx.android.synthetic.main.activity_open.*
-import kotlinx.android.synthetic.main.activity_open.checkbox_remember_path
-import kotlinx.android.synthetic.main.activity_open.checkbox_save_password
-import kotlinx.android.synthetic.main.activity_open.edit_password
-import kotlinx.android.synthetic.main.activity_open.edit_volume_path
-import kotlinx.android.synthetic.main.activity_open.saved_path_listview
import kotlinx.android.synthetic.main.toolbar.*
+import kotlinx.android.synthetic.main.volume_path_section.*
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
import sushi.hardcore.droidfs.explorers.ExplorerActivity
import sushi.hardcore.droidfs.explorers.ExplorerActivityDrop
diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt
index ad2c22d..50ac5e0 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt
@@ -287,7 +287,7 @@ open class BaseExplorerActivity : BaseActivity() {
dialogEditText.selectAll()
val dialog = ColoredAlertDialogBuilder(this)
.setView(dialogEditTextView)
- .setTitle(getString(R.string.enter_new_name))
+ .setTitle(R.string.enter_new_name)
.setPositiveButton(R.string.ok) { _, _ ->
handler.sendMessage(Message().apply { obj = checkPathOverwrite(PathUtils.path_join(PathUtils.getParentPath(path), dialogEditText.text.toString()), isDirectory) })
}
@@ -302,7 +302,7 @@ open class BaseExplorerActivity : BaseActivity() {
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
dialog.show()
}
- .setPositiveButton(R.string.yes) {_, _ -> handler.sendMessage(Message().apply { obj = path }) }
+ .setPositiveButton(R.string.yes) { _, _ -> handler.sendMessage(Message().apply { obj = path }) }
.create()
dialog.setOnCancelListener { handler.sendMessage(Message().apply { obj = null }) }
dialog.show()
diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt
index 04c311c..bffc007 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt
@@ -22,8 +22,8 @@ abstract class FileViewerActivity: BaseActivity() {
}
open fun hideSystemUi(){
window.decorView.systemUiVisibility =
- View.SYSTEM_UI_FLAG_LOW_PROFILE or
View.SYSTEM_UI_FLAG_FULLSCREEN/* or
+ View.SYSTEM_UI_FLAG_LOW_PROFILE or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt
index 9ec2ebc..5da3bc4 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt
@@ -21,6 +21,8 @@ import sushi.hardcore.droidfs.util.MiscUtils
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import sushi.hardcore.droidfs.widgets.ZoomableImageView
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
import java.io.File
import java.security.MessageDigest
import kotlin.math.abs
@@ -40,11 +42,20 @@ class ImageViewer: FileViewerActivity() {
private var slideshowActive = false
private var currentMappedImageIndex = -1
private var rotationAngle: Float = 0F
+ private var rotatedBitmap: Bitmap? = null
private val handler = Handler()
private val hideUI = Runnable {
action_buttons.visibility = View.GONE
action_bar.visibility = View.GONE
}
+ private val slideshowLoop = object : Runnable {
+ override fun run() {
+ if (slideshowActive){
+ swipeImage(-1F)
+ handler.postDelayed(this, ConstValues.slideshow_delay)
+ }
+ }
+ }
override fun viewFile() {
setContentView(R.layout.activity_image_viewer)
image_viewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener {
@@ -69,7 +80,7 @@ class ImageViewer: FileViewerActivity() {
x2 = event.x
val deltaX = x2 - x1
if (abs(deltaX) > MIN_SWIPE_DISTANCE) {
- swipeImage(deltaX)
+ askSaveRotation { swipeImage(deltaX) }
}
}
}
@@ -149,13 +160,7 @@ class ImageViewer: FileViewerActivity() {
fun onClickSlideshow(view: View) {
if (!slideshowActive){
slideshowActive = true
- Thread {
- Thread.sleep(ConstValues.slideshow_delay)
- while (slideshowActive){
- runOnUiThread { swipeImage(-1F) }
- Thread.sleep(ConstValues.slideshow_delay)
- }
- }.start()
+ handler.postDelayed(slideshowLoop, ConstValues.slideshow_delay)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
hideUI.run()
Toast.makeText(this, R.string.slideshow_started, Toast.LENGTH_SHORT).show()
@@ -174,26 +179,27 @@ class ImageViewer: FileViewerActivity() {
if (slideshowActive){
stopSlideshow()
} else {
- super.onBackPressed()
+ askSaveRotation { super.onBackPressed() }
}
}
- class RotateTransformation(private val rotationAngle: Float): BitmapTransformation() {
+ class RotateTransformation(private val imageViewer: ImageViewer): BitmapTransformation() {
- override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
+ 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)
+ matrix.postRotate(imageViewer.rotationAngle)
+ imageViewer.rotatedBitmap = Bitmap.createBitmap(toTransform, 0, 0, toTransform.width, toTransform.height, matrix, true)
+ return imageViewer.rotatedBitmap
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
- messageDigest.update("rotate$rotationAngle".toByteArray())
+ messageDigest.update("rotate${imageViewer.rotationAngle}".toByteArray())
}
}
private fun rotateImage(){
image_viewer.restoreZoomNormal()
- glideImage.transform(RotateTransformation(rotationAngle)).into(image_viewer)
+ glideImage.transform(RotateTransformation(this)).into(image_viewer)
}
fun onCLickRotateRight(view: View){
rotationAngle += 90
@@ -204,6 +210,55 @@ class ImageViewer: FileViewerActivity() {
rotateImage()
}
+ fun onClickPrevious(view: View){
+ askSaveRotation { swipeImage(1F) }
+ }
+ fun onClickNext(view: View){
+ askSaveRotation { swipeImage(-1F) }
+ }
+
+ private fun askSaveRotation(callback: () -> Unit){
+ if (rotationAngle%360 != 0f){
+ ColoredAlertDialogBuilder(this)
+ .keepFullScreen()
+ .setTitle(R.string.warning)
+ .setMessage(R.string.ask_save_img_rotated)
+ .setNegativeButton(R.string.no) { _, _ -> callback() }
+ .setPositiveButton(R.string.yes) { _, _ ->
+ val outputStream = ByteArrayOutputStream()
+ if (rotatedBitmap?.compress(
+ if (fileName.endsWith("png", true)){
+ Bitmap.CompressFormat.PNG
+ } else {
+ Bitmap.CompressFormat.JPEG
+ }, 100, outputStream) == true
+ ){
+ if (gocryptfsVolume.importFile(ByteArrayInputStream(outputStream.toByteArray()), filePath)){
+ Toast.makeText(this, R.string.image_saved_successfully, Toast.LENGTH_SHORT).show()
+ callback()
+ } else {
+ ColoredAlertDialogBuilder(this)
+ .keepFullScreen()
+ .setTitle(R.string.error)
+ .setMessage(R.string.file_write_failed)
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ }
+ } else {
+ ColoredAlertDialogBuilder(this)
+ .keepFullScreen()
+ .setTitle(R.string.error)
+ .setMessage(R.string.bitmap_compress_failed)
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ }
+ }
+ .show()
+ } else {
+ callback()
+ }
+ }
+
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
image_viewer.restoreZoomNormal()
diff --git a/app/src/main/java/sushi/hardcore/droidfs/util/GocryptfsVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/util/GocryptfsVolume.kt
index bbbe792..922ebb0 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/util/GocryptfsVolume.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/util/GocryptfsVolume.kt
@@ -3,7 +3,9 @@ package sushi.hardcore.droidfs.util
import android.content.Context
import android.net.Uri
import sushi.hardcore.droidfs.explorers.ExplorerElement
-import java.io.*
+import java.io.FileOutputStream
+import java.io.InputStream
+import java.io.OutputStream
class GocryptfsVolume(var sessionID: Int) {
private external fun native_close(sessionID: Int)
diff --git a/app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredAlertDialogBuilder.kt b/app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredAlertDialogBuilder.kt
index eb5a008..0f17156 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredAlertDialogBuilder.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredAlertDialogBuilder.kt
@@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.widgets
import androidx.appcompat.app.AlertDialog
import android.content.Context
+import android.view.View
import android.view.WindowManager
class ColoredAlertDialogBuilder: AlertDialog.Builder {
@@ -27,6 +28,10 @@ class ColoredAlertDialogBuilder: AlertDialog.Builder {
override fun show(): AlertDialog {
val dialog = create()
dialog.show()
+ if (keepFullScreen){
+ dialog.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
+ dialog.window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
+ }
return dialog
}
diff --git a/app/src/main/res/layout/activity_change_password.xml b/app/src/main/res/layout/activity_change_password.xml
index d9655b0..bce890f 100644
--- a/app/src/main/res/layout/activity_change_password.xml
+++ b/app/src/main/res/layout/activity_change_password.xml
@@ -16,34 +16,7 @@
android:orientation="vertical"
android:padding="10dp">
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_open.xml b/app/src/main/res/layout/activity_open.xml
index edb1336..ad1b65a 100644
--- a/app/src/main/res/layout/activity_open.xml
+++ b/app/src/main/res/layout/activity_open.xml
@@ -16,34 +16,7 @@
android:padding="10dp"
android:orientation="vertical">
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index f87fa9a..4bdc481 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -14,4 +14,5 @@
20dp
20dp
18sp
+ 40dp
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7980935..3585899 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -173,4 +173,8 @@
DroidFS can\'t write on removable SD cards, please move the volume to internal storage.
Slideshow stopped
Slideshow started
+ The image has been rotated. Do you want to save these changes and overwrite the original image ?
+ Image changes successfully saved.
+ Failed to compress the bitmap.
+ Failed to write the file.