From c6598528fd95be67ac9eec421a139de21e4ab8a4 Mon Sep 17 00:00:00 2001 From: tibbi Date: Tue, 8 Nov 2016 21:49:54 +0100 Subject: [PATCH] add a couple things related to file copying --- .../com/simplemobiletools/gallery/Utils.kt | 5 + .../gallery/activities/MediaActivity.java | 3 +- .../gallery/activities/ViewPagerActivity.java | 7 ++ .../gallery/activities/PickAlbumActivity.kt | 3 +- .../gallery/asynctasks/CopyTask.kt | 119 ++++++++++++++++++ .../gallery/dialogs/CopyDialog.kt | 98 +++++++++++++++ .../gallery/extensions/context.kt | 3 + .../gallery/extensions/textView.kt | 5 + app/src/main/res/layout/copy_item.xml | 66 ++++++++++ app/src/main/res/menu/viewpager_menu.xml | 4 + app/src/main/res/values-de/strings.xml | 14 +++ app/src/main/res/values-es/strings.xml | 14 +++ app/src/main/res/values-it/strings.xml | 14 +++ app/src/main/res/values-ja/strings.xml | 14 +++ app/src/main/res/values-pt-rPT/strings.xml | 14 +++ app/src/main/res/values-sv/strings.xml | 14 +++ app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 14 +++ 18 files changed, 410 insertions(+), 2 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/CopyTask.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/CopyDialog.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/gallery/extensions/textView.kt create mode 100644 app/src/main/res/layout/copy_item.xml diff --git a/app/src/main/java/com/simplemobiletools/gallery/Utils.kt b/app/src/main/java/com/simplemobiletools/gallery/Utils.kt index d50651e42..45a9db5d2 100644 --- a/app/src/main/java/com/simplemobiletools/gallery/Utils.kt +++ b/app/src/main/java/com/simplemobiletools/gallery/Utils.kt @@ -21,6 +21,7 @@ import android.webkit.MimeTypeMap import android.widget.Toast import com.simplemobiletools.filepicker.extensions.getSDCardPath import com.simplemobiletools.gallery.dialogs.WritePermissionDialog +import com.simplemobiletools.gallery.extensions.scanFile import com.simplemobiletools.gallery.models.Medium import java.io.File @@ -182,5 +183,9 @@ class Utils { false } } + + fun scanFiles(context: Context, paths: Array) { + context.scanFile(paths) + } } } diff --git a/app/src/main/java/com/simplemobiletools/gallery/activities/MediaActivity.java b/app/src/main/java/com/simplemobiletools/gallery/activities/MediaActivity.java index 2245cc570..acedf00a8 100644 --- a/app/src/main/java/com/simplemobiletools/gallery/activities/MediaActivity.java +++ b/app/src/main/java/com/simplemobiletools/gallery/activities/MediaActivity.java @@ -167,7 +167,8 @@ public class MediaActivity extends SimpleActivity rescanDirectory(files[i]); } } - MediaScannerConnection.scanFile(getApplicationContext(), paths, null, null); + + Utils.Companion.scanFiles(getApplicationContext(), paths); } private void showSortingDialog() { diff --git a/app/src/main/java/com/simplemobiletools/gallery/activities/ViewPagerActivity.java b/app/src/main/java/com/simplemobiletools/gallery/activities/ViewPagerActivity.java index e42e11ca7..d929c1b4b 100644 --- a/app/src/main/java/com/simplemobiletools/gallery/activities/ViewPagerActivity.java +++ b/app/src/main/java/com/simplemobiletools/gallery/activities/ViewPagerActivity.java @@ -151,6 +151,9 @@ public class ViewPagerActivity extends SimpleActivity case R.id.menu_set_as_wallpaper: setAsWallpaper(); return true; + case R.id.menu_copy: + displayCopyDialog(); + return true; case R.id.menu_open_with: openWith(); return true; @@ -181,6 +184,10 @@ public class ViewPagerActivity extends SimpleActivity adapter.updateItems(mPos); } + private void displayCopyDialog() { + + } + private void openEditor() { final Intent intent = new Intent(Intent.ACTION_EDIT); intent.setDataAndType(Uri.fromFile(getCurrentFile()), "image/*"); diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PickAlbumActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PickAlbumActivity.kt index 7d9b67246..3cad55d24 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PickAlbumActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PickAlbumActivity.kt @@ -7,6 +7,7 @@ import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.Utils import com.simplemobiletools.gallery.adapters.DirectoryAdapter import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask +import com.simplemobiletools.gallery.extensions.toast import com.simplemobiletools.gallery.models.Directory import kotlinx.android.synthetic.main.activity_main.* import java.util.* @@ -27,7 +28,7 @@ class PickAlbumActivity : SimpleActivity(), AdapterView.OnItemClickListener, Get if (Utils.hasStoragePermission(applicationContext)) { getDirectories() } else { - Utils.showToast(applicationContext, R.string.no_permissions) + toast(R.string.no_permissions) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/CopyTask.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/CopyTask.kt new file mode 100644 index 000000000..0ea085f66 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/CopyTask.kt @@ -0,0 +1,119 @@ +package com.simplemobiletools.gallery.asynctasks + +import android.content.Context +import android.os.AsyncTask +import android.support.v4.util.Pair +import android.util.Log +import com.simplemobiletools.gallery.Utils +import java.io.* +import java.lang.ref.WeakReference + +class CopyTask(listener: CopyTask.CopyListener, val context: Context) : AsyncTask, File>, Void, Boolean>() { + private val TAG = CopyTask::class.java.simpleName + private var mListener: WeakReference? = null + private var destinationDir: File? = null + + init { + mListener = WeakReference(listener) + } + + override fun doInBackground(vararg params: Pair, File>): Boolean? { + val pair = params[0] + val files = pair.first + for (file in files) { + try { + destinationDir = File(pair.second, file.name) + copy(file, destinationDir!!) + } catch (e: Exception) { + Log.e(TAG, "copy " + e) + return false + } + } + return true + } + + @Throws(Exception::class) + private fun copy(source: File, destination: File) { + if (source.isDirectory) { + copyDirectory(source, destination) + } else { + copyFile(source, destination) + } + } + + private fun copyDirectory(source: File, destination: File) { + if (!destination.exists()) { + if (Utils.needsStupidWritePermissions(context, destination.absolutePath)) { + val document = Utils.getFileDocument(context, destination.absolutePath) + document.createDirectory(destination.name) + } else if (!destination.mkdirs()) { + throw IOException("Could not create dir " + destination.absolutePath) + } + } + + val children = source.list() + for (child in children) { + val newFile = File(source, child) + if (Utils.needsStupidWritePermissions(context, destination.absolutePath)) { + if (newFile.isDirectory) { + copyDirectory(newFile, File(destination, child)) + } else { + var document = Utils.getFileDocument(context, destination.absolutePath) + document = document.createFile("", child) + + val inputStream = FileInputStream(newFile) + val out = context.contentResolver.openOutputStream(document.uri) + copyStream(inputStream, out) + } + } else { + copy(newFile, File(destination, child)) + } + } + } + + private fun copyFile(source: File, destination: File) { + val directory = destination.parentFile + if (!directory.exists() && !directory.mkdirs()) { + throw IOException("Could not create dir " + directory.absolutePath) + } + + val inputStream = FileInputStream(source) + val out: OutputStream? + if (Utils.needsStupidWritePermissions(context, destination.absolutePath)) { + var document = Utils.getFileDocument(context, destination.absolutePath) + document = document.createFile("", destination.name) + out = context.contentResolver.openOutputStream(document.uri) + } else { + out = FileOutputStream(destination) + } + + copyStream(inputStream, out) + } + + private fun copyStream(inputStream: InputStream, out: OutputStream?) { + val buf = ByteArray(1024) + var len: Int + while (true) { + len = inputStream.read(buf) + if (len <= 0) + break + out?.write(buf, 0, len) + } + } + + override fun onPostExecute(success: Boolean) { + val listener = mListener?.get() ?: return + + if (success) { + listener.copySucceeded(destinationDir!!) + } else { + listener.copyFailed() + } + } + + interface CopyListener { + fun copySucceeded(destinationDir: File) + + fun copyFailed() + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/CopyDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/CopyDialog.kt new file mode 100644 index 000000000..fe73eb1fa --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/CopyDialog.kt @@ -0,0 +1,98 @@ +package com.simplemobiletools.gallery.dialogs + +import android.app.Activity +import android.support.v4.util.Pair +import android.support.v7.app.AlertDialog +import android.view.LayoutInflater +import android.view.WindowManager +import com.simplemobiletools.gallery.R +import com.simplemobiletools.gallery.Utils +import com.simplemobiletools.gallery.asynctasks.CopyTask +import com.simplemobiletools.gallery.extensions.scanFile +import com.simplemobiletools.gallery.extensions.toast +import com.simplemobiletools.gallery.extensions.value +import kotlinx.android.synthetic.main.copy_item.view.* +import java.io.File +import java.util.* + +class CopyDialog(val activity: Activity, val files: List, val path: String, val copyListener: CopyTask.CopyListener, val listener: OnCopyListener) { + + init { + val context = activity + val view = LayoutInflater.from(context).inflate(R.layout.copy_item, null) + view.source.text = "${path.trimEnd('/')}/" + + view.destination.setOnClickListener { + + } + + AlertDialog.Builder(context) + .setTitle(context.resources.getString(if (files.size == 1) R.string.copy_item else R.string.copy_items)) + .setView(view) + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, null) + .create().apply { + window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) + show() + getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener({ + val destinationPath = view.destination.value + if (destinationPath == context.resources.getString(R.string.select_destination)) { + context.toast(R.string.please_select_destination) + return@setOnClickListener + } + + if (view.source.text.trimEnd('/') == destinationPath.trimEnd('/')) { + context.toast(R.string.source_and_destination_same) + return@setOnClickListener + } + + val destinationDir = File(destinationPath) + if (!destinationDir.exists()) { + context.toast(R.string.invalid_destination) + return@setOnClickListener + } + + if (files.size == 1) { + val newFile = File(files[0].path) + if (File(destinationPath, newFile.name).exists()) { + context.toast(R.string.already_exists) + return@setOnClickListener + } + } + + if (Utils.isShowingWritePermissions(context, destinationDir)) { + return@setOnClickListener + } + + if (view.dialog_radio_group.checkedRadioButtonId == R.id.dialog_radio_copy) { + context.toast(R.string.copying) + val pair = Pair, File>(files, destinationDir) + CopyTask(copyListener, context).execute(pair) + dismiss() + } else { + if (Utils.isPathOnSD(context, view.source.value) && Utils.isPathOnSD(context, destinationPath)) { + val paths = ArrayList() + for (f in files) { + val destination = File(destinationDir, f.name) + f.renameTo(destination) + paths.add(destination.absolutePath) + } + + context.scanFile(paths.toTypedArray()) + + dismiss() + listener.onSuccess() + } else { + val pair = Pair, File>(files, destinationDir) + CopyTask(copyListener, context).execute(pair) + dismiss() + } + } + }) + } + } + + interface OnCopyListener { + fun onSuccess() + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt index 75bd2003a..4b8afda12 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt @@ -1,8 +1,11 @@ package com.simplemobiletools.gallery.extensions import android.content.Context +import android.media.MediaScannerConnection import android.widget.Toast fun Context.toast(msg: String, duration: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, msg, duration).show() fun Context.toast(msgId: Int, duration: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, resources.getString(msgId), duration).show() + +fun Context.scanFile(paths: Array) = MediaScannerConnection.scanFile(this, paths, null, null) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/textView.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/textView.kt new file mode 100644 index 000000000..80e64d1cc --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/textView.kt @@ -0,0 +1,5 @@ +package com.simplemobiletools.gallery.extensions + +import android.widget.TextView + +val TextView.value: String get() = this.text.toString().trim() diff --git a/app/src/main/res/layout/copy_item.xml b/app/src/main/res/layout/copy_item.xml new file mode 100644 index 000000000..47db395bd --- /dev/null +++ b/app/src/main/res/layout/copy_item.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/viewpager_menu.xml b/app/src/main/res/menu/viewpager_menu.xml index ed2ebbcff..9865b299c 100644 --- a/app/src/main/res/menu/viewpager_menu.xml +++ b/app/src/main/res/menu/viewpager_menu.xml @@ -5,6 +5,10 @@ android:id="@+id/menu_set_as_wallpaper" android:title="@string/set_as_wallpaper" app:showAsAction="never"/> + Please choose the root folder of the SD card to grant write access on the next screen Save as File saved successfully + Kopieren + Verschieben + Kopieren/Verschieben + Datei/Ordner kopieren + Dateien/Ordner kopieren + Quelle + Ziel + Ziel auswählen + Konnte nicht an ausgewähltes Ziel schreiben + Bitte wähle ein Ziel + Source and destination cannot be the same + Konnte die Datei nicht kopieren + Kopiere + A file with that name already exists 1 Ordner gelöscht diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 5dec82c60..52742dab5 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -40,6 +40,20 @@ Please choose the root folder of the SD card to grant write access on the next screen Salvar como Archivo guardado con éxito + Copy + Move + Copy/Move to + Copy item + Copy items + Source + Destination + Select destination + Could not write to the selected destination + Please select a destination + Source and destination cannot be the same + Could not copy the files + Copying + A file with that name already exists 1 carpeta eliminada diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index c2ffa03a4..3ab68075d 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -40,6 +40,20 @@ Please choose the root folder of the SD card to grant write access on the next screen Save as File saved successfully + Copia + Sposta + Copia/Sposta + Copia elemento + Copia elementi + Fonte + Destinazione + Seleziona destinazione + Impossibile scrivere nella destinazione selezionata + Seleziona una destinazione + Source and destination cannot be the same + Impossibile copiare i file + Copia in corso + A file with that name already exists 1 cartella eliminata diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 0ec1fece6..3593009b0 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -40,6 +40,20 @@ Please choose the root folder of the SD card to grant write access on the next screen Save as File saved successfully + コピー + 移動 + Copy/Move to + アイテムをコピー + アイテムをコピー + + + 宛先を選択 + 選択した宛先に書き込みできませんでした + 宛先を選択してください + Source and destination cannot be the same + ファイルをコピーできませんでした + コピー中 + A file with that name already exists 1 フォルダーを削除しました diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 9265c4201..51712c658 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -40,6 +40,20 @@ Please choose the root folder of the SD card to grant write access on the next screen Save as File saved successfully + Copiar + Mover + Copiar/Mover + Copiar item + Copiar itens + Origem + Destino + Selecionar destino + Não foi possível escrever no destino selecionado + Por favor selecione um destino + Source and destination cannot be the same + Não foi possível copiar os ficheiros + A copiar + A file with that name already exists 1 pasta eliminada diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 19dd867d6..49d91dace 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -40,6 +40,20 @@ Please choose the root folder of the SD card to grant write access on the next screen Save as File saved successfully + Kopiera + Flytta + Copy/Move to + Kopiera objekt + Kopiera objekt + Källa + Mål + Välj mål + Det gick inte att skriva till målet + Please select a destination + Source and destination cannot be the same + Kunde inte kopiera filen + Kopierar + A file with that name already exists 1 mapp borttagen diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 5c479a54e..62d6dfb44 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -14,5 +14,6 @@ 56dp 8dp + 12sp 14sp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 635446143..1bd0309e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -40,6 +40,20 @@ Please choose the root folder of the SD card to grant write access on the next screen Save as File saved successfully + Copy + Move + Copy/Move to + Copy item + Copy items + Source + Destination + Select destination + Could not write to the selected destination + Please select a destination + Source and destination cannot be the same + Could not copy the files + Copying + A file with that name already exists 1 folder deleted