mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Update import/delete dialog for Languages screen
This commit is contained in:
parent
3208ab3050
commit
a116eb73a2
@ -23,6 +23,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
@ -42,7 +43,7 @@ import org.futo.inputmethod.latin.Subtypes
|
||||
import org.futo.inputmethod.latin.SubtypesSetting
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItem
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
|
||||
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
||||
import org.futo.inputmethod.latin.uix.settings.ScreenTitleWithIcon
|
||||
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
||||
import org.futo.inputmethod.latin.uix.settings.Tip
|
||||
import org.futo.inputmethod.latin.uix.settings.useDataStore
|
||||
@ -98,7 +99,7 @@ fun ImportScreen(fileKind: FileKindAndInfo, file: String?, onApply: (FileKindAnd
|
||||
val importing = remember { mutableStateOf(false) }
|
||||
val importingLanguage = remember { mutableStateOf("") }
|
||||
ScrollableList {
|
||||
ScreenTitle(title = "Resource Importer")
|
||||
ScreenTitleWithIcon(title = "Import ${fileKind.kind.kindTitle()}", painter = painterResource(id = fileKind.kind.icon()))
|
||||
|
||||
if(fileKind.kind == FileKind.Invalid) {
|
||||
Text("This file does not appear to be a dictionary, voice input or transformer model. It may be an invalid file or corrupted. Please try a different file.")
|
||||
@ -111,9 +112,10 @@ fun ImportScreen(fileKind: FileKindAndInfo, file: String?, onApply: (FileKindAnd
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Text("You are importing a ${fileKind.kind.youAreImporting()}. ${fileKind.name?.let { "Info: $it" } ?: ""}", modifier = Modifier.padding(8.dp))
|
||||
|
||||
fileKind.name?.let {
|
||||
Text("Info: $it", modifier = Modifier.padding(16.dp, 8.dp))
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
|
||||
if(importing.value) {
|
||||
Box(modifier = Modifier
|
||||
@ -124,8 +126,8 @@ fun ImportScreen(fileKind: FileKindAndInfo, file: String?, onApply: (FileKindAnd
|
||||
Text("Importing for ${importingLanguage.value}", textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth())
|
||||
} else {
|
||||
Text(
|
||||
"Which language would you like to set the ${fileKind.kind.youAreImporting()} for?",
|
||||
modifier = Modifier.padding(8.dp)
|
||||
"Select the language to import for:",
|
||||
modifier = Modifier.padding(16.dp, 8.dp)
|
||||
)
|
||||
|
||||
val languages = getActiveLanguages(context).let {
|
||||
@ -163,7 +165,16 @@ enum class FileKind {
|
||||
VoiceInput,
|
||||
Transformer,
|
||||
Dictionary,
|
||||
Invalid
|
||||
Invalid;
|
||||
|
||||
fun getAddonUrlForLocale(locale: Locale?): String {
|
||||
return when(this) {
|
||||
VoiceInput -> "https://keyboard.futo.org/voice-input-models?locale=${locale?.toLanguageTag() ?: ""}"
|
||||
Transformer -> "https://keyboard.futo.org/models?locale=${locale?.toLanguageTag() ?: ""}"
|
||||
Dictionary -> "https://keyboard.futo.org/dictionaries?locale=${locale?.toLanguageTag() ?: ""}"
|
||||
Invalid -> "https://keyboard.futo.org/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun FileKind.youAreImporting(): String {
|
||||
@ -175,6 +186,25 @@ fun FileKind.youAreImporting(): String {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun FileKind.kindTitle(): String {
|
||||
return when(this) {
|
||||
FileKind.VoiceInput -> "Voice Input"
|
||||
FileKind.Transformer -> "Transformer"
|
||||
FileKind.Dictionary -> "Dictionary"
|
||||
FileKind.Invalid -> "(invalid)"
|
||||
}
|
||||
}
|
||||
|
||||
fun FileKind.icon(): Int {
|
||||
return when(this) {
|
||||
FileKind.VoiceInput -> R.drawable.mic_fill
|
||||
FileKind.Transformer -> R.drawable.cpu
|
||||
FileKind.Dictionary -> R.drawable.book
|
||||
FileKind.Invalid -> R.drawable.close
|
||||
}
|
||||
}
|
||||
|
||||
fun FileKind.extension(): String {
|
||||
return when(this) {
|
||||
FileKind.VoiceInput -> ".bin"
|
||||
|
@ -90,6 +90,19 @@ fun ScreenTitle(title: String, showBack: Boolean = false, navController: NavHost
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ScreenTitleWithIcon(title: String, painter: Painter) {
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
Icon(painter, contentDescription = "", modifier = Modifier.align(CenterVertically))
|
||||
Spacer(modifier = Modifier.width(18.dp))
|
||||
Text(title, style = Typography.titleLarge, modifier = Modifier
|
||||
.align(CenterVertically)
|
||||
.padding(0.dp, 16.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun Tip(text: String = "This is an example tip") {
|
||||
|
@ -30,7 +30,7 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.uix.ImportResourceActivity
|
||||
import org.futo.inputmethod.latin.uix.THEME_KEY
|
||||
import org.futo.inputmethod.latin.uix.USE_SYSTEM_VOICE_INPUT
|
||||
import org.futo.inputmethod.latin.uix.deferGetSetting
|
||||
@ -40,7 +40,6 @@ import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOptions
|
||||
import org.futo.inputmethod.latin.uix.theme.UixThemeWrapper
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.VoiceInputTheme
|
||||
import org.futo.inputmethod.latin.uix.urlEncode
|
||||
import org.futo.inputmethod.latin.xlm.ModelPaths
|
||||
import org.futo.inputmethod.updates.checkForUpdateAndSaveToPreferences
|
||||
import java.io.File
|
||||
@ -222,14 +221,13 @@ class SettingsActivity : ComponentActivity() {
|
||||
|
||||
if(requestCode == IMPORT_GGUF_MODEL_REQUEST && resultCode == Activity.RESULT_OK) {
|
||||
data?.data?.also { uri ->
|
||||
try {
|
||||
val model = ModelPaths.importModel(this, uri)
|
||||
navController.navigate("model/${model.absolutePath.urlEncode()}")
|
||||
}catch(error: IllegalArgumentException) {
|
||||
navController.navigateToError(getString(R.string.model_import_failed), error.message ?: getString(
|
||||
R.string.failed_to_import_the_selected_model
|
||||
))
|
||||
}
|
||||
val intent = Intent()
|
||||
intent.setClass(this, ImportResourceActivity::class.java)
|
||||
intent.setFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
)
|
||||
intent.setData(uri)
|
||||
startActivity(intent)
|
||||
}
|
||||
} else if(requestCode == EXPORT_GGUF_MODEL_REQUEST && resultCode == Activity.RESULT_OK && fileBeingSaved != null) {
|
||||
data?.data?.also { uri ->
|
||||
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@ -39,12 +40,14 @@ import org.futo.inputmethod.latin.common.Constants
|
||||
import org.futo.inputmethod.latin.uix.FileKind
|
||||
import org.futo.inputmethod.latin.uix.ResourceHelper
|
||||
import org.futo.inputmethod.latin.uix.getSetting
|
||||
import org.futo.inputmethod.latin.uix.icon
|
||||
import org.futo.inputmethod.latin.uix.kindTitle
|
||||
import org.futo.inputmethod.latin.uix.namePreferenceKeyFor
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItem
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
|
||||
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
||||
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
||||
import org.futo.inputmethod.latin.uix.settings.SettingItem
|
||||
import org.futo.inputmethod.latin.uix.settings.pages.modelmanager.openModelImporter
|
||||
import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
|
||||
import org.futo.inputmethod.latin.uix.theme.Typography
|
||||
import org.futo.inputmethod.latin.uix.youAreImporting
|
||||
@ -59,41 +62,56 @@ data class LanguageOptions(
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun ConfirmDeleteResourceDialog(
|
||||
fun ConfirmResourceActionDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
onConfirmation: () -> Unit,
|
||||
dialogTitle: String,
|
||||
dialogText: String,
|
||||
|
||||
onExplore: () -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
onImport: () -> Unit,
|
||||
|
||||
resourceKind: FileKind,
|
||||
isCurrentlySet: Boolean,
|
||||
locale: Locale
|
||||
) {
|
||||
AlertDialog(
|
||||
icon = {
|
||||
Icon(painterResource(id = R.drawable.delete), contentDescription = "Example Icon")
|
||||
Icon(painterResource(id = resourceKind.icon()), contentDescription = "Action")
|
||||
},
|
||||
title = {
|
||||
Text(text = dialogTitle)
|
||||
Text(text = "${locale.displayLanguage} - ${resourceKind.kindTitle()}")
|
||||
},
|
||||
text = {
|
||||
Text(text = dialogText)
|
||||
if(isCurrentlySet) {
|
||||
Text(text = "Would you like to delete ${resourceKind.youAreImporting()} for ${locale.displayLanguage}, or replace it with another file?")
|
||||
} else {
|
||||
Text(text = "No ${resourceKind.youAreImporting()} override is set for ${locale.displayLanguage}. You can explore downloads online, or import an existing file.")
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
onDismissRequest()
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onConfirmation()
|
||||
TextButton(onClick = {
|
||||
onImport()
|
||||
}) {
|
||||
Text(
|
||||
if(isCurrentlySet) {
|
||||
"Replace"
|
||||
} else {
|
||||
"Import"
|
||||
}
|
||||
) {
|
||||
Text("Delete")
|
||||
)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDismissRequest()
|
||||
if(isCurrentlySet) {
|
||||
TextButton(onClick = { onDelete() }) {
|
||||
Text("Delete")
|
||||
}
|
||||
} else {
|
||||
TextButton(onClick = { onExplore() }) {
|
||||
Text("Explore")
|
||||
}
|
||||
) {
|
||||
Text("Cancel")
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -119,14 +137,24 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
||||
|
||||
if(deleteDialogInfo.value != null) {
|
||||
val info = deleteDialogInfo.value!!
|
||||
ConfirmDeleteResourceDialog(
|
||||
ConfirmResourceActionDialog(
|
||||
onDismissRequest = { deleteDialogInfo.value = null },
|
||||
onConfirmation = {
|
||||
onExplore = {
|
||||
context.openURI(info.kind.getAddonUrlForLocale(info.locale), true)
|
||||
deleteDialogInfo.value = null
|
||||
},
|
||||
onDelete = {
|
||||
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."
|
||||
onImport = {
|
||||
openModelImporter(context)
|
||||
deleteDialogInfo.value = null
|
||||
},
|
||||
|
||||
resourceKind = info.kind,
|
||||
locale = info.locale,
|
||||
isCurrentlySet = runBlocking { ResourceHelper.findFileForKind(context, info.locale, info.kind)?.exists() == true }
|
||||
)
|
||||
}
|
||||
LazyColumn {
|
||||
@ -209,37 +237,25 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
||||
title = options.voiceInputModel ?: "None",
|
||||
style = options.voiceInputModel?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
||||
navigate = {
|
||||
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(FileKind.VoiceInput.icon())
|
||||
)
|
||||
NavigationItem(
|
||||
title = options.dictionary ?: "None",
|
||||
style = options.dictionary?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
||||
navigate = {
|
||||
if(runBlocking { ResourceHelper.findFileForKind(context, locale, FileKind.Dictionary) } == null) {
|
||||
context.openURI("https://keyboard.futo.org/dictionaries", true)
|
||||
} else {
|
||||
deleteDialogInfo.value = DeleteInfo(locale, FileKind.Dictionary)
|
||||
}
|
||||
},
|
||||
icon = painterResource(id = R.drawable.book)
|
||||
icon = painterResource(FileKind.Dictionary.icon())
|
||||
)
|
||||
NavigationItem(
|
||||
title = options.transformerModel ?: "None",
|
||||
style = options.transformerModel?.let { NavigationItemStyle.HomeTertiary } ?: NavigationItemStyle.MiscNoArrow,
|
||||
navigate = {
|
||||
if(options.transformerModel == null) {
|
||||
context.openURI("https://keyboard.futo.org/models", true)
|
||||
} else {
|
||||
navController.navigate("models")
|
||||
}
|
||||
},
|
||||
icon = painterResource(id = R.drawable.cpu)
|
||||
icon = painterResource(FileKind.Transformer.icon())
|
||||
)
|
||||
if(subtypes.size > 1) {
|
||||
subtypes.forEach {
|
||||
@ -260,7 +276,48 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
ScreenTitle("Other options")
|
||||
NavigationItem(
|
||||
title = "Import resource file",
|
||||
style = NavigationItemStyle.Misc,
|
||||
navigate = {
|
||||
openModelImporter(context)
|
||||
},
|
||||
)
|
||||
NavigationItem(
|
||||
title = "Explore voice input models",
|
||||
style = NavigationItemStyle.Misc,
|
||||
navigate = {
|
||||
context.openURI(
|
||||
FileKind.VoiceInput.getAddonUrlForLocale(null),
|
||||
true
|
||||
)
|
||||
},
|
||||
)
|
||||
NavigationItem(
|
||||
title = "Explore dictionaries",
|
||||
style = NavigationItemStyle.Misc,
|
||||
navigate = {
|
||||
context.openURI(
|
||||
FileKind.Dictionary.getAddonUrlForLocale(null),
|
||||
true
|
||||
)
|
||||
},
|
||||
)
|
||||
NavigationItem(
|
||||
title = "Explore transformer models",
|
||||
style = NavigationItemStyle.Misc,
|
||||
navigate = {
|
||||
context.openURI(
|
||||
FileKind.Transformer.getAddonUrlForLocale(null),
|
||||
true
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -100,12 +100,7 @@ fun ModelListScreen(navController: NavHostController = rememberNavController())
|
||||
title = "Import from file",
|
||||
style = NavigationItemStyle.Misc,
|
||||
navigate = {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "application/octet-stream"
|
||||
}
|
||||
|
||||
(context as Activity).startActivityForResult(intent, IMPORT_GGUF_MODEL_REQUEST)
|
||||
openModelImporter(context)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.futo.inputmethod.latin.uix.settings.pages.modelmanager
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.view.ContextThemeWrapper
|
||||
@ -24,6 +25,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import org.futo.inputmethod.latin.uix.settings.EXPORT_GGUF_MODEL_REQUEST
|
||||
import org.futo.inputmethod.latin.uix.settings.IMPORT_GGUF_MODEL_REQUEST
|
||||
import org.futo.inputmethod.latin.uix.settings.SettingsActivity
|
||||
import org.futo.inputmethod.latin.xlm.ModelInfo
|
||||
import org.futo.inputmethod.latin.xlm.ModelInfoLoader
|
||||
@ -141,3 +143,13 @@ fun ModelPicker(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun openModelImporter(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "application/octet-stream"
|
||||
}
|
||||
|
||||
(context as Activity).startActivityForResult(intent, IMPORT_GGUF_MODEL_REQUEST)
|
||||
}
|
Loading…
Reference in New Issue
Block a user