ark-builders / ark-navigator Goto Github PK
View Code? Open in Web Editor NEWAndroid app for navigation through your data
License: MIT License
Android app for navigation through your data
License: MIT License
In gallery mode PDF files should be depicted by it's first page.
If possible, number of pages should be depicted on top of preview.
In resources grid PDF files should be depicted by special PDF icon.
If possible, number of pages should be overlayed on top the icon.
This actually should be default screen of the app: all roots should be passed to ResourceFragment
.
The same as if a user clicks on "navigate data" tab.
But right now it crashes.
There should be "open with" button displayed on top of preview in GalleryFragment. Similar to "edit" and "delete" buttons.
The action to trigger by this button is opening the resource in an external app. E.g. video might be opened in video player or html file might be opened in web browser.
This issue will be updated with various debt about warnings.
MainActivity.kt: (55, 27): 'setOnNavigationItemSelectedListener(BottomNavigationView.OnNavigationItemSelectedListener?): Unit' is deprecated. Deprecated in Java
MainActivity.kt: (168, 15): 'onActivityResult(Int, Int, Intent?): Unit' is deprecated. Overrides deprecated member in 'androidx.activity.ComponentActivity'. Deprecated in Java
The button must shuffle current selection every time (it isn't "as-is" ordering).
Lazy shuffling could be implemented for usage with big collections: select random N resources, where N is amount of visible items in the grid; select next ones only when a user scrolls the grid or the gallery. Similar to #73.
Ideally, we should react to changes in filesystem.
E.g. if some path P maps to id A, after an external app modified P it needs to be updated to id B.
This change also must be propagated to the tags storage since id changed.
But there are some unclear moments like if an external app, in fact, moved original file untouched to another path S and put new content to the original path P. In this case, id A is still in our collection, it just was moved from P to S, so we shouldn't change tags storage regarding A but only bind A to new path S in the resources index and bind P to new resource B.
There might be other corner cases. This feature requires to be discussed before approaching.
There is a software called Syncthing: https://syncthing.net/
Our app's focus is on easy replication of data — we don't involve our own syncing mechanism, but we assume that a user can replicate his files to other devices. That's why we store tags in files inside of user-chosen folders. These storage files will be automatically replicated (whether it is by USB drive, or by syncing software like Syncthing).
But Syncthing on Android versions allows writing only into folders inside of Synthing's folder.
This makes a user to choose long paths, so we can ease this by creating a virtual device for Syncthing in our app.
Some random frame from the video would be enough.
It can be useful to overlay also duration of the video and quality.
Expected: resources are sorted with ordering type specified before.
Actual: resources are not sorted. Sorting menu displays ordering type chosen before.
Right now, the following actions can be applied to a chip (tag) in tags selector:
The desired feature is third possible action:
3. Double-tap for "focus on" the tag. After this, the tag becomes selected. Then, all tags from available set become negated. Previously selected or negated tags must not be affected.
When tags editing dialog is spawned, focus must be on the text input and keyboard must be displayed.
This reduces amount of time necessary to input a tag.
How to reproduce:
Expected:
Actual:
In current state, when a user lists resources' previews in GalleryFragment
, he can tap on a free space and this will hide controls.
It would be great to also switch picture into full-screen mode, hiding titlebar, bottom tabs switch and system topbar.
This SQL query
@Query("DELETE FROM Resource where path in (:paths)")
suspend fun deletePaths(paths: List<StringPath>)
fails when there are too much elements in paths
:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: space.taran.arknavigator, PID: 27089
E/AndroidRuntime: android.database.sqlite.SQLiteException: too many SQL variables (Sqlite code 1 SQLITE_ERROR): , while compiling: DELETE FROM Resource where path in (?,?,...,?), (OS error - 0:Success)
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:948)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:559)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:603)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:63)
at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:1166)
at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.compileStatement(FrameworkSQLiteDatabase.java:64)
at androidx.room.RoomDatabase.compileStatement(RoomDatabase.java:459)
at space.taran.arknavigator.mvp.model.dao.ResourceDao_Impl$4.call(ResourceDao_Impl.java:138)
at space.taran.arknavigator.mvp.model.dao.ResourceDao_Impl$4.call(ResourceDao_Impl.java:129)
at androidx.room.CoroutinesRoom$Companion$execute$2.invokeSuspend(CoroutinesRoom.kt:61)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at androidx.room.TransactionExecutor$1.run(TransactionExecutor.java:47)
at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:784)
D/item-container: item 8 clicked
D/gallery-screen: preview at 8 clicked, switching controls on/off
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0102]
D/gallery-screen: tag todo on resource 1771473116 long-clicked
D/gallery-screen: closing dialog in GalleryFragment
D/gallery-screen: displaying tags of resource 1771473116 for preview
D/gallery-screen: displaying tags resource 1771473116 for edit
D/OpenGLRenderer: HWUI Binary is enabled
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0102]
D/gallery-screen: tags [ark] added to 1771473116
D/mali_winsys: EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 0x3000
D/OpenGLRenderer: HWUI Binary is enabled
E/AndroidRuntime: FATAL EXCEPTION: main
Process: space.taran.arknavigator, PID: 13324
java.lang.AssertionError: Storage isn't aware about this resource id
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage$setTags$2.invokeSuspend(PlainTagsStorage.kt:62)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Asynchronous indexing (#23) will allow a user to continue working while she has some resources in indexing queue. This means, that some of resources can have modified tags and unknown (yet) id. Such resources should gain priority of indexing.
Sorting preferences must be saved between runs. E.g. if a user chooses "sort by size, descending", this choice must be still enabled even after the user left the app, or the app crashed and restarted.
Right now, if a user leaves the app on, e.g. GalleryFragment
, and switches to another app, and OS kills our app — after Android attempts to restore our app, it will crash. The reason is that Android can restore only fragments with empty constructors.
Fragments should be reworked to gain this capability, particularly GalleryFragment
and ResourcesFragment
.
Right now, if a user removes a tag (by pressing cross icon) then the dialog disappears.
But the user might be willing to remove more than 1 tag, so we should keep the dialog open.
Another improvement. It would be great if the user had the option to see the full path to the opened folder. There isn't enough space to display the full path on the header, so maybe we could show it somewhere in the white section? The header could just show the name of the current folder or something?
Huge folders can cause ResourcesFragment
freeze during sorting — sorting of 5000 resources freezes for 5 seconds on my Huawei P10. We should inform user about operation in progress. Also would be great to attach short label to any spinner animation: like "indexing" and "sorting" to provide a user with clue about what exactly takes time (so she can disable sorting for instance).
In gallery screen, a resource must be capable of edition. The "edit tags" button should be moved into tags list so its place could be used by new "edit resource" button.
Previews of image resources must be possible to zoom-in.
Right now, CRC-32 hash is used for resource identification.
Calculation of hash of some file's content can take the same time as reading the file from disk.
This should be improved. Maybe with native library.
In my experience, this reproduces not every time.
During steps 4 and 5 the "pick" button still has label "favorite".
During step 4 the "pick" button is still active.
Right now, sorting of resources causes small delays on huge collections (e.g. 5000 of pictures). After addition of persistence of sorting preferences, this delay is imposed after frequent actions: opening a folder and going back from gallery mode to resources grid.
It may be possible to perform sorting in a smarter way:
Implementation can be non-trivial, but performance would be better:
blocking phase: T * N operations to find top T resources (where N is number of all resources)
background phase: normal sorting of N - T elements
The tag on/off state is not remembered when returning back after viewing media
As you see in the video, tags were turned ON before viewing media. When returning back to the view, the button shows as OFF again
Related to #27
Every time a resource has changed, we can represent this change as a transition from id1 to id2. This transition we can store in replicated state (or send to another app instance, but it will complicate implementation and should be avoided if possible). Afterwards, it should ease conflicts resolution.
This library might be useful: https://github.com/koral--/android-gif-drawable
This is more of an improvement than a bug.
It is a few extra steps each time to open the root folders again after pressing the compass button and returning back to the Manage Folders tab.
Ideally, the app remembers the expanded and collapsed folders and displays it when the user returns back to the view
Right now, we only have predefined previews (icons) for "file" and "folder" types.
It is necessary to add icons for html, txt, doc and other types of files.
This feature is conceptually simple, but requires some smart structure in fact.
Architecturally, we should modify the counter every time we index a resource.
Visually, these counters should be placed on the folders screen.
It must be possible to edit tags, i.e. rename or delete them.
Renaming a tag from A to B walks through all resources labeled with A, removes A from them and sets B instead. Deletion of a tag X just removes it from all resources labeled with X.
Kotlin synthetics is deprecated.
There should be "share" button displayed on top of preview in GalleryFragment. Similar to "edit" and "delete" buttons.
The action to trigger by this button is sharing the resource via external app like messengers.
How to reproduce:
add a tag to the resource on the SD card
It looks like this bug does not affect Android 11
Log:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: space.taran.arknavigator, PID: 8596
java.nio.file.AccessDeniedException: /storage/1B0C-2304/DCIM/.ark-tags
at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)
at java.nio.file.spi.FileSystemProvider.newOutputStream(FileSystemProvider.java:434)
at java.nio.file.Files.newOutputStream(Files.java:216)
at java.nio.file.Files.write(Files.java:3351)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage$writeStorage$2.invokeSuspend(PlainTagsStorage.kt:174)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage$writeStorage$2.invoke(Unknown Source:8)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage$writeStorage$2.invoke(Unknown Source:4)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:161)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage.writeStorage(PlainTagsStorage.kt:165)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage.access$writeStorage(PlainTagsStorage.kt:22)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage$persist$2.invokeSuspend(PlainTagsStorage.kt:136)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage$persist$2.invoke(Unknown Source:8)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage$persist$2.invoke(Unknown Source:4)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:161)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage.persist(PlainTagsStorage.kt:90)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage.access$persist(PlainTagsStorage.kt:22)
at space.taran.arknavigator.mvp.model.repo.PlainTagsStorage$setTags$2.invokeSuspend(PlainTagsStorage.kt:68)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
When the app reads a tags storage file, it checks the format version. If the version is lower than the current one, the file must be upgraded before using.
The app must contain code for upgrades between any two adjacent versions. Backup of the file should be done before upgrade.
Such button would be useful for testing (quickly reset sorting or chosen apps to open certain types of resources).
Necessary to save state properly
It should be possible to apply some operations to selections, e.g. to move all selected resources to some folder (favorite or root) with all their tags.
It would be great, if a user could switch to other activities with the app while huge folders are being indexed.
E.g. trigger indexing of other folders or tag resources. It can happen that the user tags a resource, which is still not indexed.
Then we need to postpone modification of the storage, since we don't know the resource's id.
This means, beside of indexing queue we also need to create tagging queue.
When we load preview for an image, we should create hint for a user about size of it. Spinner animation also would not hurt. We should also verify later that even 100mb images load successfully.
Steps:
App crashes. Logs attached
log.txt
When a user opens the app, she sees folders screen. Indexing of resources should start immediately in background. All "favorites" should be placed first in the queue, "roots" follow after. Every folder must have score which is incremented every time the user opens the folder. If types of 2 folders are the same, their scores are used to order them in the queue.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.