Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move RootPicker to filepicker module #114

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

mdrlzy
Copy link
Member

@mdrlzy mdrlzy commented Dec 1, 2024

#68
Also refactor filepicker pin feature. Check only for nested roots, we can make favorites under parent root.

@@ -191,9 +192,8 @@ internal class ArkFilePickerViewModel(
val rootsWithFavorites = container.stateFlow.value.rootsWithFavs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename the function pinFile into pinFolder for more clarity?

Comment on lines 208 to 210
val favorites = rootsWithFavorites.map { (root, relativeFavorites) ->
relativeFavorites.map {
root.resolve(it)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But why rootsWithFavorites.map contains absolute paths? We should save only relative paths on disk.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Favorites in rootsWithFavorites are relative and I map them into absolute paths for check

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdrlzy I'm curious why do we have to resolve relative path into absolute path just for checking if the current being pinned folder is already a favorite, while we still can do it with the original relative paths?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that we check all favorites and not just under specific root. I didn't like the check via endsWith. But in fact everything was ok, I returned it as it was.


val hasNestedRoot = file.hasNestedOrParentalRoot(roots)
val hasNestedRoot = file.hasNestedRoot(roots)
Copy link
Collaborator

@tuancoltech tuancoltech Dec 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdrlzy By checking if a folder hasNestedOrParentalRoot, we are prohibiting pinning current folder if

  • it contains root(s)
    or
  • it is being contained by root(s)
    By changing from hasNestedOrParentalRoot to hasNestedRoot, we're ignoring every root folder that might contain currently folder, and still allow pining the current folder.

Is that our expectation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If folder has parental root, we should still be able to pin it as favorite. Now this is not possible, check the main branch yourself.
Sorry, my bad, I forgot about it when I was reviewing your PR

@@ -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")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Firstly, this path actually denotes external storage, not internal storage, so you might want to update the value and the function's name. Also, the intention is to check if a path is the root external storage (not every external storage path is a root one).
So, the name isInternalStorage is quite confusing.
What about this name? isRootExternalStorage?

Secondly, comparison using this hard-coded path is unreliable because the path is not always exactly the same on every device.
Instead, what do you think about the other approach as below?

fun File.isRootExternalStorageFolder(): Boolean {
    // Root of external storage
    val rootExternalStorage = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).parentFile
    return this.canonicalPath == rootExternalStorage?.canonicalPath
}

I guess this will work on every device regardless of the actually path value of the external storage.

Copy link
Member Author

@mdrlzy mdrlzy Dec 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal storage is meant in relation to sd card, for example there is device and sd card, the device will be internal.
Naming taken from there

With arklib we can get list of storage paths (device, sd card)
https://github.com/ARK-Builders/arklib-android/blob/main/lib/src/main/java/dev/arkbuilders/arklib/utils/FileUtils.kt
/storage/emulated/0 is needed only to show meaningful Internal storage instead of full path. User will not be able to go to /storage/emulated/, /storage/, /
Hardcode is bad, but it was simple option that covers 95% of cases
User doesn't know about internal folder of Android apps :)

How can I understand with your code whether this path belongs to device or sd card?

Actually INTERNAL_STORAGE constant is not needed here, it is already in arklib.
And I'll delete isInternalStorage, it is really confusing.

I did some research, there is an api that seems to allow to find out storage name:
https://developer.android.com/reference/android/os/storage/StorageVolume
https://github.com/zhanghai/MaterialFiles/blob/master/app/src/main/java/me/zhanghai/android/files/storage/DeviceStorage.kt

We can create a task to refactor this constant and get names through normal api.
@kirillt what do you think?

) { _, bundle ->
listener(
Path(
bundle.getString(ArkRootPickerFragment.PICKED_PATH_BUNDLE_KEY)!!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of asserting the returned string value, what about giving it a non-null fallback value?
It will never crash the app even if the value cannot be found from this bundle.

Suggested change
bundle.getString(ArkRootPickerFragment.PICKED_PATH_BUNDLE_KEY)!!
bundle.getString(ArkFilePickerFragment.PATH_PICKED_PATH_BUNDLE_KEY, "")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is key for selected path from dialog. If we return fragment result bundle without selected path, then something goes terribly wrong. We want to crash in this case.

val folders = FoldersRepo.instance.provideFolders()
val roots = folders.keys

if (currentFolder.isInternalStorage() || currentFolder.hasNestedRoot(roots)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we still allowing picking a root folder even if the folder is inside another root folder already?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If folder has parental root, we should still be able to make it favorite

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants