mirror of
https://github.com/florisboard/florisboard.git
synced 2024-09-19 19:42:20 +02:00
Add new SubtypeSupportInfo API to NlpProvider
This new API allows the UI to dynamically check if a subtype is supported by a given NLP Provider.
This commit is contained in:
parent
857e315e6c
commit
e70a84bea7
@ -46,6 +46,7 @@ import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
|
||||
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedText
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
@ -252,7 +253,7 @@ private fun FlorisInvalidPluginBox(plugin: IndexedPlugin) {
|
||||
val reason = (plugin.state as IndexedPluginState.Error).toString()
|
||||
FlorisOutlinedBox(modifier = Modifier.defaultFlorisOutlinedBox()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
modifier = Modifier.defaultFlorisOutlinedText(),
|
||||
text = "Unrecognised plugin with service name ${plugin.serviceName}\n\nReason: $reason",
|
||||
color = MaterialTheme.colors.error,
|
||||
fontStyle = FontStyle.Italic,
|
||||
|
@ -34,8 +34,10 @@ import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
@ -54,6 +56,7 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.core.ComputedSubtype
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.core.SubtypeJsonConfig
|
||||
@ -63,15 +66,19 @@ import dev.patrickgold.florisboard.ime.core.SubtypePreset
|
||||
import dev.patrickgold.florisboard.ime.keyboard.LayoutArrangementComponent
|
||||
import dev.patrickgold.florisboard.ime.keyboard.LayoutType
|
||||
import dev.patrickgold.florisboard.ime.keyboard.extCorePopupMapping
|
||||
import dev.patrickgold.florisboard.ime.nlp.SubtypeSupportInfo
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisDropdownLikeButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisDropdownMenu
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedText
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.nlpManager
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
@ -83,6 +90,7 @@ private val SelectComponentName = ExtensionComponentName("00", "00")
|
||||
private val SelectNlpProviderId = SelectComponentName.toString()
|
||||
private val SelectNlpProviders = SubtypeNlpProviderMap(
|
||||
spelling = SelectNlpProviderId,
|
||||
suggestion = SelectNlpProviderId,
|
||||
)
|
||||
private val SelectLayoutMap = SubtypeLayoutMap(
|
||||
characters = SelectComponentName,
|
||||
@ -96,6 +104,7 @@ private val SelectLayoutMap = SubtypeLayoutMap(
|
||||
)
|
||||
private val SelectLocale = FlorisLocale.from("00", "00")
|
||||
private val SelectListKeys = listOf(SelectComponentName)
|
||||
private val SelectNlpProviderKeys = listOf(SelectNlpProviderId)
|
||||
|
||||
private class SubtypeEditorState(init: Subtype?) {
|
||||
companion object {
|
||||
@ -124,10 +133,11 @@ private class SubtypeEditorState(init: Subtype?) {
|
||||
val id: MutableState<Long> = mutableStateOf(init?.id ?: -1)
|
||||
val primaryLocale: MutableState<FlorisLocale> = mutableStateOf(init?.primaryLocale ?: SelectLocale)
|
||||
val secondaryLocales: MutableState<List<FlorisLocale>> = mutableStateOf(init?.secondaryLocales ?: listOf())
|
||||
val nlpProviders: MutableState<SubtypeNlpProviderMap> = mutableStateOf(init?.nlpProviders ?: Subtype.FALLBACK.nlpProviders)
|
||||
val nlpProviders: MutableState<SubtypeNlpProviderMap> = mutableStateOf(init?.nlpProviders ?: SelectNlpProviders)
|
||||
val composer: MutableState<ExtensionComponentName> = mutableStateOf(init?.composer ?: SelectComponentName)
|
||||
val currencySet: MutableState<ExtensionComponentName> = mutableStateOf(init?.currencySet ?: SelectComponentName)
|
||||
val punctuationRule: MutableState<ExtensionComponentName> = mutableStateOf(init?.punctuationRule ?: Subtype.FALLBACK.punctuationRule)
|
||||
val punctuationRule: MutableState<ExtensionComponentName> =
|
||||
mutableStateOf(init?.punctuationRule ?: Subtype.FALLBACK.punctuationRule)
|
||||
val popupMapping: MutableState<ExtensionComponentName> = mutableStateOf(init?.popupMapping ?: SelectComponentName)
|
||||
val layoutMap: MutableState<SubtypeLayoutMap> = mutableStateOf(init?.layoutMap ?: SelectLayoutMap)
|
||||
|
||||
@ -168,14 +178,16 @@ private class SubtypeEditorState(init: Subtype?) {
|
||||
|
||||
@Composable
|
||||
fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
|
||||
title = stringRes(if (id == null) {
|
||||
R.string.settings__localization__subtype_add_title
|
||||
} else {
|
||||
R.string.settings__localization__subtype_edit_title
|
||||
})
|
||||
title = stringRes(
|
||||
if (id == null) {
|
||||
R.string.settings__localization__subtype_add_title
|
||||
} else {
|
||||
R.string.settings__localization__subtype_edit_title
|
||||
}
|
||||
)
|
||||
|
||||
val selectValue = stringRes(R.string.settings__localization__subtype_select_placeholder)
|
||||
val selectListValues = remember (selectValue) { listOf(selectValue) }
|
||||
val selectListValues = remember(selectValue) { listOf(selectValue) }
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val navController = LocalNavController.current
|
||||
@ -183,6 +195,7 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
|
||||
val configuration = LocalConfiguration.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
val nlpManager by context.nlpManager()
|
||||
val subtypeManager by context.subtypeManager()
|
||||
|
||||
val displayLanguageNamesIn by prefs.localization.displayLanguageNamesIn.observeAsState()
|
||||
@ -267,9 +280,10 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
|
||||
content {
|
||||
Column(modifier = Modifier.padding(8.dp)) {
|
||||
if (id == null) {
|
||||
Card(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(vertical = 8.dp)) {
|
||||
Text(
|
||||
@ -303,7 +317,9 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
|
||||
},
|
||||
text = when (displayLanguageNamesIn) {
|
||||
DisplayLanguageNamesIn.SYSTEM_LOCALE -> suggestedPreset.locale.displayName()
|
||||
DisplayLanguageNamesIn.NATIVE_LOCALE -> suggestedPreset.locale.displayName(suggestedPreset.locale)
|
||||
DisplayLanguageNamesIn.NATIVE_LOCALE -> suggestedPreset.locale.displayName(
|
||||
suggestedPreset.locale
|
||||
)
|
||||
},
|
||||
secondaryText = suggestedPreset.preferred.characters.componentId,
|
||||
)
|
||||
@ -373,16 +389,21 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
|
||||
|
||||
SubtypeGroupSpacer()
|
||||
|
||||
/*SubtypeProperty(stringRes(R.string.settings__localization__subtype_suggestion_provider)) {
|
||||
SubtypeProperty(stringRes(R.string.settings__localization__subtype_suggestion_provider)) {
|
||||
// TODO: Put this map somewhere more formal (another KeyboardExtension field?)
|
||||
// optionally use a string resource below
|
||||
val nlpProviderMappings = mapOf(
|
||||
LatinLanguageProvider.ProviderId to "Latin",
|
||||
HanShapeBasedLanguageProvider.ProviderId to "Chinese shape-based"
|
||||
)
|
||||
val plugins by nlpManager.plugins.pluginIndexFlow.collectAsState()
|
||||
val nlpProviderMappings = remember(plugins) {
|
||||
buildMap {
|
||||
for (plugin in plugins) {
|
||||
val packageContext = plugin.packageContext()
|
||||
put(plugin.metadata.id, plugin.metadata.title.getOrNull(packageContext) ?: "??")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val nlpProviderMappingIds = remember(nlpProviderMappings) {
|
||||
SelectListKeys + nlpProviderMappings.keys
|
||||
SelectNlpProviderKeys + nlpProviderMappings.keys
|
||||
}
|
||||
val nlpProviderMappingLabels = remember(nlpProviderMappings) {
|
||||
selectListValues + nlpProviderMappings.values.map { it }
|
||||
@ -394,14 +415,64 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
|
||||
expanded = expanded,
|
||||
selectedIndex = selectedIndex,
|
||||
isError = showSelectAsError && selectedIndex == 0,
|
||||
onSelectItem = { nlpProviders = SubtypeNlpProviderMap(
|
||||
suggestion = nlpProviderMappingIds[it] as String,
|
||||
spelling = nlpProviderMappingIds[it] as String
|
||||
) },
|
||||
onSelectItem = {
|
||||
nlpProviders = SubtypeNlpProviderMap(
|
||||
suggestion = nlpProviderMappingIds[it],
|
||||
spelling = nlpProviderMappingIds[it],
|
||||
)
|
||||
},
|
||||
onExpandRequest = { expanded = true },
|
||||
onDismissRequest = { expanded = false },
|
||||
)
|
||||
}*/
|
||||
val subtypeForPluginSupport = ComputedSubtype(
|
||||
id = subtypeEditor.id.value,
|
||||
primaryLocale = subtypeEditor.primaryLocale.value.languageTag(),
|
||||
secondaryLocales = subtypeEditor.secondaryLocales.value.map { it.languageTag() },
|
||||
)
|
||||
val subtypeSupportInfo by produceState<SubtypeSupportInfo?>(
|
||||
initialValue = null,
|
||||
plugins,
|
||||
subtypeForPluginSupport,
|
||||
nlpProviders,
|
||||
) {
|
||||
value = nlpManager.plugins.getOrNull(nlpProviders.suggestion)
|
||||
?.evaluateIsSupported(subtypeForPluginSupport)
|
||||
}
|
||||
val supportInfo = subtypeSupportInfo
|
||||
if (supportInfo == null) {
|
||||
FlorisOutlinedBox {
|
||||
Text(
|
||||
modifier = Modifier.defaultFlorisOutlinedText(),
|
||||
text = "No plugin selected",
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
} else if (supportInfo.isFullySupported()) {
|
||||
FlorisOutlinedBox {
|
||||
Text(
|
||||
modifier = Modifier.defaultFlorisOutlinedText(),
|
||||
text = "Supported",
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
} else if (supportInfo.isPartiallySupported()) {
|
||||
FlorisOutlinedBox {
|
||||
Text(
|
||||
modifier = Modifier.defaultFlorisOutlinedText(),
|
||||
text = "Partially supported\nReason: ${supportInfo.reason}",
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
} else if (supportInfo.isUnsupported()) {
|
||||
FlorisOutlinedBox {
|
||||
Text(
|
||||
modifier = Modifier.defaultFlorisOutlinedText(),
|
||||
text = "Unsupported\nReason: ${supportInfo.reason}",
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SubtypeGroupSpacer()
|
||||
|
||||
@ -610,7 +681,9 @@ private fun SubtypeLayoutDropdown(
|
||||
|
||||
@Composable
|
||||
private fun SubtypeGroupSpacer() {
|
||||
Spacer(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(32.dp))
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(32.dp)
|
||||
)
|
||||
}
|
||||
|
@ -369,6 +369,10 @@ class NlpManager(context: Context) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override suspend fun evaluateIsSupported(subtype: ComputedSubtype): SubtypeSupportInfo {
|
||||
return SubtypeSupportInfo.fullySupported()
|
||||
}
|
||||
|
||||
override suspend fun preload(subtype: ComputedSubtype) {
|
||||
// Do nothing
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import dev.patrickgold.florisboard.ime.core.ComputedSubtype
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyProximityChecker
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingProvider
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingResult
|
||||
import dev.patrickgold.florisboard.ime.nlp.SubtypeSupportInfo
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionProvider
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionRequestFlags
|
||||
@ -116,6 +117,16 @@ class LatinLanguageProviderService : FlorisPluginService(), SpellingProvider, Su
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun evaluateIsSupported(subtype: ComputedSubtype): SubtypeSupportInfo {
|
||||
val baseDictionaries = getBaseDictionaryPaths(subtype)
|
||||
return if (baseDictionaries.isNotEmpty()) {
|
||||
SubtypeSupportInfo.fullySupported()
|
||||
} else {
|
||||
// TODO make string resource and translatable
|
||||
SubtypeSupportInfo.unsupported("No dictionary could be found")
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun spell(
|
||||
subtypeId: Long,
|
||||
word: String,
|
||||
|
@ -301,3 +301,8 @@ fun Modifier.defaultFlorisOutlinedBox(): Modifier {
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp, horizontal = 16.dp)
|
||||
}
|
||||
|
||||
fun Modifier.defaultFlorisOutlinedText(): Modifier {
|
||||
return this
|
||||
.padding(vertical = 8.dp, horizontal = 16.dp)
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.ime.core.ComputedSubtype
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingProvider
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingResult
|
||||
import dev.patrickgold.florisboard.ime.nlp.SubtypeSupportInfo
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionProvider
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionRequest
|
||||
@ -67,6 +68,20 @@ class IndexedPlugin(
|
||||
connection.bindService(serviceName)
|
||||
}
|
||||
|
||||
override suspend fun evaluateIsSupported(subtype: ComputedSubtype): SubtypeSupportInfo {
|
||||
val message = FlorisPluginMessage.requestToService(
|
||||
action = FlorisPluginMessage.ACTION_EVALUATE_IS_SUPPORTED,
|
||||
id = messageIdGenerator.getAndIncrement(),
|
||||
data = Json.encodeToString(subtype),
|
||||
)
|
||||
connection.sendMessage(message)
|
||||
return withTimeoutOrNull(5000L) {
|
||||
val replyMessage = connection.replyMessages.first { it.id == message.id }
|
||||
val resultData = replyMessage.data ?: return@withTimeoutOrNull null
|
||||
return@withTimeoutOrNull Json.decodeFromString(resultData)
|
||||
} ?: SubtypeSupportInfo.unsupported("!! Error in communication with plugin !!")
|
||||
}
|
||||
|
||||
override suspend fun preload(subtype: ComputedSubtype) {
|
||||
val message = FlorisPluginMessage.requestToService(
|
||||
action = FlorisPluginMessage.ACTION_PRELOAD,
|
||||
|
@ -32,6 +32,15 @@ interface NlpProvider {
|
||||
*/
|
||||
suspend fun create()
|
||||
|
||||
/**
|
||||
* Is called to check if the language provider supports the subtype using its primary/secondary language options.
|
||||
*
|
||||
* @param subtype Information about the subtype to check, primarily used for getting the primary and secondary
|
||||
* language for correct dictionary selection.
|
||||
* @return true if this provider is able to provide NLP services for given subtype, false otherwise.
|
||||
*/
|
||||
suspend fun evaluateIsSupported(subtype: ComputedSubtype): SubtypeSupportInfo
|
||||
|
||||
/**
|
||||
* Is called at least once before a task specific request occurs, to allow for locale-specific preloading of
|
||||
* dictionaries and language models.
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.nlp
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SubtypeSupportInfo(
|
||||
val state: SubtypeSupportState,
|
||||
val reason: String?,
|
||||
) {
|
||||
fun isFullySupported(): Boolean {
|
||||
return state == SubtypeSupportState.FullySupported
|
||||
}
|
||||
|
||||
fun isPartiallySupported(): Boolean {
|
||||
return state == SubtypeSupportState.PartiallySupported
|
||||
}
|
||||
|
||||
fun isUnsupported(): Boolean {
|
||||
return state == SubtypeSupportState.Unsupported
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fullySupported(): SubtypeSupportInfo {
|
||||
return SubtypeSupportInfo(SubtypeSupportState.FullySupported, null)
|
||||
}
|
||||
|
||||
fun partiallySupported(reason: String? = null): SubtypeSupportInfo {
|
||||
return SubtypeSupportInfo(SubtypeSupportState.PartiallySupported, reason)
|
||||
}
|
||||
|
||||
fun unsupported(reason: String? = null): SubtypeSupportInfo {
|
||||
return SubtypeSupportInfo(SubtypeSupportState.Unsupported, reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class SubtypeSupportState {
|
||||
FullySupported,
|
||||
PartiallySupported,
|
||||
Unsupported;
|
||||
}
|
@ -46,9 +46,10 @@ data class FlorisPluginMessage(
|
||||
const val TYPE_REQUEST = 1
|
||||
const val TYPE_RESPONSE = 2
|
||||
|
||||
const val ACTION_PRELOAD = 1
|
||||
const val ACTION_SPELL = 2
|
||||
const val ACTION_SUGGEST = 3
|
||||
const val ACTION_EVALUATE_IS_SUPPORTED = 1
|
||||
const val ACTION_PRELOAD = 2
|
||||
const val ACTION_SPELL = 3
|
||||
const val ACTION_SUGGEST = 4
|
||||
|
||||
private const val M_SOURCE = 0x0000000F
|
||||
private val O_SOURCE = M_SOURCE.countTrailingZeroBits()
|
||||
|
@ -106,6 +106,23 @@ abstract class FlorisPluginService : Service(), NlpProvider {
|
||||
|
||||
when (type) {
|
||||
FlorisPluginMessage.TYPE_REQUEST -> when (action) {
|
||||
FlorisPluginMessage.ACTION_EVALUATE_IS_SUPPORTED -> processAction("EVALUATE_IS_SUPPORTED") {
|
||||
val data = message.data ?: error("Request message contains no data")
|
||||
val id = message.id
|
||||
val replyToMessenger = message.replyTo ?: error("Request message contains no replyTo field")
|
||||
val subtype = Json.decodeFromString<ComputedSubtype>(data)
|
||||
service.scope.launch {
|
||||
flogDebug { "ACTION_EVALUATE_IS_SUPPORTED: $subtype" }
|
||||
val info = service.evaluateIsSupported(subtype)
|
||||
val responseMessage = FlorisPluginMessage.replyToConsumer(
|
||||
action = FlorisPluginMessage.ACTION_EVALUATE_IS_SUPPORTED,
|
||||
id = id,
|
||||
data = Json.encodeToString(info),
|
||||
)
|
||||
replyToMessenger.send(responseMessage.toAndroidMessage())
|
||||
}
|
||||
}
|
||||
|
||||
FlorisPluginMessage.ACTION_PRELOAD -> processAction("PRELOAD") {
|
||||
val data = message.data ?: error("Request message contains no data")
|
||||
val subtype = Json.decodeFromString<ComputedSubtype>(data)
|
||||
|
Loading…
Reference in New Issue
Block a user