Anki-Android icon indicating copy to clipboard operation
Anki-Android copied to clipboard

Nicer way to enter path to put the collection

Open hssm opened this issue 9 years ago • 12 comments

Originally reported on Google Code with ID 2217

In the prefs, you can specify the path where AD stores the collection, e.g. to put it
on an external SD-card. Currently you have to type in the path via keyboard. 

It would be nice to use some kind of GUI directory picker.

The way to go seems to be to launch the user’s preferred file browser, if there is
one, and to add a simple file browser to AD as a fallback.
Maybe this one
https://github.com/iPaulPro/aFileChooser
could be used for that. Maybe there are nicer ones out there.

Is this feature available on similar apps (Anki Desktop, AnkiMobile,
AnyMemo, etc) ? If yes, it could help to include a screenshot or link to a
page explaining the feature.

Anki desktop is using standard OS file dialogs all the time…

Reported by ospalh on 2014-07-31 09:43:47

hssm avatar Jul 28 '15 10:07 hssm

Yeah it would be nice if someone has motivation

Reported by perceptualchaos2 on 2014-08-01 02:29:33

  • Status changed: Accepted
  • Labels added: Priority-Medium
  • Labels removed: Priority-Undecided

hssm avatar Jul 28 '15 10:07 hssm

For the record, if someone implements this, they can remove the integrity check I added
recently because I couldn't be bothered doing it properly as suggested by ospalh:

https://github.com/ankidroid/Anki-Android/pull/429/files

Reported by perceptualchaos2 on 2014-08-19 09:01:37

hssm avatar Jul 28 '15 10:07 hssm

Could be part of #4932 - or a PR following

mikehardy avatar Oct 08 '18 00:10 mikehardy

Hello 👋, this issue has been opened for more than 2 months with no activity on it. If the issue is still here, please keep in mind that we need community support and help to fix it! Just comment something like still searching for solutions and if you found one, please open a pull request! You have 7 days until this gets closed automatically

github-actions[bot] avatar Jun 03 '20 18:06 github-actions[bot]

I'd like to keep this open - losing your collection is/was a large reason for bad reviews, and if we can help, then it's /much/ better for the user experience.

I also want this as a dev, because I have made hundreds of test collections

david-allison avatar Jun 03 '20 19:06 david-allison

