diff --git a/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkFilePickerConfig.kt b/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkFilePickerConfig.kt
index ed01069..b0719e8 100644
--- a/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkFilePickerConfig.kt
+++ b/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkFilePickerConfig.kt
@@ -6,7 +6,7 @@ import androidx.annotation.StyleRes
import dev.arkbuilders.components.filepicker.R
import java.nio.file.Path
-class ArkFilePickerConfig(
+data class ArkFilePickerConfig(
@StringRes
val titleStringId: Int = R.string.ark_file_picker_pick_title,
@StringRes
diff --git a/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkFilePickerViewModel.kt b/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkFilePickerViewModel.kt
index cafe146..a065a0d 100644
--- a/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkFilePickerViewModel.kt
+++ b/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkFilePickerViewModel.kt
@@ -15,6 +15,7 @@ import dev.arkbuilders.arklib.data.folders.FoldersRepo
import dev.arkbuilders.arklib.utils.DeviceStorageUtils
import dev.arkbuilders.arklib.utils.listChildren
import dev.arkbuilders.components.utils.hasNestedOrParentalRoot
+import dev.arkbuilders.components.utils.hasNestedRoot
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.nio.file.Path
@@ -191,9 +192,8 @@ internal class ArkFilePickerViewModel(
val rootsWithFavorites = container.stateFlow.value.rootsWithFavs
val roots = rootsWithFavorites.keys
val root = roots.find { root -> file.startsWith(root) }
- val favorites = rootsWithFavorites[root]?.flatten()
- val hasNestedRoot = file.hasNestedOrParentalRoot(roots)
+ val hasNestedRoot = file.hasNestedRoot(roots)
if (hasNestedRoot) {
postSideEffect(FilePickerSideEffect.NestedRootProhibited)
@@ -203,10 +203,14 @@ internal class ArkFilePickerViewModel(
val haveRoot = haveRoot()
root?.let {
-
//Make sure file isn't inside a root folder
if (root != file) {
- val foundAsFavorite = favorites?.any { file.endsWith(it) } ?: false
+ val favorites = rootsWithFavorites.map { (root, relativeFavorites) ->
+ relativeFavorites.map {
+ root.resolve(it)
+ }
+ }.flatten()
+ val foundAsFavorite = favorites.any { it == file }
if (!foundAsFavorite) {
addFavorite(file)
diff --git a/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkRootPickerFragment.kt b/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkRootPickerFragment.kt
new file mode 100644
index 0000000..a01ccc6
--- /dev/null
+++ b/filepicker/src/main/java/dev/arkbuilders/components/filepicker/ArkRootPickerFragment.kt
@@ -0,0 +1,97 @@
+package dev.arkbuilders.components.filepicker
+
+import androidx.core.os.bundleOf
+import androidx.fragment.app.setFragmentResult
+import androidx.lifecycle.lifecycleScope
+import dev.arkbuilders.arklib.data.folders.FoldersRepo
+import dev.arkbuilders.components.utils.hasNestedRoot
+import dev.arkbuilders.components.utils.isInternalStorage
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import java.nio.file.Path
+
+class ArkRootPickerFragment : ArkFilePickerFragment() {
+ private var rootNotFavorite = false
+
+ override fun onFolderChanged(currentFolder: Path) {
+ lifecycleScope.launch {
+ val folders = FoldersRepo.instance.provideFolders()
+ val roots = folders.keys
+
+ if (currentFolder.isInternalStorage() || currentFolder.hasNestedRoot(roots)) {
+ rootNotFavorite = true
+ binding.btnPick.text = getString(R.string.ark_file_picker_root)
+ binding.btnPick.isEnabled = false
+ return@launch
+ }
+
+ val root = roots.find { root -> currentFolder.startsWith(root) }
+ root?.let {
+ if (root == currentFolder) {
+ rootNotFavorite = true
+ binding.btnPick.text = getString(R.string.ark_file_picker_root)
+ binding.btnPick.isEnabled = false
+ } else {
+ val favorites = folders.map { (root, relativeFavorites) ->
+ relativeFavorites.map {
+ root.resolve(it)
+ }
+ }.flatten()
+ val foundAsFavorite = favorites.any { it == currentFolder }
+ rootNotFavorite = false
+ binding.btnPick.text = getString(R.string.ark_file_picker_favorite)
+ binding.btnPick.isEnabled = !foundAsFavorite
+ }
+ } ?: let {
+ rootNotFavorite = true
+ binding.btnPick.text = getString(R.string.ark_file_picker_root)
+ binding.btnPick.isEnabled = true
+ }
+ }
+ }
+
+ override fun onPick(pickedPath: Path) {
+ lifecycleScope.launch(Dispatchers.IO) {
+ addRootOrFavorite(pickedPath)
+ setFragmentResult(
+ ROOT_PICKED_REQUEST_KEY,
+ bundleOf().apply {
+ putString(PICKED_PATH_BUNDLE_KEY, pickedPath.toString())
+ putBoolean(ROOT_NOT_FAV_BUNDLE_KEY, rootNotFavorite)
+ }
+ )
+ }
+ }
+
+ private suspend fun addRootOrFavorite(pickedPath: Path) {
+ val folders = FoldersRepo.instance.provideFolders()
+ if (rootNotFavorite) {
+ FoldersRepo.instance.addRoot(pickedPath)
+ } else {
+ val root = folders.keys.find { pickedPath.startsWith(it) }
+ ?: throw IllegalStateException(
+ "Can't add favorite if it's root is not added"
+ )
+ val favoriteRelativePath = root.relativize(pickedPath)
+ FoldersRepo.instance.addFavorite(root, favoriteRelativePath)
+ }
+ }
+
+ companion object {
+ const val ROOT_PICKED_REQUEST_KEY = "rootPicked"
+ const val PICKED_PATH_BUNDLE_KEY = "pickedPath"
+ const val ROOT_NOT_FAV_BUNDLE_KEY = "rootNotFav"
+
+ fun newInstance(
+ config: ArkFilePickerConfig = ArkFilePickerConfig()
+ ) = ArkRootPickerFragment().apply {
+ setConfig(
+ config.copy(
+ showRoots = false,
+ mode = ArkFilePickerMode.FOLDER,
+ pathPickedRequestKey = "notUsed"
+ )
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/filepicker/src/main/java/dev/arkbuilders/components/filepicker/FragmentManagerUtils.kt b/filepicker/src/main/java/dev/arkbuilders/components/filepicker/FragmentManagerUtils.kt
index a198434..5e451e1 100644
--- a/filepicker/src/main/java/dev/arkbuilders/components/filepicker/FragmentManagerUtils.kt
+++ b/filepicker/src/main/java/dev/arkbuilders/components/filepicker/FragmentManagerUtils.kt
@@ -20,4 +20,21 @@ fun FragmentManager.onArkPathPicked(
)
)
}
+}
+
+fun FragmentManager.onArkRootOrFavPicked(
+ lifecycleOwner: LifecycleOwner,
+ listener: (path: Path, rootNotFavorite: Boolean) -> Unit
+) {
+ setFragmentResultListener(
+ ArkRootPickerFragment.ROOT_PICKED_REQUEST_KEY,
+ lifecycleOwner
+ ) { _, bundle ->
+ listener(
+ Path(
+ bundle.getString(ArkRootPickerFragment.PICKED_PATH_BUNDLE_KEY)!!
+ ),
+ bundle.getBoolean(ArkRootPickerFragment.ROOT_NOT_FAV_BUNDLE_KEY)
+ )
+ }
}
\ No newline at end of file
diff --git a/filepicker/src/main/res/values/strings.xml b/filepicker/src/main/res/values/strings.xml
index 20116db..3ba7705 100644
--- a/filepicker/src/main/res/values/strings.xml
+++ b/filepicker/src/main/res/values/strings.xml
@@ -18,6 +18,8 @@
Only folder can be pinned.
There\'s already nested root(s) inside.
Pin
+ Root
+ Favorite
- %d item
- %d items
diff --git a/sample/src/main/java/dev/arkbuilders/sample/MainActivity.kt b/sample/src/main/java/dev/arkbuilders/sample/MainActivity.kt
index db201bd..cef3940 100644
--- a/sample/src/main/java/dev/arkbuilders/sample/MainActivity.kt
+++ b/sample/src/main/java/dev/arkbuilders/sample/MainActivity.kt
@@ -16,6 +16,7 @@ import com.google.android.material.button.MaterialButton
import dev.arkbuilders.components.filepicker.ArkFilePickerConfig
import dev.arkbuilders.components.filepicker.ArkFilePickerFragment
import dev.arkbuilders.components.filepicker.ArkFilePickerMode
+import dev.arkbuilders.components.filepicker.ArkRootPickerFragment
import dev.arkbuilders.components.filepicker.onArkPathPicked
import dev.arkbuilders.sample.about.AboutActivity
import dev.arkbuilders.sample.storage.StorageDemoFragment
@@ -39,7 +40,7 @@ class MainActivity : AppCompatActivity() {
findViewById(R.id.btn_root_picker).setOnClickListener {
resolvePermissions()
- RootFavPickerDialog
+ ArkRootPickerFragment
.newInstance()
.show(supportFragmentManager, null)
}
diff --git a/sample/src/main/java/dev/arkbuilders/sample/RootFavPickerDialog.kt b/sample/src/main/java/dev/arkbuilders/sample/RootFavPickerDialog.kt
deleted file mode 100644
index bea52c3..0000000
--- a/sample/src/main/java/dev/arkbuilders/sample/RootFavPickerDialog.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package dev.arkbuilders.sample
-
-import android.widget.Toast
-import androidx.lifecycle.lifecycleScope
-import kotlinx.coroutines.launch
-import dev.arkbuilders.arklib.data.folders.FoldersRepo
-import dev.arkbuilders.components.filepicker.ArkFilePickerConfig
-import dev.arkbuilders.components.filepicker.ArkFilePickerFragment
-import java.nio.file.Path
-
-class RootFavPickerDialog : ArkFilePickerFragment() {
- var rootNotFavorite = false
-
- override fun onFolderChanged(currentFolder: Path) {
- lifecycleScope.launch {
- val folders = FoldersRepo.instance.provideFolders()
- val roots = folders.keys
- val favorites = folders.values.flatten()
- val root = roots.find { root -> currentFolder.startsWith(root) }
- root?.let {
- if (root == currentFolder) {
- rootNotFavorite = true
- binding.btnPick.text = "Root"
- binding.btnPick.isEnabled = false
- } else {
- var foundAsFavorite = false
- favorites.forEach {
- if (currentFolder.endsWith(it)) {
- foundAsFavorite = true
- return@forEach
- }
- }
- rootNotFavorite = false
- binding.btnPick.text = "Favorite"
- binding.btnPick.isEnabled = !foundAsFavorite
- }
- } ?: let {
- rootNotFavorite = true
- binding.btnPick.text = "Root"
- binding.btnPick.isEnabled = true
- }
- }
- }
-
- override fun onPick(pickedPath: Path) {
- Toast.makeText(
- requireContext(),
- "rootNotFavorite [$rootNotFavorite]",
- Toast.LENGTH_SHORT
- ).show()
- }
-
- companion object {
- fun newInstance() = RootFavPickerDialog().apply {
- setConfig(ArkFilePickerConfig())
- }
- }
-}
\ No newline at end of file
diff --git a/utils/src/main/java/dev/arkbuilders/components/utils/PathExt.kt b/utils/src/main/java/dev/arkbuilders/components/utils/PathExt.kt
index df0d9a9..69723bc 100644
--- a/utils/src/main/java/dev/arkbuilders/components/utils/PathExt.kt
+++ b/utils/src/main/java/dev/arkbuilders/components/utils/PathExt.kt
@@ -1,10 +1,17 @@
package dev.arkbuilders.components.utils
import java.nio.file.Path
+import kotlin.io.path.Path
+
+val INTERNAL_STORAGE = Path("/storage/emulated/0")
fun Path.hasNestedOrParentalRoot(roots: Iterable): Boolean {
val hasNestedRoot = roots.any { path ->
this.startsWith(path) || path.startsWith(this)
}
return hasNestedRoot
-}
\ No newline at end of file
+}
+
+fun Path.hasNestedRoot(roots: Iterable) = roots.any { it.startsWith(this) }
+
+fun Path.isInternalStorage() = this == INTERNAL_STORAGE
\ No newline at end of file