Skip to content

Commit

Permalink
updated README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
anggrayudi committed Jun 18, 2024
1 parent e1ef249 commit 3092fd8
Showing 1 changed file with 36 additions and 32 deletions.
68 changes: 36 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ allprojects {

Simple Storage is built in Kotlin. Follow this [documentation](JAVA_COMPATIBILITY.md) to use it in your Java project.

Note that some long-running functions like copy, move, compress, and unzip are now only available in Kotlin.
They are powered by Kotlin Coroutines & Flow, which are easy to use.
You can still use these Java features in your project, but you will need [v1.5.6](https://github.com/anggrayudi/SimpleStorage/releases/tag/1.5.6) which is the latest version that
supports Java.

## Terminology

![Alt text](art/terminology.png?raw=true "Simple Storage Terms")
Expand All @@ -73,7 +78,7 @@ To check whether you have access to particular paths, call `DocumentFileCompat.g
![Alt text](art/getAccessibleAbsolutePaths.png?raw=true "DocumentFileCompat.getAccessibleAbsolutePaths()")

All paths in those locations are accessible via functions `DocumentFileCompat.from*()`, otherwise your action will be denied by the system if you want to
access paths other than those. Functions `DocumentFileCompat.from*()` (next section) will return null as well. On API 28-, you can obtain it by requesting
access paths other than those, then functions `DocumentFileCompat.from*()` (next section) will return null as well. On API 28-, you can obtain it by requesting
the runtime permission. For API 29+, it is obtained automatically by calling `SimpleStorageHelper#requestStorageAccess()` or
`SimpleStorageHelper#openFolderPicker()`. The granted paths are persisted by this library via `ContentResolver#takePersistableUriPermission()`,
so you don't need to remember them in preferences:
Expand Down Expand Up @@ -246,44 +251,43 @@ For example, you can move a folder with few lines of code:
val folder: DocumentFile = ...
val targetFolder: DocumentFile = ...

// Since moveFolderTo() is annotated with @WorkerThread, you must execute it in the background thread
folder.moveFolderTo(applicationContext, targetFolder, skipEmptyFiles = false, callback = object : FolderCallback() {
override fun onPrepare() {
// Show notification or progress bar dialog with indeterminate state
}

override fun onCountingFiles() {
// Inform user that the app is counting & calculating files
}

override fun onStart(folder: DocumentFile, totalFilesToCopy: Int, workerThread: Thread): Long {
return 1000 // update progress every 1 second
}

override fun onParentConflict(destinationFolder: DocumentFile, action: FolderCallback.ParentFolderConflictAction, canMerge: Boolean) {
handleParentFolderConflict(destinationFolder, action, canMerge)
ioScope.launch {
folder.moveFolderTo(applicationContext, targetFolder, skipEmptyFiles = false, updateInterval = 1000, onConflict = object : FolderConflictCallback(uiScope) {
override fun onParentConflict(destinationFolder: DocumentFile, action: ParentFolderConflictAction, canMerge: Boolean) {
handleParentFolderConflict(destinationFolder, action, canMerge)
}

override fun onContentConflict(
destinationFolder: DocumentFile,
conflictedFiles: MutableList<FolderCallback.FileConflict>,
action: FolderCallback.FolderContentConflictAction
destinationFolder: DocumentFile,
conflictedFiles: MutableList<FileConflict>,
action: FolderContentConflictAction
) {
handleFolderContentConflict(action, conflictedFiles)
}

override fun onReport(report: Report) {
Timber.d("onReport() -> ${report.progress.toInt()}% | Copied ${report.fileCount} files")
handleFolderContentConflict(action, conflictedFiles)
}

override fun onCompleted(result: Result) {
Toast.makeText(baseContext, "Copied ${result.totalCopiedFiles} of ${result.totalFilesToCopy} files", Toast.LENGTH_SHORT).show()
}).onCompletion {
if (it is CancellationException) {
Timber.d("Folder move is aborted")
}

override fun onFailed(errorCode: ErrorCode) {
Toast.makeText(baseContext, "An error has occurred: $errorCode", Toast.LENGTH_SHORT).show()
}.collect { result ->
when (result) {
is FolderResult.Validating -> Timber.d("Validating...")
is FolderResult.Preparing -> Timber.d("Preparing...")
is FolderResult.CountingFiles -> Timber.d("Counting files...")
is FolderResult.DeletingConflictedFiles -> Timber.d("Deleting conflicted files...")
is FolderResult.Starting -> Timber.d("Starting...")
is FolderResult.InProgress -> Timber.d("Progress: ${result.progress.toInt()}% | ${result.fileCount} files")
is FolderResult.Completed -> uiScope.launch {
Timber.d("Completed: ${result.totalCopiedFiles} of ${result.totalFilesToCopy} files")
Toast.makeText(baseContext, "Moved ${result.totalCopiedFiles} of ${result.totalFilesToCopy} files", Toast.LENGTH_SHORT).show()
}

is FolderResult.Error -> uiScope.launch {
Timber.e(result.errorCode.name)
Toast.makeText(baseContext, "An error has occurred: ${result.errorCode.name}", Toast.LENGTH_SHORT).show()
}
}
})
}
}
```

The coolest thing of this library is you can ask users to choose Merge, Replace, Create New, or Skip Duplicate folders & files
Expand Down

0 comments on commit 3092fd8

Please sign in to comment.