|
@@ -11,6 +11,22 @@ import io.reactivex.android.schedulers.AndroidSchedulers
|
|
|
import io.reactivex.disposables.Disposable
|
|
|
import io.reactivex.schedulers.Schedulers
|
|
|
import java.io.File
|
|
|
+import java.lang.Exception
|
|
|
+
|
|
|
+/**
|
|
|
+ * 1. if info.shouldCopyFile == false,
|
|
|
+ * just call onCopySuccess() to send Event.Success(destination path)
|
|
|
+ * 2. if source path == destination path,
|
|
|
+ * just call onCopySuccess() to send Event.Success(destination path)
|
|
|
+ * 3. if the application has no permission,
|
|
|
+ * send Event.Failed(destination path, FileNotFoundException) and delete the destination file
|
|
|
+ * 4. if an IOException is thrown during copying,
|
|
|
+ * send Event.Failed(destination path, IOException) and delete the destination file
|
|
|
+ * 5. otherwise, when CopyFileViewModel finishes copying file,
|
|
|
+ * call onCopySuccess() to send Event.Success(destination path)
|
|
|
+ *
|
|
|
+ * Finally, when CopyFileViewModel::onCleared() is called, delete the destination file if it is not complete copied
|
|
|
+*/
|
|
|
|
|
|
class CopyFileViewModel(applicationContext: Context,
|
|
|
private val info: CopyFileInfo,
|
|
@@ -28,6 +44,7 @@ class CopyFileViewModel(applicationContext: Context,
|
|
|
private val mCopyProgressLiveData = MutableLiveData<Int>().apply { value = 0 }
|
|
|
|
|
|
private var copyFileDisposable: Disposable? = null
|
|
|
+ private var srcFilePath: String? = null
|
|
|
private var dstFilePath: String? = null
|
|
|
private var hasCompleteCopy = false
|
|
|
|
|
@@ -38,31 +55,47 @@ class CopyFileViewModel(applicationContext: Context,
|
|
|
fun copyFile(applicationContext: Context) {
|
|
|
if (!info.shouldCopyFile) {
|
|
|
onCopySuccess()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ val source = if (!info.filePath.isNullOrEmpty()) {
|
|
|
+ FilePathSource(info.filePath!!)
|
|
|
+ } else if (info.isActionView && null != info.uri) {
|
|
|
+ FileUriSource(applicationContext, info.uri)
|
|
|
} else {
|
|
|
- val source = if (!info.filePath.isNullOrEmpty()) {
|
|
|
- FilePathSource(info.filePath!!)
|
|
|
- } else if (info.isActionView && null != info.uri) {
|
|
|
- FileUriSource(applicationContext, info.uri)
|
|
|
- } else {
|
|
|
- null
|
|
|
- }
|
|
|
- val fullFileSize = Math.max(1, source?.getFileSize() ?: 1)
|
|
|
- val task = CopyFileTask()
|
|
|
- task.setCopyMode(CopyFileTask.Mode.CREATE_NEW_FILE)
|
|
|
- task.setTargetFolder(FileUtil.getKdanPDFReaderFolder())
|
|
|
- dstFilePath = task.generateUniqueFilePath(source)
|
|
|
-
|
|
|
- copyFileDisposable = task.copyFile(source)
|
|
|
- .subscribeOn(Schedulers.io())
|
|
|
- .observeOn(AndroidSchedulers.mainThread())
|
|
|
- .subscribe({
|
|
|
- val progress = Math.min(100, (it * 100.0 / fullFileSize).toInt())
|
|
|
- onCopyProgressUpdate(progress)
|
|
|
- }, {
|
|
|
- onCopyFailed(it)
|
|
|
- }, {
|
|
|
- onCopySuccess()
|
|
|
- })
|
|
|
+ null
|
|
|
+ }
|
|
|
+ srcFilePath = source?.getFilePath()
|
|
|
+ if (isSrcFileEqualsDstFile()) {
|
|
|
+ onCopySuccess()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ val fullFileSize = Math.max(1, source?.getFileSize() ?: 1)
|
|
|
+ val task = CopyFileTask()
|
|
|
+ task.setCopyMode(CopyFileTask.Mode.CREATE_NEW_FILE)
|
|
|
+ task.setTargetFolder(FileUtil.getKdanPDFReaderFolder())
|
|
|
+ dstFilePath = task.generateUniqueFilePath(source)
|
|
|
+
|
|
|
+ copyFileDisposable = task.copyFile(source)
|
|
|
+ .subscribeOn(Schedulers.io())
|
|
|
+ .observeOn(AndroidSchedulers.mainThread())
|
|
|
+ .subscribe({
|
|
|
+ val progress = Math.min(100, (it * 100.0 / fullFileSize).toInt())
|
|
|
+ onCopyProgressUpdate(progress)
|
|
|
+ }, {
|
|
|
+ onCopyFailed(it)
|
|
|
+ }, {
|
|
|
+ onCopySuccess()
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // check the destination path is the same with the source path or not
|
|
|
+ private fun isSrcFileEqualsDstFile(): Boolean {
|
|
|
+ return try {
|
|
|
+ (!srcFilePath.isNullOrEmpty() && File(srcFilePath).canonicalPath == File(dstFilePath).canonicalPath)
|
|
|
+ } catch (e: Exception) {
|
|
|
+ false
|
|
|
}
|
|
|
}
|
|
|
|