Starting in API 21, we can open a directory picker pretty easily! (

I forget how this project is--if I added a PR that opened the OS directory picker on API 21 and newer, and left it how it is for <21, would that be OK, or do we avoid that sort of thing?

adamwolf avatar Oct 30 '20 13:10 adamwolf

That would be okay - API-specific functionality. We can either put the API conditional inline if it makes sense, or you can put it in the "Compat" infrastructure, where you add an API to the Compat interface, do a fallback / lower-API implementation in the oldest one (CompatV16 right now) and in the first API that behaves the way you really want (CompatV21 in this case) you override it to be more awesome, then you call CompatHelper.getCompat().myAPI() in the code

mikehardy avatar Oct 30 '20 13:10 mikehardy

Can I work on this? I would go with the way suggested by adamwolf.

mrudultora avatar Apr 15 '21 20:04 mrudultora

My approach would be to make custom dialog preference with 3 buttons (Ok, cancel and browse). On clicking browse we would open DocumentTree and then on result we would set the directory selected by user.

mrudultora avatar Apr 16 '21 10:04 mrudultora

Even having a completion helper would be a welcome change.

Entering the path to a fat filesystem card is easy - imagine having an ext4 formatted card and typing it its UUID.

Plus, on some devices it is difficult to find the path to the card without using ADB.

yoshi314 avatar Apr 23 '22 06:04 yoshi314

Can I work on this @david-allison ?

ghost avatar Jun 07 '22 07:06 ghost

I'll be changing how this screen work due to #5304, I'd recommend another issue until the functionality is solidified

david-allison avatar Jun 07 '22 22:06 david-allison

Subject: [PATCH]  3114
---
Index: AnkiDroid/src/main/res/xml/preferences_advanced.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/res/xml/preferences_advanced.xml b/AnkiDroid/src/main/res/xml/preferences_advanced.xml
--- a/AnkiDroid/src/main/res/xml/preferences_advanced.xml	(revision 55347e636fb0c8d422b0531d16e295de7c4c0b67)
+++ b/AnkiDroid/src/main/res/xml/preferences_advanced.xml	(date 1709671181324)
@@ -25,7 +25,7 @@
     xmlns:app1="http://schemas.android.com/apk/res-auto"
     android:title="@string/pref_cat_advanced"
     android:key="@string/pref_advanced_screen_key">
-        <EditTextPreference
+        <com.ichi2.preferences.ExternalDirectorySelectionPreference
             android:defaultValue="/sdcard/AnkiDroid"
             android:key="@string/pref_ankidroid_directory_key"
             android:title="@string/col_path"
Index: AnkiDroid/src/main/java/com/ichi2/preferences/ExternalDirectorySelectionPreference.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/java/com/ichi2/preferences/ExternalDirectorySelectionPreference.kt b/AnkiDroid/src/main/java/com/ichi2/preferences/ExternalDirectorySelectionPreference.kt
new file mode 100644
--- /dev/null	(date 1709671772178)
+++ b/AnkiDroid/src/main/java/com/ichi2/preferences/ExternalDirectorySelectionPreference.kt	(date 1709671772178)
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (c) 2024 David Allison <[email protected]>
+ *
+ *  This program is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free Software
+ *  Foundation; either version 3 of the License, or (at your option) any later
+ *  version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *  PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.ichi2.preferences
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.fragment.app.DialogFragment
+import androidx.preference.EditTextPreference
+import androidx.preference.R
+import com.ichi2.anki.CollectionHelper
+import com.ichi2.utils.Permissions
+import java.io.File
+
+class ExternalDirectorySelectionPreference(context: Context, attrs: AttributeSet?) :
+    EditTextPreference(
+        context,
+        attrs,
+        styleAttr(context),
+        android.R.attr.dialogPreferenceStyle
+    ),
+    ListPreferenceTrait {
+
+
+    override fun makeDialogFragment(): DialogFragment? {
+        return if (isEditText(context)) {
+            null // use EditTextPreference
+        } else {
+            ListPreferenceDialogFragment()
+        }
+    }
+
+    // only used if a user has no file access
+    override var listEntries = CollectionHelper.getAppSpecificExternalDirectories(context).let { dirs ->
+            // This should ALWAYS start with the current AnkiDroid directory
+            listOf(File(CollectionHelper.getDefaultAnkiDroidDirectory(context))) +
+                    dirs.flatMap { findAnkiDroidSubDirectories(it) }
+        }
+        .distinct()
+        .map { ListPreferenceTrait.Entry(it.absolutePath, it.absolutePath) }
+        .toMutableList()
+
+    // TODO: This should handle persistence
+    override var listValue: String = listEntries.firstOrNull()?.value ?: ""
+
+    // In future, we may want to disable this is there is only one selection
+    override fun isEnabled() = listEntries.size > 0
+
+    companion object {
+        fun findAnkiDroidSubDirectories(f: File): List<File> {
+            // either returns '/AnkiDroid1...AnkiDroid100' from storage migration
+            // OR returns '/AnkiDroid' if no directories are available
+            return (f.listFiles()?.toList() ?: listOf<File>())
+                .filter { it.isDirectory }
+                .filter { it.name.startsWith("AnkiDroid") }
+                .ifEmpty { listOf(File(f, "AnkiDroid")) }
+        }
+
+        // TODO: Allow an override via Development Options
+        // TODO: This should be checking app private
+        private fun isEditText(context: Context) = Permissions.canManageExternalStorage(context)
+        fun styleAttr(context: Context): Int = if (isEditText(context))
+            R.attr.editTextPreferenceStyle else ListPreferenceTrait.STYLE_ATTR
+    }
+}
\ No newline at end of file

david-allison avatar Mar 05 '24 20:03 david-allison