app/src/main/kotlin/space/subread/anki/Requests.kt (4220 bytes)
1 package space.subread.anki 2 3 import android.content.Intent 4 import android.net.Uri 5 import androidx.core.content.IntentCompat 6 import space.subread.anki.core.MineRequest 7 import space.subread.anki.core.SharedText 8 9 /** Reads a [MineRequest] from each kind of Intent that [AddActivity] takes. */ 10 object Requests { 11 12 /** The action for another app: the extras below, any subset of them. */ 13 const val ACTION_ADD = "space.subread.anki.action.ADD" 14 15 /** Each key of [MineRequest.KEYS], in upper case, after this prefix: `space.subread.anki.extra.SENTENCE`. */ 16 const val EXTRA_PREFIX = "space.subread.anki.extra." 17 18 /** In the result of the activity: the id of the note in AnkiDroid (`Long`). */ 19 const val EXTRA_NOTE_ID = "space.subread.anki.extra.NOTE_ID" 20 21 /** In the result of the activity: why no card was added (`String`). */ 22 const val EXTRA_ERROR = "space.subread.anki.extra.ERROR" 23 24 /** The name of the extra for a key of [MineRequest]. */ 25 fun extraName(key: String): String = EXTRA_PREFIX + key.uppercase() 26 27 /** 28 * The request in an Intent, or null when the Intent is none of the kinds the app takes. 29 * A text from the selection menu or the share sheet is the word. A picture from the 30 * share sheet is the picture, with the text beside it as the word. A browser shares the 31 * link of the page with the text: the link does not go on the card. 32 */ 33 fun fromIntent(intent: Intent): MineRequest? = when (intent.action) { 34 Intent.ACTION_PROCESS_TEXT -> MineRequest(expression = intent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT)?.toString()) 35 Intent.ACTION_SEND -> { 36 val stream = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java) 37 val text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT)?.toString()?.let(SharedText::clean) 38 MineRequest(expression = text?.ifEmpty { null }, image = stream?.toString()) 39 } 40 Intent.ACTION_VIEW -> { 41 // A web page: the query of the link. An intent: link can carry extras too; they win. 42 val fromQuery = MineRequest.parseQuery(intent.data?.encodedQuery) 43 MineRequest.fromMap(fromQuery + fromExtras(intent)) 44 } 45 ACTION_ADD -> MineRequest.fromMap(fromExtras(intent)) 46 else -> null 47 } 48 49 /** 50 * The extras of the request, as strings. A Uri, a number and a boolean are written as text. 51 * 52 * The extras of the intent API of the main branch are taken too, with their meaning there: 53 * `WORD` is the word, `TEXT` a text with no word chosen, `AUDIO` the audio of the word, 54 * `SENTENCE_AUDIO` the audio of the sentence, `SHOW` the same as `CONFIRM`. SubRead 55 * Overlay and SubRead Dictionary send those. 56 */ 57 fun fromExtras(intent: Intent): Map<String, String> { 58 val extras = intent.extras ?: return emptyMap() 59 val out = LinkedHashMap<String, String>() 60 fun text(name: String): String? { 61 @Suppress("DEPRECATION") // The value can be of any type: only the untyped get tells which. 62 val value = extras.get(name) ?: return null 63 return if (value is Boolean) (if (value) "1" else "0") else value.toString() 64 } 65 for (key in MineRequest.KEYS) text(extraName(key))?.let { out[key] = it } 66 val other = text(EXTRA_PREFIX + "WORD") != null || text(EXTRA_PREFIX + "TEXT") != null 67 if (other) { 68 text(EXTRA_PREFIX + "WORD")?.let { out[MineRequest.KEY_EXPRESSION] = it } 69 text(EXTRA_PREFIX + "TEXT")?.let { out.putIfAbsent(MineRequest.KEY_SENTENCE, it) } 70 text(EXTRA_PREFIX + "AUDIO")?.let { out[MineRequest.KEY_WORD_AUDIO] = it } 71 out.remove(MineRequest.KEY_AUDIO) 72 text(EXTRA_PREFIX + "SENTENCE_AUDIO")?.let { out[MineRequest.KEY_AUDIO] = it } 73 text(EXTRA_PREFIX + "SHOW")?.let { out.putIfAbsent(MineRequest.KEY_CONFIRM, it) } 74 } 75 return out 76 } 77 78 /** The Intent for another app on the device: the request as extras of [ACTION_ADD]. */ 79 fun toIntent(request: MineRequest): Intent = Intent(ACTION_ADD).apply { 80 for ((key, value) in request.toMap()) putExtra(extraName(key), value) 81 } 82 }