From a2e6302cd3033b1791a33eeefee6c96d7daee193 Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Sat, 19 Nov 2022 14:17:58 +0100 Subject: [PATCH] Add possibility to add custom extras to app search actions --- .../searchactions/actions/AppSearchAction.kt | 7 +- .../actions/CustomIntentAction.kt | 4 +- .../builders/AppSearchActionBuilder.kt | 10 +- .../builders/SearchActionBuilder.kt | 4 +- .../ui/component/SearchActionIcon.kt | 4 +- .../searchactions/EditSearchActionSheet.kt | 341 +++++++++++++++++- .../searchactions/EditSearchActionSheetVM.kt | 156 +++++++- 7 files changed, 505 insertions(+), 21 deletions(-) diff --git a/search-actions/src/main/java/de/mm20/launcher2/searchactions/actions/AppSearchAction.kt b/search-actions/src/main/java/de/mm20/launcher2/searchactions/actions/AppSearchAction.kt index 701deeb1..c3be8f00 100644 --- a/search-actions/src/main/java/de/mm20/launcher2/searchactions/actions/AppSearchAction.kt +++ b/search-actions/src/main/java/de/mm20/launcher2/searchactions/actions/AppSearchAction.kt @@ -4,11 +4,12 @@ import android.app.SearchManager import android.content.ComponentName import android.content.Context import android.content.Intent +import android.os.Bundle import de.mm20.launcher2.ktx.tryStartActivity data class AppSearchAction( override val label: String, - val componentName: ComponentName, + val baseIntent: Intent, val query: String, override val icon: SearchActionIcon = SearchActionIcon.Custom, override val iconColor: Int = 1, @@ -16,8 +17,8 @@ data class AppSearchAction( ): SearchAction { override fun start(context: Context) { - val intent = Intent(Intent.ACTION_SEARCH).apply { - component = componentName + val intent = Intent(baseIntent).apply { + action = Intent.ACTION_SEARCH putExtra(SearchManager.QUERY, query) putExtra(SearchManager.USER_QUERY, query) } diff --git a/search-actions/src/main/java/de/mm20/launcher2/searchactions/actions/CustomIntentAction.kt b/search-actions/src/main/java/de/mm20/launcher2/searchactions/actions/CustomIntentAction.kt index 633c4e06..23266e43 100644 --- a/search-actions/src/main/java/de/mm20/launcher2/searchactions/actions/CustomIntentAction.kt +++ b/search-actions/src/main/java/de/mm20/launcher2/searchactions/actions/CustomIntentAction.kt @@ -7,8 +7,8 @@ import de.mm20.launcher2.ktx.tryStartActivity class CustomIntentAction( override val label: String, val query: String, - val queryKey: String, - val baseIntent: Intent, + private val queryKey: String, + private val baseIntent: Intent, override val icon: SearchActionIcon = SearchActionIcon.Custom, override val iconColor: Int = 1, override val customIcon: String? = null, diff --git a/search-actions/src/main/java/de/mm20/launcher2/searchactions/builders/AppSearchActionBuilder.kt b/search-actions/src/main/java/de/mm20/launcher2/searchactions/builders/AppSearchActionBuilder.kt index 5b53d233..16de32ec 100644 --- a/search-actions/src/main/java/de/mm20/launcher2/searchactions/builders/AppSearchActionBuilder.kt +++ b/search-actions/src/main/java/de/mm20/launcher2/searchactions/builders/AppSearchActionBuilder.kt @@ -2,6 +2,8 @@ package de.mm20.launcher2.searchactions.builders import android.content.ComponentName import android.content.Context +import android.content.Intent +import android.os.Bundle import de.mm20.launcher2.searchactions.TextClassificationResult import de.mm20.launcher2.searchactions.TextType import de.mm20.launcher2.searchactions.actions.AppSearchAction @@ -10,18 +12,18 @@ import de.mm20.launcher2.searchactions.actions.SearchActionIcon data class AppSearchActionBuilder( override val label: String, - val componentName: ComponentName, + val baseIntent: Intent, override val icon: SearchActionIcon = SearchActionIcon.Custom, override val iconColor: Int = 0, override val customIcon: String? = null, ) : CustomizableSearchActionBuilder { override val key: String - get() = "app://${componentName.flattenToShortString()}" - override fun build(context: Context, classifiedQuery: TextClassificationResult): SearchAction? { + get() = "app://${baseIntent.toUri(0)}" + override fun build(context: Context, classifiedQuery: TextClassificationResult): SearchAction { return AppSearchAction( label = label, - componentName = componentName, + baseIntent = baseIntent, query = classifiedQuery.text, icon = icon, iconColor = iconColor, diff --git a/search-actions/src/main/java/de/mm20/launcher2/searchactions/builders/SearchActionBuilder.kt b/search-actions/src/main/java/de/mm20/launcher2/searchactions/builders/SearchActionBuilder.kt index 4e60e738..13dfb36e 100644 --- a/search-actions/src/main/java/de/mm20/launcher2/searchactions/builders/SearchActionBuilder.kt +++ b/search-actions/src/main/java/de/mm20/launcher2/searchactions/builders/SearchActionBuilder.kt @@ -46,7 +46,7 @@ interface SearchActionBuilder { "app" -> { return AppSearchActionBuilder( label = entity.label ?: "", - componentName = ComponentName.unflattenFromString(entity.data ?: return null) ?: return null, + baseIntent = Intent.parseUri(entity.data, 0), iconColor = entity.color ?: 0, icon = SearchActionIcon.fromInt(entity.icon), customIcon = entity.customIcon, @@ -92,7 +92,7 @@ interface SearchActionBuilder { position = position, type = "app", label = builder.label, - data = builder.componentName.flattenToShortString(), + data = builder.baseIntent.toUri(0), color = builder.iconColor, icon = builder.icon.toInt(), customIcon = builder.customIcon, diff --git a/ui/src/main/java/de/mm20/launcher2/ui/component/SearchActionIcon.kt b/ui/src/main/java/de/mm20/launcher2/ui/component/SearchActionIcon.kt index b96fcedd..c150a81b 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/component/SearchActionIcon.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/component/SearchActionIcon.kt @@ -92,7 +92,7 @@ fun SearchActionIcon(action: SearchAction, size: Dp = 20.dp) { icon = action.icon, color = action.iconColor, customIcon = action.customIcon, - componentName = (action as? AppSearchAction)?.componentName, + componentName = (action as? AppSearchAction)?.baseIntent?.component, size = size, ) } @@ -103,7 +103,7 @@ fun SearchActionIcon(builder: CustomizableSearchActionBuilder, size: Dp = 20.dp) icon = builder.icon, color = builder.iconColor, customIcon = builder.customIcon, - componentName = (builder as? AppSearchActionBuilder)?.componentName, + componentName = (builder as? AppSearchActionBuilder)?.baseIntent?.component, size = size, ) } diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheet.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheet.kt index 784aae5a..04deed76 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheet.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheet.kt @@ -2,6 +2,7 @@ package de.mm20.launcher2.ui.settings.searchactions import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -21,18 +22,25 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Add import androidx.compose.material.icons.rounded.Android import androidx.compose.material.icons.rounded.ArrowDropDown import androidx.compose.material.icons.rounded.Delete import androidx.compose.material.icons.rounded.ManageSearch import androidx.compose.material.icons.rounded.MoreVert +import androidx.compose.material.icons.rounded.RemoveCircleOutline +import androidx.compose.material.icons.rounded.ToggleOn import androidx.compose.material.icons.rounded.TravelExplore import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.FilledIconButton +import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -60,6 +68,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.OffsetMapping import androidx.compose.ui.text.input.TransformedText import androidx.compose.ui.text.input.VisualTransformation @@ -68,6 +77,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import de.mm20.launcher2.searchactions.actions.SearchActionIcon import de.mm20.launcher2.searchactions.builders.AppSearchActionBuilder +import de.mm20.launcher2.searchactions.builders.CustomIntentActionBuilder import de.mm20.launcher2.searchactions.builders.CustomizableSearchActionBuilder import de.mm20.launcher2.searchactions.builders.WebsearchActionBuilder import de.mm20.launcher2.ui.R @@ -373,7 +383,9 @@ private fun InitWebSearchPage(viewModel: EditSearchActionSheetVM) { fun CustomizeWebSearch(viewModel: EditSearchActionSheetVM) { val searchAction by viewModel.searchAction - Column { + Column( + modifier = Modifier.verticalScroll(rememberScrollState()) + ) { if (searchAction != null && searchAction is WebsearchActionBuilder) { Row( @@ -456,11 +468,16 @@ fun CustomizeAppSearch(viewModel: EditSearchActionSheetVM) { initial = emptyList() ) val selectedApp = - remember(availableSearchApps, (searchAction as? AppSearchActionBuilder)?.componentName) { - availableSearchApps.find { it.componentName == (searchAction as? AppSearchActionBuilder)?.componentName } + remember( + availableSearchApps, + (searchAction as? AppSearchActionBuilder)?.baseIntent?.component + ) { + availableSearchApps.find { it.componentName == (searchAction as? AppSearchActionBuilder)?.baseIntent?.component } } - Column { + Column( + modifier = Modifier.verticalScroll(rememberScrollState()) + ) { if (searchAction != null) { @@ -538,6 +555,23 @@ fun CustomizeAppSearch(viewModel: EditSearchActionSheetVM) { } } } + + var showAdvanced by remember { + mutableStateOf(false) + } + + AnimatedVisibility(!showAdvanced) { + TextButton( + modifier = Modifier.padding(top = 16.dp), + onClick = { showAdvanced = true }) { + Text(stringResource(id = R.string.websearch_dialog_advanced)) + } + } + + AnimatedVisibility(showAdvanced) { + IntentExtrasEditor(viewModel) + } + } } } @@ -547,7 +581,9 @@ fun CustomizeCustomIntent(viewModel: EditSearchActionSheetVM) { val searchAction by viewModel.searchAction if (searchAction != null) { - Column { + Column( + modifier = Modifier.verticalScroll(rememberScrollState()) + ) { Row( verticalAlignment = Alignment.Bottom ) { @@ -602,7 +638,7 @@ fun PickIcon(viewModel: EditSearchActionSheetVM) { }) { SearchActionIcon( icon = SearchActionIcon.Custom, - componentName = (action as AppSearchActionBuilder).componentName, + componentName = (action as AppSearchActionBuilder).baseIntent.component, size = 24.dp, color = 1, ) @@ -703,4 +739,297 @@ private fun SearchActionIconTile( icon() } } +} + +@Composable +private fun IntentExtrasEditor(viewModel: EditSearchActionSheetVM) { + + val action = viewModel.searchAction.value + val extras = remember(action?.key) { + when (action) { + is CustomIntentActionBuilder -> action.baseIntent.extras + is AppSearchActionBuilder -> action.baseIntent.extras + else -> null + } + + } + + val keys = remember(extras) { extras?.keySet()?.sorted() ?: emptyList() } + + Column( + modifier = Modifier.padding(top = 24.dp) + ) { + Text("Extras", style = MaterialTheme.typography.titleSmall) + for (key in keys) { + Row( + modifier = Modifier.padding(top = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + val value = extras?.get(key) + when (value) { + is String -> { + OutlinedTextField( + modifier = Modifier + .weight(1f) + .padding(bottom = 8.dp), + value = value, + onValueChange = { viewModel.putStringExtra(key, it) }, + label = { Text(key) }, + leadingIcon = { + Text("ABC", style = MaterialTheme.typography.labelSmall) + }, + singleLine = true, + ) + } + + is Long -> { + OutlinedTextField( + modifier = Modifier + .weight(1f) + .padding(bottom = 8.dp), + value = value.toString(), + onValueChange = { + viewModel.putLongExtra( + key, + it.replace(Regex("[^0-9]"), "").toLongOrNull() ?: 0 + ) + }, + label = { Text(key) }, + leadingIcon = { + Text("1234", style = MaterialTheme.typography.labelSmall) + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + ) + } + + is Int -> { + OutlinedTextField( + modifier = Modifier + .weight(1f) + .padding(bottom = 8.dp), + value = value.toString(), + onValueChange = { + viewModel.putIntExtra( + key, + it.replace(Regex("[^0-9]"), "").toIntOrNull() ?: 0 + ) + }, + label = { Text(key) }, + leadingIcon = { + Text("123", style = MaterialTheme.typography.labelSmall) + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + ) + } + + is Double -> { + OutlinedTextField( + modifier = Modifier + .weight(1f) + .padding(bottom = 8.dp), + value = value.toString(), + onValueChange = { + viewModel.putDoubleExtra( + key, + it.replace(Regex("[^0-9.]"), "").toDoubleOrNull() ?: 0.0 + ) + }, + label = { Text(key) }, + leadingIcon = { + Text("1.00", style = MaterialTheme.typography.labelSmall) + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + ) + } + + is Float -> { + OutlinedTextField( + modifier = Modifier + .weight(1f) + .padding(bottom = 8.dp), + value = value.toString(), + onValueChange = { + viewModel.putFloatExtra( + key, + it.replace(Regex("[^0-9.]"), "").toFloatOrNull() ?: 0f + ) + }, + label = { Text(key) }, + leadingIcon = { + Text("1.0", style = MaterialTheme.typography.labelSmall) + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + ) + } + + is Boolean -> { + Switch( + checked = value, + onCheckedChange = { viewModel.putBooleanExtra(key, it) }) + Text( + text = key, + modifier = Modifier + .weight(1f) + .padding(start = 8.dp), + style = MaterialTheme.typography.labelSmall, + ) + } + } + IconButton( + onClick = { viewModel.removeExtra(key) }, + modifier = Modifier.padding(horizontal = 8.dp) + ) { + Icon(imageVector = Icons.Rounded.RemoveCircleOutline, contentDescription = null) + } + } + } + + + OutlinedCard( + modifier = Modifier + .padding(top = 16.dp) + .fillMaxWidth(), + shape = MaterialTheme.shapes.medium, + ) { + + var newKey by remember { mutableStateOf("") } + var newType by remember { mutableStateOf("string") } + var showTypeDropdown by remember { mutableStateOf(false) } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp), + ) { + FilledTonalIconButton( + modifier = Modifier.padding(end = 8.dp), + onClick = { showTypeDropdown = !showTypeDropdown } + ) { + when (newType) { + "bool" -> { + Icon(Icons.Rounded.ToggleOn, contentDescription = null) + } + + "string" -> { + Text("ABC", style = MaterialTheme.typography.labelSmall) + } + + "int" -> { + Text("123", style = MaterialTheme.typography.labelSmall) + } + + "long" -> { + Text("1234", style = MaterialTheme.typography.labelSmall) + } + + "float" -> { + Text("1.0", style = MaterialTheme.typography.labelSmall) + } + + "double" -> { + Text("1.00", style = MaterialTheme.typography.labelSmall) + } + } + DropdownMenu( + expanded = showTypeDropdown, + onDismissRequest = { showTypeDropdown = false }) { + DropdownMenuItem( + leadingIcon = { + Text( + "ABC", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("String") }, + onClick = { + newType = "string" + showTypeDropdown = false + }) + DropdownMenuItem( + leadingIcon = { + Text( + "123", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("Integer") }, + onClick = { + newType = "int" + showTypeDropdown = false + }) + DropdownMenuItem( + leadingIcon = { + Text( + "1234", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("Long") }, + onClick = { + newType = "long" + showTypeDropdown = false + }) + DropdownMenuItem( + leadingIcon = { + Text( + "1.0", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("Float") }, + onClick = { + newType = "float" + showTypeDropdown = false + }) + DropdownMenuItem( + leadingIcon = { + Text( + "1.00", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("Double") }, + onClick = { + newType = "double" + showTypeDropdown = false + }) + DropdownMenuItem( + leadingIcon = { Icon(Icons.Rounded.ToggleOn, null) }, + text = { Text("Boolean") }, + onClick = { + newType = "bool" + showTypeDropdown = false + }) + } + } + OutlinedTextField( + modifier = Modifier + .weight(1f) + .padding(bottom = 8.dp), + label = { Text("Key") }, + value = newKey, + onValueChange = { newKey = it }, + ) + FilledIconButton( + modifier = Modifier.padding(start = 8.dp), + onClick = { + when (newType) { + "string" -> viewModel.putStringExtra(newKey) + "int" -> viewModel.putIntExtra(newKey) + "bool" -> viewModel.putBooleanExtra(newKey) + "long" -> viewModel.putLongExtra(newKey) + "double" -> viewModel.putDoubleExtra(newKey) + "float" -> viewModel.putFloatExtra(newKey) + } + newKey = "" + }, + enabled = newKey.isNotBlank() + ) { + Icon(imageVector = Icons.Rounded.Add, contentDescription = null) + } + } + } + } } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheetVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheetVM.kt index 58029f7b..0195ff2b 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheetVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheetVM.kt @@ -4,6 +4,7 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.net.Uri +import android.os.Bundle import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.unit.Density @@ -73,7 +74,9 @@ class EditSearchActionSheetVM : ViewModel(), KoinComponent { fun selectSearchableApp(app: SearchableApp) { searchAction.value = AppSearchActionBuilder( label = app.label, - componentName = app.componentName, + baseIntent = Intent().apply { + setComponent(app.componentName) + }, icon = SearchActionIcon.Custom, customIcon = null, iconColor = 1, @@ -116,7 +119,9 @@ class EditSearchActionSheetVM : ViewModel(), KoinComponent { ) ) - is AppSearchActionBuilder -> action.copy(componentName = componentName) + is AppSearchActionBuilder -> action.also { + it.baseIntent.setComponent(componentName) + } is WebsearchActionBuilder -> action } @@ -259,6 +264,153 @@ class EditSearchActionSheetVM : ViewModel(), KoinComponent { setCustomIcon(path) } } + + fun removeExtra(key: String) { + val action = searchAction.value ?: return + searchAction.value = when(action) { + is CustomIntentActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.remove(key) + it.replaceExtras(extras) + }, + ) + is AppSearchActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.remove(key) + it.replaceExtras(extras) + } + ) + else -> action + } + } + + fun putStringExtra(key: String, value: String = "") { + val action = searchAction.value ?: return + searchAction.value = when(action) { + is CustomIntentActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putString(key, value) + it.replaceExtras(extras) + }, + ) + is AppSearchActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putString(key, value) + it.replaceExtras(extras) + }, + ) + else -> action + } + } + + fun putIntExtra(key: String, value: Int = 0) { + val action = searchAction.value ?: return + searchAction.value = when(action) { + is CustomIntentActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putInt(key, value) + it.replaceExtras(extras) + }, + ) + is AppSearchActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putInt(key, value) + it.replaceExtras(extras) + }, + ) + else -> action + } + } + + fun putLongExtra(key: String, value: Long = 0L) { + val action = searchAction.value ?: return + searchAction.value = when(action) { + is CustomIntentActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putLong(key, value) + it.replaceExtras(extras) + }, + ) + is AppSearchActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putLong(key, value) + it.replaceExtras(extras) + }, + ) + else -> action + } + } + + fun putFloatExtra(key: String, value: Float = 0f) { + val action = searchAction.value ?: return + searchAction.value = when(action) { + is CustomIntentActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putFloat(key, value) + it.replaceExtras(extras) + }, + ) + is AppSearchActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putFloat(key, value) + it.replaceExtras(extras) + }, + ) + else -> action + } + } + + fun putDoubleExtra(key: String, value: Double = 0.0) { + val action = searchAction.value ?: return + searchAction.value = when(action) { + is CustomIntentActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putDouble(key, value) + it.replaceExtras(extras) + }, + ) + is AppSearchActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putDouble(key, value) + it.replaceExtras(extras) + }, + ) + else -> action + } + } + + fun putBooleanExtra(key: String, value: Boolean = false) { + val action = searchAction.value ?: return + searchAction.value = when(action) { + is CustomIntentActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putBoolean(key, value) + it.replaceExtras(extras) + }, + ) + is AppSearchActionBuilder -> action.copy( + baseIntent = action.baseIntent.cloneFilter().also { + val extras = action.baseIntent.extras?.deepCopy() ?: Bundle() + extras.putBoolean(key, value) + it.replaceExtras(extras) + }, + ) + else -> action + } + } } enum class EditSearchActionPage {