mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Allow deleting imported dictionaries and voice input models
This commit is contained in:
parent
626477a027
commit
31b5fe933e
@ -266,6 +266,18 @@ object ResourceHelper {
|
|||||||
Dictionary.TYPE_MAIN
|
Dictionary.TYPE_MAIN
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteResourceForLanguage(context: Context, kind: FileKind, locale: Locale) {
|
||||||
|
val setting = kind.preferencesKeyFor(locale.toString())
|
||||||
|
val value = runBlocking { context.getSetting(setting, "") }
|
||||||
|
if(value.isNotBlank()) {
|
||||||
|
runBlocking { context.setSetting(setting, "") }
|
||||||
|
val file = File(context.getExternalFilesDir(null), value)
|
||||||
|
file.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
LatinIMELegacy.mPendingDictionaryUpdate = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImportResourceActivity : ComponentActivity() {
|
class ImportResourceActivity : ComponentActivity() {
|
||||||
@ -314,7 +326,7 @@ class ImportResourceActivity : ComponentActivity() {
|
|||||||
applicationContext.setSetting(key, outputFileName)
|
applicationContext.setSetting(key, outputFileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LatinIMELegacy.mPendingDictionaryUpdate = true;
|
LatinIMELegacy.mPendingDictionaryUpdate = true
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.clickable
|
|||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
@ -15,6 +16,8 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
@ -33,6 +36,7 @@ import org.futo.inputmethod.latin.uix.VERBOSE_PROGRESS
|
|||||||
import org.futo.inputmethod.latin.uix.getSetting
|
import org.futo.inputmethod.latin.uix.getSetting
|
||||||
import org.futo.inputmethod.latin.uix.voiceinput.downloader.DownloadActivity
|
import org.futo.inputmethod.latin.uix.voiceinput.downloader.DownloadActivity
|
||||||
import org.futo.inputmethod.latin.xlm.UserDictionaryObserver
|
import org.futo.inputmethod.latin.xlm.UserDictionaryObserver
|
||||||
|
import org.futo.inputmethod.updates.openURI
|
||||||
import org.futo.voiceinput.shared.ModelDoesNotExistException
|
import org.futo.voiceinput.shared.ModelDoesNotExistException
|
||||||
import org.futo.voiceinput.shared.RecognizerView
|
import org.futo.voiceinput.shared.RecognizerView
|
||||||
import org.futo.voiceinput.shared.RecognizerViewListener
|
import org.futo.voiceinput.shared.RecognizerViewListener
|
||||||
@ -224,15 +228,18 @@ private class VoiceInputNoModelWindow(val locale: Locale) : ActionWindow {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun WindowContents(keyboardShown: Boolean) {
|
override fun WindowContents(keyboardShown: Boolean) {
|
||||||
|
val context = LocalContext.current
|
||||||
Box(modifier = Modifier
|
Box(modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.clickable(enabled = true,
|
.clickable(enabled = true,
|
||||||
onClickLabel = null,
|
onClickLabel = null,
|
||||||
onClick = { TODO() },
|
onClick = {
|
||||||
|
context.openURI("https://keyboard.futo.org/voice-input-models", true)
|
||||||
|
},
|
||||||
role = null,
|
role = null,
|
||||||
indication = null,
|
indication = null,
|
||||||
interactionSource = remember { MutableInteractionSource() })) {
|
interactionSource = remember { MutableInteractionSource() })) {
|
||||||
Text("No model available for ${locale.displayLanguage}, tap to check options?", modifier = Modifier.align(Alignment.Center))
|
Text("No voice input model installed for ${locale.displayLanguage}, tap to check options?", modifier = Modifier.align(Alignment.Center).padding(8.dp), textAlign = TextAlign.Center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
package org.futo.inputmethod.latin.uix.settings.pages
|
package org.futo.inputmethod.latin.uix.settings.pages
|
||||||
|
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -20,6 +26,7 @@ import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
|||||||
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
||||||
import org.futo.inputmethod.latin.uix.settings.Tip
|
import org.futo.inputmethod.latin.uix.settings.Tip
|
||||||
import org.futo.inputmethod.latin.uix.settings.openLanguageSettings
|
import org.futo.inputmethod.latin.uix.settings.openLanguageSettings
|
||||||
|
import org.futo.inputmethod.latin.uix.youAreImporting
|
||||||
import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils
|
import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils
|
||||||
import org.futo.inputmethod.latin.xlm.ModelPaths
|
import org.futo.inputmethod.latin.xlm.ModelPaths
|
||||||
import org.futo.inputmethod.updates.openURI
|
import org.futo.inputmethod.updates.openURI
|
||||||
@ -31,11 +38,69 @@ data class LanguageOptions(
|
|||||||
val transformerModel: String?
|
val transformerModel: String?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ConfirmDeleteResourceDialog(
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
onConfirmation: () -> Unit,
|
||||||
|
dialogTitle: String,
|
||||||
|
dialogText: String,
|
||||||
|
) {
|
||||||
|
AlertDialog(
|
||||||
|
icon = {
|
||||||
|
Icon(painterResource(id = R.drawable.delete), contentDescription = "Example Icon")
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
Text(text = dialogTitle)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(text = dialogText)
|
||||||
|
},
|
||||||
|
onDismissRequest = {
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
onConfirmation()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text("Delete")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
onDismissRequest()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text("Cancel")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class DeleteInfo(
|
||||||
|
val locale: Locale,
|
||||||
|
val kind: FileKind
|
||||||
|
)
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun LanguagesScreen(navController: NavHostController = rememberNavController()) {
|
fun LanguagesScreen(navController: NavHostController = rememberNavController()) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val deleteDialogInfo: MutableState<DeleteInfo?> = remember { mutableStateOf(null) }
|
||||||
|
if(deleteDialogInfo.value != null) {
|
||||||
|
val info = deleteDialogInfo.value!!
|
||||||
|
ConfirmDeleteResourceDialog(
|
||||||
|
onDismissRequest = { deleteDialogInfo.value = null },
|
||||||
|
onConfirmation = {
|
||||||
|
ResourceHelper.deleteResourceForLanguage(context, info.kind, info.locale)
|
||||||
|
deleteDialogInfo.value = null
|
||||||
|
},
|
||||||
|
dialogTitle = "Delete ${info.kind.youAreImporting()} for ${info.locale.displayLanguage}?",
|
||||||
|
dialogText = "If deleted, the imported ${info.kind.youAreImporting()} file for ${info.locale.displayLanguage} will be deleted. If there is no built-in fallback for this language, the feature may cease to function. You can always download and re-import a different ${info.kind.youAreImporting()} file."
|
||||||
|
)
|
||||||
|
}
|
||||||
ScrollableList {
|
ScrollableList {
|
||||||
ScreenTitle("Languages", showBack = true, navController)
|
ScreenTitle("Languages", showBack = true, navController)
|
||||||
|
|
||||||
@ -55,10 +120,7 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
|||||||
val voiceInputModelName = ResourceHelper.tryFindingVoiceInputModelForLocale(context, locale)?.name?.let { stringResource(it) }
|
val voiceInputModelName = ResourceHelper.tryFindingVoiceInputModelForLocale(context, locale)?.name?.let { stringResource(it) }
|
||||||
val dictionaryName = runBlocking { ResourceHelper.findFileForKind(context, locale, FileKind.Dictionary) }?.let {
|
val dictionaryName = runBlocking { ResourceHelper.findFileForKind(context, locale, FileKind.Dictionary) }?.let {
|
||||||
"Imported Dictionary"
|
"Imported Dictionary"
|
||||||
} ?: if(BinaryDictionaryGetter.getDictionaryFiles(locale, context, false, false).let {
|
} ?: if(BinaryDictionaryGetter.getDictionaryFiles(locale, context, false, false).isNotEmpty()) {
|
||||||
println("DICTIONARIES FOR ${locale.displayLanguage}: ${it.toList().map { it.mFilename }.joinToString(",")}")
|
|
||||||
it
|
|
||||||
}.isNotEmpty()) {
|
|
||||||
"Built-in Dictionary"
|
"Built-in Dictionary"
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@ -80,7 +142,11 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
|||||||
title = options.voiceInputModel ?: "None",
|
title = options.voiceInputModel ?: "None",
|
||||||
style = options.voiceInputModel?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
style = options.voiceInputModel?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
||||||
navigate = {
|
navigate = {
|
||||||
context.openURI("https://keyboard.futo.org/voice-input-models", true)
|
if(runBlocking { ResourceHelper.findFileForKind(context, locale, FileKind.VoiceInput) } == null) {
|
||||||
|
context.openURI("https://keyboard.futo.org/voice-input-models", true)
|
||||||
|
} else {
|
||||||
|
deleteDialogInfo.value = DeleteInfo(locale, FileKind.VoiceInput)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
icon = painterResource(id = R.drawable.mic_fill)
|
icon = painterResource(id = R.drawable.mic_fill)
|
||||||
)
|
)
|
||||||
@ -88,7 +154,14 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
|||||||
title = options.dictionary ?: "None",
|
title = options.dictionary ?: "None",
|
||||||
style = options.dictionary?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
style = options.dictionary?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
||||||
navigate = {
|
navigate = {
|
||||||
context.openURI("https://codeberg.org/Helium314/aosp-dictionaries#dictionaries", true)
|
if(runBlocking { ResourceHelper.findFileForKind(context, locale, FileKind.Dictionary) } == null) {
|
||||||
|
context.openURI(
|
||||||
|
"https://codeberg.org/Helium314/aosp-dictionaries#dictionaries",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
deleteDialogInfo.value = DeleteInfo(locale, FileKind.Dictionary)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
icon = painterResource(id = R.drawable.book)
|
icon = painterResource(id = R.drawable.book)
|
||||||
)
|
)
|
||||||
@ -96,7 +169,11 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
|||||||
title = options.transformerModel ?: "None",
|
title = options.transformerModel ?: "None",
|
||||||
style = options.transformerModel?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
style = options.transformerModel?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
||||||
navigate = {
|
navigate = {
|
||||||
context.openURI("https://keyboard.futo.org/models", true)
|
if(options.transformerModel == null) {
|
||||||
|
context.openURI("https://keyboard.futo.org/models", true)
|
||||||
|
} else {
|
||||||
|
navController.navigate("models")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
icon = painterResource(id = R.drawable.cpu)
|
icon = painterResource(id = R.drawable.cpu)
|
||||||
)
|
)
|
||||||
|
@ -25,6 +25,7 @@ import org.futo.inputmethod.latin.xlm.ModelInfo
|
|||||||
import org.futo.inputmethod.latin.xlm.ModelPaths
|
import org.futo.inputmethod.latin.xlm.ModelPaths
|
||||||
import org.futo.inputmethod.updates.openURI
|
import org.futo.inputmethod.updates.openURI
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ModelNavigationItem(navController: NavHostController, name: String, isPrimary: Boolean, path: String) {
|
fun ModelNavigationItem(navController: NavHostController, name: String, isPrimary: Boolean, path: String) {
|
||||||
@ -68,7 +69,7 @@ fun ModelListScreen(navController: NavHostController = rememberNavController())
|
|||||||
|
|
||||||
modelsByLanguage.forEach { item ->
|
modelsByLanguage.forEach { item ->
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
ScreenTitle(item.key)
|
ScreenTitle(Locale(item.key).displayLanguage)
|
||||||
|
|
||||||
item.value.forEach { model ->
|
item.value.forEach { model ->
|
||||||
val name = if (model.finetune_count > 0) {
|
val name = if (model.finetune_count > 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user