Overwrite warning & KEEP_SCREEN_ON while playing

This commit is contained in:
Hardcore Sushi 2020-08-07 19:25:16 +02:00
parent 0bfb952365
commit d3bcd29806
9 changed files with 203 additions and 82 deletions

View File

@ -2,6 +2,9 @@ package sushi.hardcore.droidfs.explorers
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.Menu
import android.view.MenuItem
import android.view.View
@ -34,6 +37,7 @@ import sushi.hardcore.droidfs.util.ExternalProvider
import sushi.hardcore.droidfs.util.GocryptfsVolume
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import java.io.File
open class BaseExplorerActivity : BaseActivity() {
private lateinit var sortOrderEntries: Array<String>
@ -253,6 +257,53 @@ open class BaseExplorerActivity : BaseActivity() {
dialog.show()
}
protected fun checkFileOverwrite(path: String): String? {
var outputPath: String? = null
if (gocryptfsVolume.pathExists(path)){
val fileName = File(path).name
val handler = Handler{ msg ->
outputPath = msg.obj as String?
throw RuntimeException()
}
runOnUiThread {
val dialog = ColoredAlertDialogBuilder(this)
.setTitle(R.string.warning)
.setMessage(getString(R.string.file_overwrite_question, fileName))
.setNegativeButton(R.string.no) { _, _ ->
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text)
dialogEditText.setText(fileName)
dialogEditText.selectAll()
val dialog = ColoredAlertDialogBuilder(this)
.setView(dialogEditTextView)
.setTitle(getString(R.string.enter_new_filename))
.setPositiveButton(R.string.ok) { _, _ ->
handler.sendMessage(Message().apply { obj = checkFileOverwrite(PathUtils.path_join(PathUtils.getParentPath(path), dialogEditText.text.toString())) })
}
.setNegativeButton(R.string.cancel) { _, _ -> handler.sendMessage(Message().apply { obj = null }) }
.create()
dialogEditText.setOnEditorActionListener { _, _, _ ->
dialog.dismiss()
handler.sendMessage(Message().apply { obj = checkFileOverwrite(PathUtils.path_join(PathUtils.getParentPath(path), dialogEditText.text.toString())) })
true
}
dialog.setOnCancelListener { handler.sendMessage(Message().apply { obj = null }) }
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
dialog.show()
}
.setPositiveButton(R.string.yes) {_, _ -> handler.sendMessage(Message().apply { obj = path }) }
.create()
dialog.setOnCancelListener { handler.sendMessage(Message().apply { obj = null }) }
dialog.show()
}
try { Looper.loop() }
catch (e: RuntimeException) {}
} else {
outputPath = path
}
return outputPath
}
protected fun rename(old_name: String, new_name: String){
if (new_name.isEmpty()) {
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()

View File

@ -3,6 +3,7 @@ package sushi.hardcore.droidfs.explorers
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Looper
import android.view.Menu
import android.view.MenuItem
import android.view.View
@ -43,7 +44,8 @@ class ExplorerActivity : BaseExplorerActivity() {
if (fileName.isEmpty()) {
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
} else {
val handleID = gocryptfsVolume.openWriteMode(PathUtils.path_join(currentDirectoryPath, fileName))
checkFileOverwrite(PathUtils.path_join(currentDirectoryPath, fileName))?.let {
val handleID = gocryptfsVolume.openWriteMode(it)
if (handleID == -1) {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
@ -57,6 +59,7 @@ class ExplorerActivity : BaseExplorerActivity() {
}
}
}
}
fun onClickFAB(view: View) {
if (modeSelectLocation){
@ -143,9 +146,13 @@ class ExplorerActivity : BaseExplorerActivity() {
} else {
uris.add(singleUri)
}
var success = true
Looper.prepare()
var success = false
for (uri in uris) {
val dstPath = PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri))
val dstPath = checkFileOverwrite(PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri)))
if (dstPath == null){
break
} else {
contentResolver.openInputStream(uri)?.let {
success = gocryptfsVolume.importFile(it, dstPath)
}
@ -160,6 +167,7 @@ class ExplorerActivity : BaseExplorerActivity() {
break
}
}
}
if (success) {
stopTask {
ColoredAlertDialogBuilder(activity)
@ -257,6 +265,7 @@ class ExplorerActivity : BaseExplorerActivity() {
val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID)
val path = data.getStringExtra("path")
var failedItem: String? = null
Looper.prepare()
if (path == null) {
val paths = data.getStringArrayListExtra("paths")
val types = data.getIntegerArrayListExtra("types")
@ -265,7 +274,7 @@ class ExplorerActivity : BaseExplorerActivity() {
failedItem = if (types[i] == 0) { //directory
recursiveImportDirectoryFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)
} else {
if (importFileFromOtherVolume(remoteGocryptfsVolume, paths[i], PathUtils.path_join(currentDirectoryPath, File(paths[i]).name))) null else paths[i]
safeImportFileFromOtherVolume(remoteGocryptfsVolume, paths[i], PathUtils.path_join(currentDirectoryPath, File(paths[i]).name))
}
if (failedItem != null) {
break
@ -273,7 +282,7 @@ class ExplorerActivity : BaseExplorerActivity() {
}
}
} else {
failedItem = if (importFileFromOtherVolume(remoteGocryptfsVolume, path, PathUtils.path_join(currentDirectoryPath, File(path).name))) null else path
failedItem = safeImportFileFromOtherVolume(remoteGocryptfsVolume, path, PathUtils.path_join(currentDirectoryPath, File(path).name))
}
if (failedItem == null) {
stopTask {
@ -283,7 +292,7 @@ class ExplorerActivity : BaseExplorerActivity() {
.setPositiveButton(R.string.ok, null)
.show()
}
} else {
} else if (failedItem!!.isNotEmpty()){
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
@ -356,13 +365,19 @@ class ExplorerActivity : BaseExplorerActivity() {
object : LoadingTask(this, R.string.loading_msg_copy){
override fun doTask(activity: AppCompatActivity) {
var failedItem: String? = null
Looper.prepare()
for (element in filesToCopy) {
failedItem = if (element.isDirectory) {
recursiveCopyDirectory(element.fullPath, currentDirectoryPath)
} else {
if (copyFile(element.fullPath, PathUtils.path_join(currentDirectoryPath, element.name))) null else element.fullPath
val dstPath = checkFileOverwrite(PathUtils.path_join(currentDirectoryPath, element.name))
if (dstPath == null){
""
} else {
if (copyFile(element.fullPath, dstPath)) null else element.fullPath
}
if (failedItem != null) {
}
if (failedItem != null && failedItem.isNotEmpty()) {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
@ -482,26 +497,34 @@ class ExplorerActivity : BaseExplorerActivity() {
if (!gocryptfsVolume.mkdir(dstPath)){
return e.fullPath
}
} else {
val checkedDstPath = checkFileOverwrite(dstPath)
if (checkedDstPath == null){
return ""
} else {
if (!copyFile(e.fullPath, dstPath)) {
return e.fullPath
}
}
}
}
return null
}
private fun importFileFromOtherVolume(remote_gocryptfsVolume: GocryptfsVolume, srcPath: String, dstPath: String): Boolean {
private fun importFileFromOtherVolume(remoteGocryptfsVolume: GocryptfsVolume, srcPath: String, dstPath: String): Boolean {
var success = true
val srcHandleID = remote_gocryptfsVolume.openReadMode(srcPath)
val srcHandleID = remoteGocryptfsVolume.openReadMode(srcPath)
if (srcHandleID != -1) {
val dstHandleID = gocryptfsVolume.openWriteMode(dstPath)
if (dstHandleID != -1) {
var length: Int
val ioBuffer = ByteArray(GocryptfsVolume.DefaultBS)
var offset: Long = 0
while (remote_gocryptfsVolume.readFile(srcHandleID, offset, ioBuffer).also { length = it } > 0){
val written = gocryptfsVolume.writeFile(dstHandleID, offset, ioBuffer, length).toLong()
while (remoteGocryptfsVolume.readFile(srcHandleID, offset, ioBuffer)
.also { length = it } > 0
) {
val written =
gocryptfsVolume.writeFile(dstHandleID, offset, ioBuffer, length).toLong()
if (written == length.toLong()) {
offset += length.toLong()
} else {
@ -511,11 +534,20 @@ class ExplorerActivity : BaseExplorerActivity() {
}
gocryptfsVolume.closeFile(dstHandleID)
}
remote_gocryptfsVolume.closeFile(srcHandleID)
remoteGocryptfsVolume.closeFile(srcHandleID)
}
return success
}
private fun safeImportFileFromOtherVolume(remoteGocryptfsVolume: GocryptfsVolume, srcPath: String, dstPath: String): String? {
val checkedDstPath = checkFileOverwrite(PathUtils.path_join(currentDirectoryPath, File(dstPath).name))
return if (checkedDstPath == null){
""
} else {
if (importFileFromOtherVolume(remoteGocryptfsVolume, srcPath, checkedDstPath)) null else dstPath
}
}
private fun recursiveImportDirectoryFromOtherVolume(remote_gocryptfsVolume: GocryptfsVolume, remote_directory_path: String, outputPath: String): String? {
val mappedElements = gocryptfsVolume.recursiveMapFiles(remote_directory_path)
val dstDirectoryPath = PathUtils.path_join(outputPath, File(remote_directory_path).name)
@ -531,11 +563,16 @@ class ExplorerActivity : BaseExplorerActivity() {
return e.fullPath
}
} else {
if (!importFileFromOtherVolume(remote_gocryptfsVolume, e.fullPath, dstPath)) {
val checkedDstPath = checkFileOverwrite(dstPath)
if (checkedDstPath == null){
return ""
} else {
if (!importFileFromOtherVolume(remote_gocryptfsVolume, e.fullPath, checkedDstPath)) {
return e.fullPath
}
}
}
}
return null
}

View File

@ -2,10 +2,13 @@ package sushi.hardcore.droidfs.explorers
import android.content.Intent
import android.net.Uri
import android.os.Looper
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.util.LoadingTask
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
@ -28,26 +31,43 @@ class ExplorerActivityDrop : BaseExplorerActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.validate -> {
val alertDialog = ColoredAlertDialogBuilder(this)
object : LoadingTask(this, R.string.loading_msg_import) {
override fun doTask(activity: AppCompatActivity) {
val alertDialog = ColoredAlertDialogBuilder(activity)
alertDialog.setCancelable(false)
alertDialog.setPositiveButton(R.string.ok) { _, _ -> finish() }
var errorMsg: String? = null
val extras = intent.extras
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)){
Looper.prepare()
if (intent.action == Intent.ACTION_SEND) {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
val outputPath = PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(this, uri))
errorMsg = if (gocryptfsVolume.importFile(this, uri, outputPath)) null else getString(R.string.import_failed, outputPath)
errorMsg = if (uri == null){
getString(R.string.share_intent_parsing_failed)
} else {
val outputPathTest = PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri))
val outputPath = checkFileOverwrite(outputPathTest)
if (outputPath == null) {
""
} else {
if (gocryptfsVolume.importFile(activity, uri, outputPath)) null else getString(R.string.import_failed, outputPath)
}
}
} else if (intent.action == Intent.ACTION_SEND_MULTIPLE) {
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
if (uris != null){
for (uri in uris) {
val outputPath = PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(this, uri))
if (!gocryptfsVolume.importFile(this, uri, outputPath)) {
val outputPath = checkFileOverwrite(PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri)))
if (outputPath == null){
errorMsg = ""
break
} else {
if (!gocryptfsVolume.importFile(activity, uri, outputPath)) {
errorMsg = getString(R.string.import_failed, outputPath)
break
}
}
}
} else {
errorMsg = getString(R.string.share_intent_parsing_failed)
}
@ -57,14 +77,18 @@ class ExplorerActivityDrop : BaseExplorerActivity() {
} else {
errorMsg = getString(R.string.share_intent_parsing_failed)
}
if (errorMsg == null || errorMsg.isNotEmpty()){
if (errorMsg == null) {
alertDialog.setTitle(R.string.success_import)
alertDialog.setMessage(R.string.success_import_msg)
} else {
} else if (errorMsg.isNotEmpty()) {
alertDialog.setTitle(R.string.error)
alertDialog.setMessage(errorMsg)
}
alertDialog.show()
stopTask { alertDialog.show() }
}
}
}
true
}
else -> super.onOptionsItemSelected(item)

View File

@ -1,5 +1,6 @@
package sushi.hardcore.droidfs.file_viewers
import android.view.WindowManager
import androidx.appcompat.app.AlertDialog
import com.google.android.exoplayer2.ExoPlaybackException
import com.google.android.exoplayer2.Player
@ -56,6 +57,14 @@ abstract class MediaPlayer: FileViewerActivity() {
errorDialog.show()
}
}
override fun onIsPlayingChanged(isPlaying: Boolean) {
if (isPlaying){
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
})
player.prepare(LoopingMediaSource(mediaSource), false, false)
}

View File

@ -14,6 +14,7 @@ abstract class LoadingTask(private val activity: AppCompatActivity, private val
.setTitle(R.string.loading)
.setCancelable(false)
.create()
private var isStopped = false
init {
dialogLoadingView.findViewById<TextView>(R.id.text_message).text = activity.getString(loadingMessageResId)
startTask()
@ -24,15 +25,21 @@ abstract class LoadingTask(private val activity: AppCompatActivity, private val
dialogLoading.show()
Thread {
doTask(activity)
if (!isStopped){
dialogLoading.dismiss()
}
activity.runOnUiThread { doFinally(activity) }
}.start()
}
protected fun stopTask(onUiThread: () -> Unit){
protected fun stopTask(onUiThread: (() -> Unit)?){
isStopped = true
dialogLoading.dismiss()
onUiThread?.let {
activity.runOnUiThread {
onUiThread()
}
}
}
protected fun stopTaskWithToast(stringId: Int){
stopTask { Toast.makeText(activity, stringId, Toast.LENGTH_SHORT).show() }
}

View File

@ -6,7 +6,6 @@ import android.graphics.drawable.DrawableContainer
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.StateListDrawable
import android.util.AttributeSet
import android.util.Log
import android.widget.ListView
import androidx.core.content.ContextCompat
import sushi.hardcore.droidfs.R

View File

@ -8,7 +8,7 @@ import androidx.appcompat.widget.AppCompatCheckBox
class ColoredCheckBox: AppCompatCheckBox {
constructor(context: Context) : super(context) { applyColor() }
constructor(context: Context, attrs: AttributeSet): super(context, attrs) { applyColor() }
//constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int): super(context, attrs, defStyleAttr) { applyColor() }
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int): super(context, attrs, defStyleAttr) { applyColor() }
private fun applyColor(){
super.setButtonTintList(ColorStateList.valueOf(ThemeColor.getThemeColor(context)))
}

View File

@ -2,16 +2,8 @@ package sushi.hardcore.droidfs.widgets
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.Drawable
import android.os.Build
import android.util.AttributeSet
import android.widget.TextView
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.content.ContextCompat
import sushi.hardcore.droidfs.R
class ColoredEditText: AppCompatEditText {
constructor(context: Context) : super(context) { applyColor() }

View File

@ -135,7 +135,7 @@
<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="share">Share</string>
<string name="decrypt">Decrypt</string>
<string name="loading_msg_copy">Copying selected items...</string>
<string name="loading_msg_copy">Copying selected items</string>
<string name="copy_failed">Copy of %1$s failed.</string>
<string name="copy_success_msg">The selected items have been successfully copied.</string>
<string name="copy_success">Copy successful !</string>
@ -144,4 +144,6 @@
<string name="picture_save_success">Picture saved to %1$s</string>
<string name="picture_save_failed">Failed to save this picture.</string>
<string name="default_total_size">N//A</string>
<string name="file_overwrite_question">%s already exists, do you want to overwrite it ?</string>
<string name="enter_new_filename">Enter new filename</string>
</resources>