mirror of
https://github.com/home-assistant/android
synced 2024-07-22 10:54:12 +00:00
Add shortcut for Assist (#3615)
- Adds a shortcut to the app that allows accessing Assist from the home screen, including options for pipeline and voice/text
This commit is contained in:
parent
1ed0f6a094
commit
48a7755e62
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@android:color/holo_red_dark" />
|
||||||
|
<foreground android:drawable="@drawable/ic_assist_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_assist_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
|
@ -397,6 +397,17 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity android:name=".widgets.assist.AssistShortcutActivity"
|
||||||
|
android:label="@string/assist_shortcut"
|
||||||
|
android:icon="@mipmap/ic_assist_launcher"
|
||||||
|
android:exported="true"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:theme="@style/Theme.HomeAssistant.Config">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.CREATE_SHORTCUT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.provider"
|
android:authorities="${applicationId}.provider"
|
||||||
|
|
|
@ -31,6 +31,7 @@ import io.homeassistant.companion.android.common.R
|
||||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||||
import io.homeassistant.companion.android.common.data.servers.ServerManager
|
import io.homeassistant.companion.android.common.data.servers.ServerManager
|
||||||
import io.homeassistant.companion.android.webview.WebViewActivity
|
import io.homeassistant.companion.android.webview.WebViewActivity
|
||||||
|
import io.homeassistant.companion.android.widgets.assist.AssistShortcutActivity
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -46,7 +47,9 @@ class ManageShortcutsViewModel @Inject constructor(
|
||||||
private lateinit var iconPack: IconPack
|
private lateinit var iconPack: IconPack
|
||||||
private var shortcutManager = application.applicationContext.getSystemService<ShortcutManager>()!!
|
private var shortcutManager = application.applicationContext.getSystemService<ShortcutManager>()!!
|
||||||
val canPinShortcuts = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && shortcutManager.isRequestPinShortcutSupported
|
val canPinShortcuts = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && shortcutManager.isRequestPinShortcutSupported
|
||||||
var pinnedShortcuts: MutableList<ShortcutInfo> = shortcutManager.pinnedShortcuts
|
var pinnedShortcuts = shortcutManager.pinnedShortcuts
|
||||||
|
.filter { !it.id.startsWith(AssistShortcutActivity.SHORTCUT_PREFIX) }
|
||||||
|
.toMutableList()
|
||||||
private set
|
private set
|
||||||
var dynamicShortcuts: MutableList<ShortcutInfo> = shortcutManager.dynamicShortcuts
|
var dynamicShortcuts: MutableList<ShortcutInfo> = shortcutManager.dynamicShortcuts
|
||||||
private set
|
private set
|
||||||
|
@ -227,6 +230,10 @@ class ManageShortcutsViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updatePinnedShortcuts() {
|
fun updatePinnedShortcuts() {
|
||||||
pinnedShortcuts = shortcutManager.pinnedShortcuts
|
pinnedShortcuts.clear()
|
||||||
|
pinnedShortcuts.addAll(
|
||||||
|
shortcutManager.pinnedShortcuts
|
||||||
|
.filter { !it.id.startsWith(AssistShortcutActivity.SHORTCUT_PREFIX) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import io.homeassistant.companion.android.common.R as commonR
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ServerExposedDropdownMenu(servers: List<Server>, current: Int?, onSelected: (Int) -> Unit, modifier: Modifier = Modifier) {
|
fun ExposedDropdownMenu(label: String, keys: List<String>, currentIndex: Int?, onSelected: (Int) -> Unit, modifier: Modifier = Modifier) {
|
||||||
var expanded by remember { mutableStateOf(false) }
|
var expanded by remember { mutableStateOf(false) }
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
ExposedDropdownMenuBox(
|
ExposedDropdownMenuBox(
|
||||||
|
@ -30,23 +30,37 @@ fun ServerExposedDropdownMenu(servers: List<Server>, current: Int?, onSelected:
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
readOnly = true,
|
readOnly = true,
|
||||||
value = servers.firstOrNull { it.id == current }?.friendlyName ?: "",
|
value = currentIndex?.let { keys[it] } ?: "",
|
||||||
onValueChange = { },
|
onValueChange = { },
|
||||||
label = { Text(stringResource(commonR.string.server_select)) },
|
label = { Text(label) },
|
||||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
||||||
colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
|
colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
|
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
|
||||||
servers.forEach { server ->
|
keys.forEachIndexed { index, key ->
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
onSelected(server.id)
|
onSelected(index)
|
||||||
expanded = false
|
expanded = false
|
||||||
focusManager.clearFocus()
|
focusManager.clearFocus()
|
||||||
}) {
|
}) {
|
||||||
Text(server.friendlyName)
|
Text(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ServerExposedDropdownMenu(servers: List<Server>, current: Int?, onSelected: (Int) -> Unit, modifier: Modifier = Modifier) {
|
||||||
|
val keys = servers.map { it.friendlyName }
|
||||||
|
val ids = servers.map { it.id }
|
||||||
|
val currentIndex = servers.indexOfFirst { it.id == current }.takeUnless { it == -1 }
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
label = stringResource(commonR.string.server_select),
|
||||||
|
keys = keys,
|
||||||
|
currentIndex = currentIndex,
|
||||||
|
onSelected = { onSelected(ids[it]) },
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package io.homeassistant.companion.android.widgets.assist
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
|
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.homeassistant.companion.android.BaseActivity
|
||||||
|
import io.homeassistant.companion.android.R
|
||||||
|
import io.homeassistant.companion.android.assist.AssistActivity
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class AssistShortcutActivity : BaseActivity() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val SHORTCUT_PREFIX = ".ha_assist_"
|
||||||
|
}
|
||||||
|
|
||||||
|
val viewModel: AssistShortcutViewModel by viewModels()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setContent {
|
||||||
|
MdcTheme {
|
||||||
|
AssistShortcutView(
|
||||||
|
selectedServerId = viewModel.serverId,
|
||||||
|
servers = viewModel.servers,
|
||||||
|
supported = viewModel.supported,
|
||||||
|
pipelines = viewModel.pipelines,
|
||||||
|
onSetServer = viewModel::setServer,
|
||||||
|
onSubmit = this::setShortcutAndFinish
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setShortcutAndFinish(name: String, serverId: Int, pipelineId: String?, startListening: Boolean) {
|
||||||
|
val assistIntent = AssistActivity.newInstance(
|
||||||
|
context = this,
|
||||||
|
serverId = serverId,
|
||||||
|
pipelineId = pipelineId,
|
||||||
|
startListening = startListening,
|
||||||
|
fromFrontend = false
|
||||||
|
).apply {
|
||||||
|
action = Intent.ACTION_VIEW
|
||||||
|
}
|
||||||
|
val shortcutInfo = ShortcutInfoCompat.Builder(this, "$SHORTCUT_PREFIX${UUID.randomUUID()}")
|
||||||
|
.setIntent(assistIntent)
|
||||||
|
.setShortLabel(name)
|
||||||
|
.setLongLabel(name)
|
||||||
|
.setIcon(IconCompat.createWithResource(this, R.mipmap.ic_assist_launcher))
|
||||||
|
.build()
|
||||||
|
val resultIntent = ShortcutManagerCompat.createShortcutResultIntent(this, shortcutInfo)
|
||||||
|
setResult(Activity.RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
package io.homeassistant.companion.android.widgets.assist
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.OutlinedTextField
|
||||||
|
import androidx.compose.material.Scaffold
|
||||||
|
import androidx.compose.material.Switch
|
||||||
|
import androidx.compose.material.SwitchDefaults
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.TopAppBar
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.colorResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineListResponse
|
||||||
|
import io.homeassistant.companion.android.database.server.Server
|
||||||
|
import io.homeassistant.companion.android.util.compose.ExposedDropdownMenu
|
||||||
|
import io.homeassistant.companion.android.util.compose.ServerExposedDropdownMenu
|
||||||
|
import io.homeassistant.companion.android.common.R as commonR
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AssistShortcutView(
|
||||||
|
selectedServerId: Int,
|
||||||
|
servers: List<Server>,
|
||||||
|
supported: Boolean?,
|
||||||
|
pipelines: AssistPipelineListResponse?,
|
||||||
|
onSetServer: (Int) -> Unit,
|
||||||
|
onSubmit: (String, Int, String?, Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(stringResource(commonR.string.assist_shortcut)) },
|
||||||
|
backgroundColor = colorResource(commonR.color.colorBackground),
|
||||||
|
contentColor = colorResource(commonR.color.colorOnBackground)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { padding ->
|
||||||
|
Box(modifier = Modifier.padding(padding).verticalScroll(rememberScrollState())) {
|
||||||
|
Column(modifier = Modifier.padding(all = 16.dp)) {
|
||||||
|
val assist = stringResource(commonR.string.assist)
|
||||||
|
var name by rememberSaveable { mutableStateOf(assist) }
|
||||||
|
var startListening by rememberSaveable { mutableStateOf(true) }
|
||||||
|
var pipelineId by rememberSaveable(selectedServerId) { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = name,
|
||||||
|
onValueChange = { name = it },
|
||||||
|
label = { Text(stringResource(commonR.string.widget_text_hint_label)) },
|
||||||
|
singleLine = true,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 16.dp)
|
||||||
|
)
|
||||||
|
if (servers.size > 1) {
|
||||||
|
ServerExposedDropdownMenu(
|
||||||
|
servers = servers,
|
||||||
|
current = selectedServerId,
|
||||||
|
onSelected = onSetServer,
|
||||||
|
modifier = Modifier.padding(bottom = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (supported == true) {
|
||||||
|
if (pipelines != null && pipelines.pipelines.isNotEmpty()) {
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
label = stringResource(commonR.string.assist_pipeline),
|
||||||
|
keys = listOf(
|
||||||
|
stringResource(
|
||||||
|
commonR.string.assist_preferred_pipeline,
|
||||||
|
pipelines.pipelines.first { it.id == pipelines.preferredPipeline }.name
|
||||||
|
)
|
||||||
|
) +
|
||||||
|
pipelines.pipelines.map { it.name },
|
||||||
|
currentIndex = pipelineId?.let { pid -> 1 + pipelines.pipelines.indexOfFirst { it.id == pid } }
|
||||||
|
?: 0,
|
||||||
|
onSelected = {
|
||||||
|
pipelineId = if (it == 0) null else pipelines.pipelines[it - 1].id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.clickable { startListening = !startListening }
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(commonR.string.assist_start_listening),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(end = 8.dp)
|
||||||
|
)
|
||||||
|
Switch(
|
||||||
|
checked = startListening,
|
||||||
|
onCheckedChange = null,
|
||||||
|
colors = SwitchDefaults.colors(uncheckedThumbColor = colorResource(commonR.color.colorSwitchUncheckedThumb))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if (supported == false) {
|
||||||
|
Text(
|
||||||
|
stringResource(
|
||||||
|
commonR.string.no_assist_support,
|
||||||
|
"2023.5",
|
||||||
|
stringResource(commonR.string.no_assist_support_assist_pipeline)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
onSubmit(
|
||||||
|
name.ifBlank { assist },
|
||||||
|
selectedServerId,
|
||||||
|
pipelineId,
|
||||||
|
startListening
|
||||||
|
)
|
||||||
|
},
|
||||||
|
enabled = supported == true,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 32.dp)
|
||||||
|
) {
|
||||||
|
Text(stringResource(commonR.string.add_shortcut))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package io.homeassistant.companion.android.widgets.assist
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import io.homeassistant.companion.android.common.data.servers.ServerManager
|
||||||
|
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineListResponse
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class AssistShortcutViewModel @Inject constructor(
|
||||||
|
val serverManager: ServerManager,
|
||||||
|
application: Application
|
||||||
|
) : AndroidViewModel(application) {
|
||||||
|
|
||||||
|
var serverId by mutableStateOf(ServerManager.SERVER_ID_ACTIVE)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var servers by mutableStateOf(serverManager.defaultServers)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var supported by mutableStateOf<Boolean?>(null)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var pipelines by mutableStateOf<AssistPipelineListResponse?>(null)
|
||||||
|
private set
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (serverManager.isRegistered()) {
|
||||||
|
serverManager.getServer()?.id?.let { serverId = it }
|
||||||
|
getData()
|
||||||
|
} else {
|
||||||
|
supported = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setServer(serverId: Int) {
|
||||||
|
if (serverId == this.serverId) return
|
||||||
|
|
||||||
|
this.serverId = serverId
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getData() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
// Loading states
|
||||||
|
supported = null
|
||||||
|
pipelines = null
|
||||||
|
|
||||||
|
// Update data
|
||||||
|
supported = serverManager.getServer(serverId)?.version?.isAtLeast(2023, 5) == true &&
|
||||||
|
serverManager.webSocketRepository(serverId).getConfig()?.components?.contains("assist_pipeline") == true
|
||||||
|
if (supported == true) {
|
||||||
|
pipelines = serverManager.webSocketRepository(serverId).getAssistPipelines()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/colorPrimary" />
|
||||||
|
<foreground android:drawable="@drawable/ic_assist_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_assist_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- drawable/comment_processing_outline.xml -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<group android:scaleX="0.45466667"
|
||||||
|
android:scaleY="0.45466667"
|
||||||
|
android:translateX="6.544"
|
||||||
|
android:translateY="6.544">
|
||||||
|
<path android:fillColor="#fff" android:pathData="M9,22A1,1 0 0,1 8,21V18H4A2,2 0 0,1 2,16V4C2,2.89 2.9,2 4,2H20A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H13.9L10.2,21.71C10,21.9 9.75,22 9.5,22V22H9M10,16V19.08L13.08,16H20V4H4V16H10M17,11H15V9H17V11M13,11H11V9H13V11M9,11H7V9H9V11Z" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
|
@ -1079,7 +1079,10 @@
|
||||||
<string name="assist_how_can_i_assist">How can I assist?</string>
|
<string name="assist_how_can_i_assist">How can I assist?</string>
|
||||||
<string name="assist_log_in">Log in to Home Assistant to start using Assist</string>
|
<string name="assist_log_in">Log in to Home Assistant to start using Assist</string>
|
||||||
<string name="assist_permission">To use Assist with your voice, allow Home Assistant to access the microphone</string>
|
<string name="assist_permission">To use Assist with your voice, allow Home Assistant to access the microphone</string>
|
||||||
|
<string name="assist_pipeline">Assistant</string>
|
||||||
|
<string name="assist_preferred_pipeline">Preferred assistant (%1$s)</string>
|
||||||
<string name="assist_send_text">Send text</string>
|
<string name="assist_send_text">Send text</string>
|
||||||
|
<string name="assist_shortcut">Assist shortcut</string>
|
||||||
<string name="assist_start_listening">Start listening</string>
|
<string name="assist_start_listening">Start listening</string>
|
||||||
<string name="assist_stop_listening">Stop listening</string>
|
<string name="assist_stop_listening">Stop listening</string>
|
||||||
<string name="not_registered">Please open the Home Assistant app and log in to start using Assist</string>
|
<string name="not_registered">Please open the Home Assistant app and log in to start using Assist</string>
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<!-- drawable/comment_processing_outline.xml -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<group android:scaleX="0.45466667"
|
|
||||||
android:scaleY="0.45466667"
|
|
||||||
android:translateX="6.544"
|
|
||||||
android:translateY="6.544">
|
|
||||||
<path android:fillColor="#fff" android:pathData="M9,22A1,1 0 0,1 8,21V18H4A2,2 0 0,1 2,16V4C2,2.89 2.9,2 4,2H20A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H13.9L10.2,21.71C10,21.9 9.75,22 9.5,22V22H9M10,16V19.08L13.08,16H20V4H4V16H10M17,11H15V9H17V11M13,11H11V9H13V11M9,11H7V9H9V11Z" />
|
|
||||||
</group>
|
|
||||||
</vector>
|
|
Loading…
Reference in a new issue