Skip to content

Commit

Permalink
Add drag-and-drop support for TEXT/CSV/TSV files
Browse files Browse the repository at this point in the history
  • Loading branch information
SanjaySargam committed Jan 31, 2025
1 parent b0d3758 commit 39b42f3
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 2 deletions.
2 changes: 1 addition & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ open class DeckPicker :

try {
// Intent is nullable because `clip.getItemAt(0).intent` always returns null
ImportUtils.FileImporter().handleContentProviderFile(this, uri)
ImportUtils.FileImporter().handleContentProviderFile(this, uri, Intent().setData(uri))
onResume()
} catch (e: Exception) {
Timber.w(e)
Expand Down
20 changes: 19 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/utils/ImportUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.ichi2.anki.R
import com.ichi2.anki.dialogs.DialogHandler
import com.ichi2.anki.dialogs.DialogHandlerMessage
import com.ichi2.anki.dialogs.ImportDialog
import com.ichi2.anki.onSelectedCsvForImport
import com.ichi2.anki.showImportDialog
import com.ichi2.annotations.NeedsTest
import com.ichi2.compat.CompatHelper
Expand Down Expand Up @@ -99,6 +100,19 @@ object ImportUtils {
fun isFileAValidDeck(fileName: String): Boolean =
FileImporter.hasExtension(fileName, "apkg") || FileImporter.hasExtension(fileName, "colpkg")

fun isValidTextOrDataFile(
context: Context,
uri: Uri,
): Boolean {
val mimeType = context.contentResolver.getType(uri)
return mimeType in
listOf(
"text/plain",
"text/comma-separated-values",
"text/tab-separated-values",
)
}

@SuppressWarnings("WeakerAccess")
open class FileImporter {
/**
Expand Down Expand Up @@ -200,7 +214,10 @@ object ImportUtils {
}
}
val tempOutDir: String
if (!isValidPackageName(filename)) {
if (isValidTextOrDataFile(context, importPathUri)) {
(context as Activity).onSelectedCsvForImport(intent!!)
return ImportResult.fromSuccess()
} else if (!isValidPackageName(filename)) {
return if (isAnkiDatabase(filename)) {
// .anki2 files aren't supported by Anki Desktop, we should eventually support them, because we can
// but for now, show a "nice" error.
Expand Down Expand Up @@ -242,6 +259,7 @@ object ImportUtils {
return when {
isDeckPackage(fileName) -> true
isCollectionPackage(fileName) -> true
isValidTextOrDataFile(context, importPathUri) -> true
else -> false
}
}
Expand Down
35 changes: 35 additions & 0 deletions AnkiDroid/src/test/java/com/ichi2/utils/ImportUtilsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ package com.ichi2.utils

import android.content.ClipData
import android.content.ClipDescription
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.annotation.CheckResult
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.anki.RobolectricTest
import com.ichi2.utils.ImportUtils.FileImporter
Expand All @@ -31,11 +33,44 @@ import org.hamcrest.Matchers.lessThanOrEqualTo
import org.hamcrest.Matchers.not
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.kotlin.whenever

@RunWith(AndroidJUnit4::class)
class ImportUtilsTest : RobolectricTest() {
private lateinit var context: Context
private lateinit var contentResolver: ContentResolver
private val uri = mock<Uri>()

@Before
override fun setUp() {
super.setUp()
context = ApplicationProvider.getApplicationContext()
contentResolver = mock()
whenever(context.contentResolver).thenReturn(contentResolver)
}

@Test
fun textFileIsValidForImport() {
whenever(contentResolver.getType(uri)).thenReturn("text/plain")
assertTrue(ImportUtils.isValidTextOrDataFile(context, uri))
}

@Test
fun csvFileIsValidForImport() {
whenever(contentResolver.getType(uri)).thenReturn("text/comma-separated-values")
assertTrue(ImportUtils.isValidTextOrDataFile(context, uri))
}

@Test
fun tsvFileIsValidForImport() {
whenever(contentResolver.getType(uri)).thenReturn("text/tab-separated-values")
assertTrue(ImportUtils.isValidTextOrDataFile(context, uri))
}

@Test
fun cjkNamesAreConvertedToUnicode() {
// NOTE: I don't know whether this still needs to exist, but it was added as this previously crashes
Expand Down

0 comments on commit 39b42f3

Please sign in to comment.