mirror of
https://github.com/home-assistant/android
synced 2024-10-15 12:32:54 +00:00
Use entity icon for quick settings tiles by default (#3160)
- When creating a new quick setting tile, use the entity's icon by default - Move Wear icon based on entity domain code to common
This commit is contained in:
parent
7f32738e10
commit
7e5e3adfe9
|
@ -18,12 +18,16 @@ import androidx.core.graphics.drawable.toBitmap
|
|||
import com.maltaisn.icondialog.pack.IconPack
|
||||
import com.maltaisn.icondialog.pack.IconPackLoader
|
||||
import com.maltaisn.iconpack.mdi.createMaterialDesignIconPack
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.getIcon
|
||||
import io.homeassistant.companion.android.database.qs.TileDao
|
||||
import io.homeassistant.companion.android.database.qs.TileEntity
|
||||
import io.homeassistant.companion.android.database.qs.isSetup
|
||||
|
@ -100,6 +104,9 @@ abstract class TileExtensions : TileService() {
|
|||
if (tileData != null && tileData.isSetup && tileData.entityId.split('.')[0] in toggleDomainsWithLock)
|
||||
integrationUseCase.getEntityUpdates(listOf(tileData.entityId))?.collect {
|
||||
tile.state = if (it.state in validActiveStates) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
|
||||
getTileIcon(tileData.iconId, it, applicationContext)?.let { icon ->
|
||||
tile.icon = Icon.createWithBitmap(icon)
|
||||
}
|
||||
tile.updateTile()
|
||||
}
|
||||
}
|
||||
|
@ -127,20 +134,30 @@ abstract class TileExtensions : TileService() {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
tile.subtitle = tileData.subtitle
|
||||
}
|
||||
if (tileData.entityId.split('.')[0] in toggleDomainsWithLock) {
|
||||
val state: Entity<*>? =
|
||||
if (
|
||||
tileData.entityId.split(".")[0] in toggleDomainsWithLock ||
|
||||
tileData.iconId == null
|
||||
) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val state = withContext(Dispatchers.IO) { integrationUseCase.getEntity(tileData.entityId) }
|
||||
tile.state = if (state?.state in validActiveStates) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
|
||||
integrationUseCase.getEntity(tileData.entityId)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to set state for tile", e)
|
||||
tile.state = Tile.STATE_UNAVAILABLE
|
||||
Log.e(TAG, "Unable to get state for tile", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
} else null
|
||||
if (tileData.entityId.split('.')[0] in toggleDomainsWithLock) {
|
||||
tile.state = when {
|
||||
state?.state in validActiveStates -> Tile.STATE_ACTIVE
|
||||
state?.state != null && state.state !in validActiveStates -> Tile.STATE_INACTIVE
|
||||
else -> Tile.STATE_UNAVAILABLE
|
||||
}
|
||||
} else
|
||||
tile.state = Tile.STATE_INACTIVE
|
||||
|
||||
val iconId = tileData.iconId
|
||||
if (iconId != null) {
|
||||
val icon = getTileIcon(iconId, context)
|
||||
getTileIcon(tileData.iconId, state, context)?.let { icon ->
|
||||
tile.icon = Icon.createWithBitmap(icon)
|
||||
}
|
||||
Log.d(TAG, "Tile data set for tile ID: $tileId")
|
||||
|
@ -264,18 +281,9 @@ abstract class TileExtensions : TileService() {
|
|||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "TileExtensions"
|
||||
private var iconPack: IconPack? = null
|
||||
private val toggleDomains = listOf(
|
||||
"automation", "cover", "fan", "humidifier", "input_boolean", "light",
|
||||
"media_player", "remote", "siren", "switch"
|
||||
)
|
||||
private val toggleDomainsWithLock = toggleDomains.plus("lock")
|
||||
private val validActiveStates = listOf("on", "open", "locked")
|
||||
|
||||
private fun getTileIcon(tileIconId: Int, context: Context): Bitmap? {
|
||||
private fun getTileIcon(tileIconId: Int?, entity: Entity<*>?, context: Context): Bitmap? {
|
||||
// Create an icon pack and load all drawables.
|
||||
if (tileIconId != null) {
|
||||
if (iconPack == null) {
|
||||
val loader = IconPackLoader(context)
|
||||
iconPack = createMaterialDesignIconPack(loader)
|
||||
|
@ -286,8 +294,28 @@ abstract class TileExtensions : TileService() {
|
|||
if (iconDrawable != null) {
|
||||
return DrawableCompat.wrap(iconDrawable).toBitmap()
|
||||
}
|
||||
} else {
|
||||
entity?.getIcon(context)?.let {
|
||||
return DrawableCompat.wrap(
|
||||
IconicsDrawable(context, it).apply {
|
||||
sizeDp = 48
|
||||
}
|
||||
).toBitmap()
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "TileExtensions"
|
||||
private var iconPack: IconPack? = null
|
||||
private val toggleDomains = listOf(
|
||||
"automation", "cover", "fan", "humidifier", "input_boolean", "light",
|
||||
"media_player", "remote", "siren", "switch"
|
||||
)
|
||||
private val toggleDomainsWithLock = toggleDomains.plus("lock")
|
||||
private val validActiveStates = listOf("on", "open", "locked")
|
||||
}
|
||||
|
||||
private fun handleInject() {
|
||||
|
|
|
@ -19,10 +19,13 @@ import com.maltaisn.icondialog.data.Icon
|
|||
import com.maltaisn.icondialog.pack.IconPack
|
||||
import com.maltaisn.icondialog.pack.IconPackLoader
|
||||
import com.maltaisn.iconpack.mdi.createMaterialDesignIconPack
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.integration.getIcon
|
||||
import io.homeassistant.companion.android.database.qs.TileDao
|
||||
import io.homeassistant.companion.android.database.qs.TileEntity
|
||||
import io.homeassistant.companion.android.database.qs.isSetup
|
||||
|
@ -70,6 +73,8 @@ class ManageTilesViewModel @Inject constructor(
|
|||
|
||||
var sortedEntities by mutableStateOf<List<Entity<*>>>(emptyList())
|
||||
private set
|
||||
var selectedIconId by mutableStateOf<Int?>(null)
|
||||
private set
|
||||
var selectedIconDrawable by mutableStateOf(AppCompatResources.getDrawable(application, commonR.drawable.ic_stat_ic_notification))
|
||||
private set
|
||||
var selectedEntityId by mutableStateOf("")
|
||||
|
@ -78,8 +83,6 @@ class ManageTilesViewModel @Inject constructor(
|
|||
var submitButtonLabel by mutableStateOf(commonR.string.tile_save)
|
||||
private set
|
||||
var selectedShouldVibrate by mutableStateOf(false)
|
||||
|
||||
private var selectedIcon: Int? = null
|
||||
private var selectedTileId = 0
|
||||
private var selectedTileAdded = false
|
||||
|
||||
|
@ -101,6 +104,10 @@ class ManageTilesViewModel @Inject constructor(
|
|||
viewModelScope.launch(Dispatchers.IO) {
|
||||
sortedEntities = integrationUseCase.getEntities().orEmpty()
|
||||
.filter { it.domain in ManageTilesFragment.validDomains }
|
||||
withContext(Dispatchers.Main) {
|
||||
// The entities list might not have been loaded when the tile data was loaded
|
||||
selectTile(slots.indexOf(selectedTile))
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
|
@ -132,9 +139,26 @@ class ManageTilesViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun selectEntityId(entityId: String) {
|
||||
selectedEntityId = entityId
|
||||
if (selectedIconId == null) selectIcon(null) // trigger drawable update
|
||||
}
|
||||
|
||||
fun selectIcon(icon: Icon?) {
|
||||
selectedIcon = icon?.id
|
||||
selectedIconDrawable = icon?.drawable?.let { DrawableCompat.wrap(it) }
|
||||
selectedIconId = icon?.id
|
||||
selectedIconDrawable = if (icon != null) {
|
||||
icon.drawable?.let { DrawableCompat.wrap(it) }
|
||||
} else {
|
||||
sortedEntities.firstOrNull { it.entityId == selectedEntityId }?.let {
|
||||
it.getIcon(app)?.let { iIcon ->
|
||||
DrawableCompat.wrap(
|
||||
IconicsDrawable(app, iIcon).apply {
|
||||
sizeDp = 20
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateExistingTileFields(currentTile: TileEntity) {
|
||||
|
@ -156,7 +180,7 @@ class ManageTilesViewModel @Inject constructor(
|
|||
id = selectedTileId,
|
||||
tileId = selectedTile.id,
|
||||
added = selectedTileAdded,
|
||||
iconId = selectedIcon,
|
||||
iconId = selectedIconId,
|
||||
entityId = selectedEntityId,
|
||||
label = tileLabel,
|
||||
subtitle = tileSubtitle,
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Button
|
||||
|
@ -18,6 +19,7 @@ import androidx.compose.material.Scaffold
|
|||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.SwitchDefaults
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.rememberScaffoldState
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -116,28 +118,6 @@ fun ManageTilesView(
|
|||
)
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.tile_icon),
|
||||
fontSize = 15.sp,
|
||||
modifier = Modifier.padding(end = 10.dp)
|
||||
)
|
||||
OutlinedButton(
|
||||
onClick = { onShowIconDialog(viewModel.selectedTile.id) }
|
||||
) {
|
||||
val iconBitmap = remember(viewModel.selectedIconDrawable) {
|
||||
viewModel.selectedIconDrawable?.toBitmap()?.asImageBitmap()
|
||||
}
|
||||
iconBitmap?.let {
|
||||
Image(
|
||||
iconBitmap,
|
||||
contentDescription = stringResource(id = R.string.tile_icon),
|
||||
colorFilter = ColorFilter.tint(colorResource(R.color.colorAccent))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.tile_entity),
|
||||
fontSize = 15.sp
|
||||
|
@ -149,7 +129,7 @@ fun ManageTilesView(
|
|||
DropdownMenu(expanded = expandedEntity, onDismissRequest = { expandedEntity = false }) {
|
||||
for (item in viewModel.sortedEntities) {
|
||||
DropdownMenuItem(onClick = {
|
||||
viewModel.selectedEntityId = item.entityId
|
||||
viewModel.selectEntityId(item.entityId)
|
||||
expandedEntity = false
|
||||
}) {
|
||||
Text(text = item.entityId, fontSize = 15.sp)
|
||||
|
@ -157,6 +137,37 @@ fun ManageTilesView(
|
|||
}
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.tile_icon),
|
||||
fontSize = 15.sp,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
OutlinedButton(
|
||||
onClick = { onShowIconDialog(viewModel.selectedTile.id) }
|
||||
) {
|
||||
val iconBitmap = remember(viewModel.selectedIconDrawable) {
|
||||
viewModel.selectedIconDrawable?.toBitmap()?.asImageBitmap()
|
||||
}
|
||||
iconBitmap?.let {
|
||||
Image(
|
||||
iconBitmap,
|
||||
contentDescription = stringResource(id = R.string.tile_icon),
|
||||
colorFilter = ColorFilter.tint(colorResource(R.color.colorAccent)),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (viewModel.selectedIconId != null && viewModel.selectedEntityId.isNotBlank()) {
|
||||
TextButton(
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
onClick = { viewModel.selectIcon(null) }
|
||||
) {
|
||||
Text(text = stringResource(R.string.tile_icon_original))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(R.string.tile_vibrate),
|
||||
|
|
|
@ -74,4 +74,7 @@ dependencies {
|
|||
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4")
|
||||
implementation("org.altbeacon:android-beacon-library:2.19.4")
|
||||
|
||||
implementation("com.mikepenz:iconics-core:5.4.0")
|
||||
implementation("com.mikepenz:community-material-typeface:7.0.96.0-kotlin@aar")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package io.homeassistant.companion.android.common.data.integration
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.util.Log
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.typeface.IIcon
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.CompressedStateDiff
|
||||
import java.util.Calendar
|
||||
import kotlin.math.round
|
||||
|
@ -222,3 +226,172 @@ fun <T> Entity<T>.getLightColor(): Int? {
|
|||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Entity<T>.getIcon(context: Context): IIcon? {
|
||||
val attributes = this.attributes as Map<String, Any?>
|
||||
val icon = attributes["icon"] as? String
|
||||
return if (icon?.startsWith("mdi") == true) {
|
||||
val mdiIcon = icon.split(":")[1]
|
||||
return IconicsDrawable(context, "cmd-$mdiIcon").icon ?: CommunityMaterial.Icon.cmd_bookmark
|
||||
} else {
|
||||
/**
|
||||
* Return a default icon for the domain that matches the icon used in the frontend, see
|
||||
* https://github.com/home-assistant/frontend/blob/dev/src/common/entity/domain_icon.ts.
|
||||
* Note: for SimplifiedEntity sometimes return a more general icon because we don't have state.
|
||||
*/
|
||||
val compareState =
|
||||
state.ifBlank { attributes["state"] as String? }
|
||||
when (domain) {
|
||||
"alert" -> CommunityMaterial.Icon.cmd_alert
|
||||
"air_quality" -> CommunityMaterial.Icon.cmd_air_filter
|
||||
"automation" -> CommunityMaterial.Icon3.cmd_robot
|
||||
"button" -> when (attributes["device_class"]) {
|
||||
"restart" -> CommunityMaterial.Icon3.cmd_restart
|
||||
"update" -> CommunityMaterial.Icon3.cmd_package_up
|
||||
else -> CommunityMaterial.Icon2.cmd_gesture_tap_button
|
||||
}
|
||||
"calendar" -> CommunityMaterial.Icon.cmd_calendar
|
||||
"camera" -> CommunityMaterial.Icon3.cmd_video
|
||||
"climate" -> CommunityMaterial.Icon3.cmd_thermostat
|
||||
"configurator" -> CommunityMaterial.Icon.cmd_cog
|
||||
"conversation" -> CommunityMaterial.Icon3.cmd_microphone_message
|
||||
"cover" -> coverIcon(compareState, this as Entity<Map<String, Any?>>)
|
||||
"counter" -> CommunityMaterial.Icon.cmd_counter
|
||||
"fan" -> CommunityMaterial.Icon2.cmd_fan
|
||||
"google_assistant" -> CommunityMaterial.Icon2.cmd_google_assistant
|
||||
"group" -> CommunityMaterial.Icon2.cmd_google_circles_communities
|
||||
"homeassistant" -> CommunityMaterial.Icon2.cmd_home_assistant
|
||||
"homekit" -> CommunityMaterial.Icon2.cmd_home_automation
|
||||
"humidifier" -> if (compareState == "off")
|
||||
CommunityMaterial.Icon.cmd_air_humidifier_off
|
||||
else
|
||||
CommunityMaterial.Icon.cmd_air_humidifier
|
||||
"image_processing" -> CommunityMaterial.Icon2.cmd_image_filter_frames
|
||||
"input_boolean" -> if (!entityId.endsWith(".ha_android_placeholder")) {
|
||||
if (compareState == "on")
|
||||
CommunityMaterial.Icon.cmd_check_circle_outline
|
||||
else
|
||||
CommunityMaterial.Icon.cmd_close_circle_outline
|
||||
} else { // For SimplifiedEntity without state, use a more generic icon
|
||||
CommunityMaterial.Icon3.cmd_toggle_switch_outline
|
||||
}
|
||||
"input_button" -> CommunityMaterial.Icon2.cmd_gesture_tap_button
|
||||
"input_datetime" -> if (attributes["has_date"] == false)
|
||||
CommunityMaterial.Icon.cmd_clock
|
||||
else if (attributes["has_time"] == false)
|
||||
CommunityMaterial.Icon.cmd_calendar
|
||||
else
|
||||
CommunityMaterial.Icon.cmd_calendar_clock
|
||||
"input_select" -> CommunityMaterial.Icon2.cmd_form_dropdown
|
||||
"input_text" -> CommunityMaterial.Icon2.cmd_form_textbox
|
||||
"light" -> CommunityMaterial.Icon2.cmd_lightbulb
|
||||
"lock" -> when (compareState) {
|
||||
"unlocked" -> CommunityMaterial.Icon2.cmd_lock_open
|
||||
"jammed" -> CommunityMaterial.Icon2.cmd_lock_alert
|
||||
"locking", "unlocking" -> CommunityMaterial.Icon2.cmd_lock_clock
|
||||
else -> CommunityMaterial.Icon2.cmd_lock
|
||||
}
|
||||
"mailbox" -> CommunityMaterial.Icon3.cmd_mailbox
|
||||
"media_player" -> when (attributes["device_class"]) {
|
||||
"speaker" -> when (compareState) {
|
||||
"playing" -> CommunityMaterial.Icon3.cmd_speaker_play
|
||||
"paused" -> CommunityMaterial.Icon3.cmd_speaker_pause
|
||||
"off" -> CommunityMaterial.Icon3.cmd_speaker_off
|
||||
else -> CommunityMaterial.Icon3.cmd_speaker
|
||||
}
|
||||
"tv" -> when (compareState) {
|
||||
"playing" -> CommunityMaterial.Icon3.cmd_television_play
|
||||
"paused" -> CommunityMaterial.Icon3.cmd_television_pause
|
||||
"off" -> CommunityMaterial.Icon3.cmd_television_off
|
||||
else -> CommunityMaterial.Icon3.cmd_television
|
||||
}
|
||||
"receiver" -> when (compareState) {
|
||||
"off" -> CommunityMaterial.Icon.cmd_audio_video_off
|
||||
else -> CommunityMaterial.Icon.cmd_audio_video
|
||||
}
|
||||
else -> when (compareState) {
|
||||
"playing", "paused" -> CommunityMaterial.Icon.cmd_cast_connected
|
||||
"off" -> CommunityMaterial.Icon.cmd_cast_off
|
||||
else -> CommunityMaterial.Icon.cmd_cast
|
||||
}
|
||||
}
|
||||
"notify" -> CommunityMaterial.Icon.cmd_comment_alert
|
||||
"number" -> CommunityMaterial.Icon3.cmd_ray_vertex
|
||||
"persistent_notification" -> CommunityMaterial.Icon.cmd_bell
|
||||
"person" -> CommunityMaterial.Icon.cmd_account
|
||||
"plant" -> CommunityMaterial.Icon2.cmd_flower
|
||||
"proximity" -> CommunityMaterial.Icon.cmd_apple_safari
|
||||
"remote" -> CommunityMaterial.Icon3.cmd_remote
|
||||
"scene" -> CommunityMaterial.Icon3.cmd_palette_outline // Different from frontend: outline version
|
||||
"script" -> CommunityMaterial.Icon3.cmd_script_text_outline // Different from frontend: outline version
|
||||
"select" -> CommunityMaterial.Icon2.cmd_format_list_bulleted
|
||||
"sensor" -> CommunityMaterial.Icon.cmd_eye
|
||||
"siren" -> CommunityMaterial.Icon.cmd_bullhorn
|
||||
"simple_alarm" -> CommunityMaterial.Icon.cmd_bell
|
||||
"sun" -> if (compareState == "above_horizon")
|
||||
CommunityMaterial.Icon3.cmd_white_balance_sunny
|
||||
else
|
||||
CommunityMaterial.Icon3.cmd_weather_night
|
||||
"switch" -> if (!entityId.endsWith(".ha_android_placeholder")) {
|
||||
when (attributes["device_class"]) {
|
||||
"outlet" -> if (compareState == "on") CommunityMaterial.Icon3.cmd_power_plug else CommunityMaterial.Icon3.cmd_power_plug_off
|
||||
"switch" -> if (compareState == "on") CommunityMaterial.Icon3.cmd_toggle_switch else CommunityMaterial.Icon3.cmd_toggle_switch_off
|
||||
else -> CommunityMaterial.Icon2.cmd_flash
|
||||
}
|
||||
} else { // For SimplifiedEntity without state, use a more generic icon
|
||||
CommunityMaterial.Icon2.cmd_light_switch
|
||||
}
|
||||
"timer" -> CommunityMaterial.Icon3.cmd_timer_outline
|
||||
"updater" -> CommunityMaterial.Icon.cmd_cloud_upload
|
||||
"vacuum" -> CommunityMaterial.Icon3.cmd_robot_vacuum
|
||||
"water_heater" -> CommunityMaterial.Icon3.cmd_thermometer
|
||||
"weather" -> CommunityMaterial.Icon3.cmd_weather_cloudy
|
||||
"zone" -> CommunityMaterial.Icon3.cmd_map_marker_radius
|
||||
else -> CommunityMaterial.Icon.cmd_bookmark
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun coverIcon(state: String?, entity: Entity<Map<String, Any?>>): IIcon {
|
||||
val open = state !== "closed"
|
||||
|
||||
return when (entity.attributes?.get("device_class")) {
|
||||
"garage" -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_up_box
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_down_box
|
||||
"closed" -> CommunityMaterial.Icon2.cmd_garage
|
||||
else -> CommunityMaterial.Icon2.cmd_garage_open
|
||||
}
|
||||
"gate" -> when (state) {
|
||||
"opening", "closing" -> CommunityMaterial.Icon2.cmd_gate_arrow_right
|
||||
"closed" -> CommunityMaterial.Icon2.cmd_gate
|
||||
else -> CommunityMaterial.Icon2.cmd_gate_open
|
||||
}
|
||||
"door" -> if (open) CommunityMaterial.Icon.cmd_door_open else CommunityMaterial.Icon.cmd_door_closed
|
||||
"damper" -> if (open) CommunityMaterial.Icon.cmd_circle else CommunityMaterial.Icon.cmd_circle_slice_8
|
||||
"shutter" -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_up_box
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_down_box
|
||||
"closed" -> CommunityMaterial.Icon3.cmd_window_shutter
|
||||
else -> CommunityMaterial.Icon3.cmd_window_shutter_open
|
||||
}
|
||||
"curtain" -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_split_vertical
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_collapse_horizontal
|
||||
"closed" -> CommunityMaterial.Icon.cmd_curtains_closed
|
||||
else -> CommunityMaterial.Icon.cmd_curtains
|
||||
}
|
||||
"blind", "shade" -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_up_box
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_down_box
|
||||
"closed" -> CommunityMaterial.Icon.cmd_blinds
|
||||
else -> CommunityMaterial.Icon.cmd_blinds_open
|
||||
}
|
||||
else -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_up_box
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_down_box
|
||||
"closed" -> CommunityMaterial.Icon3.cmd_window_closed
|
||||
else -> CommunityMaterial.Icon3.cmd_window_open
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -875,7 +875,8 @@
|
|||
<string name="info">Information</string>
|
||||
<string name="show_changelog">Show Change Log</string>
|
||||
<string name="show_changelog_summary">Show the change log dialog from when the app was updated</string>
|
||||
<string name="tile_icon">Select a icon for the tile</string>
|
||||
<string name="tile_icon">Tile Icon</string>
|
||||
<string name="tile_icon_original">Use entity icon</string>
|
||||
<string name="tile_select">Select a tile to edit</string>
|
||||
<string name="shortcut_pinned">Pinned Shortcuts</string>
|
||||
<string name="remote_debugging">WebView Remote Debugging</string>
|
||||
|
|
|
@ -16,9 +16,8 @@ import com.mikepenz.iconics.utils.colorInt
|
|||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.homeassistant.companion.android.common.R
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.integration.getIcon
|
||||
import io.homeassistant.companion.android.database.wear.EntityStateComplicationsDao
|
||||
import io.homeassistant.companion.android.util.getIcon
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
|
@ -59,7 +58,7 @@ class EntityStateDataSourceService : SuspendingComplicationDataSourceService() {
|
|||
}
|
||||
|
||||
val attributes = entity.attributes as Map<*, *>
|
||||
val icon = getIcon(entity, entity.domain, applicationContext) ?: CommunityMaterial.Icon.cmd_bookmark
|
||||
val icon = entity.getIcon(applicationContext) ?: CommunityMaterial.Icon.cmd_bookmark
|
||||
val iconBitmap = IconicsDrawable(this, icon).apply {
|
||||
colorInt = Color.WHITE
|
||||
}.toBitmap()
|
||||
|
|
|
@ -24,10 +24,10 @@ import com.mikepenz.iconics.typeface.library.community.material.CommunityMateria
|
|||
import io.homeassistant.companion.android.common.R
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.integration.getIcon
|
||||
import io.homeassistant.companion.android.home.HomePresenterImpl
|
||||
import io.homeassistant.companion.android.theme.wearColorPalette
|
||||
import io.homeassistant.companion.android.util.WearToggleChip
|
||||
import io.homeassistant.companion.android.util.getIcon
|
||||
import io.homeassistant.companion.android.util.onEntityClickedFeedback
|
||||
import io.homeassistant.companion.android.util.previewEntity1
|
||||
import io.homeassistant.companion.android.util.previewEntity3
|
||||
|
@ -43,7 +43,7 @@ fun EntityUi(
|
|||
val haptic = LocalHapticFeedback.current
|
||||
val context = LocalContext.current
|
||||
val attributes = entity.attributes as Map<*, *>
|
||||
val iconBitmap = getIcon(entity as Entity<Map<String, Any>>, entity.domain, LocalContext.current)
|
||||
val iconBitmap = entity.getIcon(LocalContext.current)
|
||||
val friendlyName = attributes["friendly_name"].toString()
|
||||
|
||||
if (entity.domain in HomePresenterImpl.toggleDomains) {
|
||||
|
|
|
@ -19,11 +19,10 @@ import androidx.wear.compose.material.rememberScalingLazyListState
|
|||
import com.mikepenz.iconics.compose.Image
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.integration.getIcon
|
||||
import io.homeassistant.companion.android.home.MainViewModel
|
||||
import io.homeassistant.companion.android.theme.WearAppTheme
|
||||
import io.homeassistant.companion.android.theme.wearColorPalette
|
||||
import io.homeassistant.companion.android.util.getIcon
|
||||
import io.homeassistant.companion.android.views.ExpandableListHeader
|
||||
import io.homeassistant.companion.android.views.ListHeader
|
||||
import io.homeassistant.companion.android.views.ThemeLazyColumn
|
||||
|
@ -88,11 +87,7 @@ private fun FavoriteToggleChip(
|
|||
onFavoriteSelected: (entityId: String, isSelected: Boolean) -> Unit
|
||||
) {
|
||||
val attributes = entity.attributes as Map<*, *>
|
||||
val iconBitmap = getIcon(
|
||||
entity as Entity<Map<String, Any>>,
|
||||
entity.domain,
|
||||
LocalContext.current
|
||||
)
|
||||
val iconBitmap = entity.getIcon(LocalContext.current)
|
||||
|
||||
val entityId = entity.entityId
|
||||
val checked = favoriteEntityIds.contains(entityId)
|
||||
|
|
|
@ -4,10 +4,9 @@ import android.content.Context
|
|||
import android.widget.Toast
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedback
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.typeface.IIcon
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.getIcon
|
||||
import io.homeassistant.companion.android.home.HomePresenterImpl
|
||||
import java.util.Calendar
|
||||
import io.homeassistant.companion.android.common.R as commonR
|
||||
|
@ -33,162 +32,14 @@ fun stringForDomain(domain: String, context: Context): String? =
|
|||
|
||||
fun getIcon(icon: String?, domain: String, context: Context): IIcon? {
|
||||
val simpleEntity = Entity(
|
||||
"",
|
||||
"$domain.ha_android_placeholder",
|
||||
"",
|
||||
mapOf("icon" to icon),
|
||||
Calendar.getInstance(),
|
||||
Calendar.getInstance(),
|
||||
null
|
||||
)
|
||||
return getIcon(simpleEntity as Entity<Map<String, Any>>, domain, context)
|
||||
}
|
||||
|
||||
fun getIcon(entity: Entity<Map<String, Any>>?, domain: String, context: Context): IIcon? {
|
||||
val icon = entity?.attributes?.get("icon") as? String
|
||||
return if (icon?.startsWith("mdi") == true) {
|
||||
getIconFromMdiString(icon, context)
|
||||
} else {
|
||||
/**
|
||||
* Return a default icon for the domain that matches the icon used in the frontend, see
|
||||
* https://github.com/home-assistant/frontend/blob/dev/src/common/entity/domain_icon.ts.
|
||||
* Note: for SimplifiedEntity sometimes return a more general icon because we don't have state.
|
||||
*/
|
||||
val compareState =
|
||||
if (entity?.state?.isNotBlank() == true)
|
||||
entity.state
|
||||
else
|
||||
entity?.attributes?.get("state") as String?
|
||||
when (domain) {
|
||||
"alert" -> CommunityMaterial.Icon.cmd_alert
|
||||
"air_quality" -> CommunityMaterial.Icon.cmd_air_filter
|
||||
"automation" -> CommunityMaterial.Icon3.cmd_robot
|
||||
"button" -> when (entity?.attributes?.get("device_class")) {
|
||||
"restart" -> CommunityMaterial.Icon3.cmd_restart
|
||||
"update" -> CommunityMaterial.Icon3.cmd_package_up
|
||||
else -> CommunityMaterial.Icon2.cmd_gesture_tap_button
|
||||
}
|
||||
"calendar" -> CommunityMaterial.Icon.cmd_calendar
|
||||
"camera" -> CommunityMaterial.Icon3.cmd_video
|
||||
"climate" -> CommunityMaterial.Icon3.cmd_thermostat
|
||||
"configurator" -> CommunityMaterial.Icon.cmd_cog
|
||||
"conversation" -> CommunityMaterial.Icon3.cmd_microphone_message
|
||||
"cover" -> coverIcon(compareState, entity)
|
||||
"counter" -> CommunityMaterial.Icon.cmd_counter
|
||||
"fan" -> CommunityMaterial.Icon2.cmd_fan
|
||||
"google_assistant" -> CommunityMaterial.Icon2.cmd_google_assistant
|
||||
"group" -> CommunityMaterial.Icon2.cmd_google_circles_communities
|
||||
"homeassistant" -> CommunityMaterial.Icon2.cmd_home_assistant
|
||||
"homekit" -> CommunityMaterial.Icon2.cmd_home_automation
|
||||
"image_processing" -> CommunityMaterial.Icon2.cmd_image_filter_frames
|
||||
"input_boolean" -> if (entity?.entityId?.isNotBlank() == true) {
|
||||
if (compareState == "on")
|
||||
CommunityMaterial.Icon.cmd_check_circle_outline
|
||||
else
|
||||
CommunityMaterial.Icon.cmd_close_circle_outline
|
||||
} else { // For SimplifiedEntity without state, use a more generic icon
|
||||
CommunityMaterial.Icon2.cmd_light_switch
|
||||
}
|
||||
"input_button" -> CommunityMaterial.Icon2.cmd_gesture_tap_button
|
||||
"input_datetime" -> if (entity?.attributes?.get("has_date") == false)
|
||||
CommunityMaterial.Icon.cmd_clock
|
||||
else if (entity?.attributes?.get("has_time") == false)
|
||||
CommunityMaterial.Icon.cmd_calendar
|
||||
else
|
||||
CommunityMaterial.Icon.cmd_calendar_clock
|
||||
"input_select" -> CommunityMaterial.Icon2.cmd_format_list_bulleted
|
||||
"input_text" -> CommunityMaterial.Icon2.cmd_form_textbox
|
||||
"light" -> CommunityMaterial.Icon2.cmd_lightbulb
|
||||
"lock" -> when (compareState) {
|
||||
"unlocked" -> CommunityMaterial.Icon2.cmd_lock_open
|
||||
"jammed" -> CommunityMaterial.Icon2.cmd_lock_alert
|
||||
"locking", "unlocking" -> CommunityMaterial.Icon2.cmd_lock_clock
|
||||
else -> CommunityMaterial.Icon2.cmd_lock
|
||||
}
|
||||
"mailbox" -> CommunityMaterial.Icon3.cmd_mailbox
|
||||
"notify" -> CommunityMaterial.Icon.cmd_comment_alert
|
||||
"number" -> CommunityMaterial.Icon3.cmd_ray_vertex
|
||||
"persistent_notification" -> CommunityMaterial.Icon.cmd_bell
|
||||
"person" -> CommunityMaterial.Icon.cmd_account
|
||||
"plant" -> CommunityMaterial.Icon2.cmd_flower
|
||||
"proximity" -> CommunityMaterial.Icon.cmd_apple_safari
|
||||
"remote" -> CommunityMaterial.Icon3.cmd_remote
|
||||
"scene" -> CommunityMaterial.Icon3.cmd_palette_outline // Different from frontend: outline version
|
||||
"script" -> CommunityMaterial.Icon3.cmd_script_text_outline // Different from frontend: outline version
|
||||
"select" -> CommunityMaterial.Icon2.cmd_format_list_bulleted
|
||||
"sensor" -> CommunityMaterial.Icon.cmd_eye
|
||||
"siren" -> CommunityMaterial.Icon.cmd_bullhorn
|
||||
"simple_alarm" -> CommunityMaterial.Icon.cmd_bell
|
||||
"sun" -> if (compareState == "above_horizon")
|
||||
CommunityMaterial.Icon3.cmd_white_balance_sunny
|
||||
else
|
||||
CommunityMaterial.Icon3.cmd_weather_night
|
||||
"switch" -> if (entity?.entityId?.isNotBlank() == true) {
|
||||
when (entity.attributes["device_class"]) {
|
||||
"outlet" -> if (compareState == "on") CommunityMaterial.Icon3.cmd_power_plug else CommunityMaterial.Icon3.cmd_power_plug_off
|
||||
"switch" -> if (compareState == "on") CommunityMaterial.Icon3.cmd_toggle_switch else CommunityMaterial.Icon3.cmd_toggle_switch_off
|
||||
else -> CommunityMaterial.Icon2.cmd_flash
|
||||
}
|
||||
} else { // For SimplifiedEntity without state, use a more generic icon
|
||||
CommunityMaterial.Icon2.cmd_light_switch
|
||||
}
|
||||
"timer" -> CommunityMaterial.Icon3.cmd_timer_outline
|
||||
"updater" -> CommunityMaterial.Icon.cmd_cloud_upload
|
||||
"vacuum" -> CommunityMaterial.Icon3.cmd_robot_vacuum
|
||||
"water_heater" -> CommunityMaterial.Icon3.cmd_thermometer
|
||||
"weather" -> CommunityMaterial.Icon3.cmd_weather_cloudy
|
||||
"zone" -> CommunityMaterial.Icon3.cmd_map_marker_radius
|
||||
else -> CommunityMaterial.Icon.cmd_bookmark
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getIconFromMdiString(icon: String, context: Context): IIcon {
|
||||
val mdiIcon = icon.split(":")[1]
|
||||
return IconicsDrawable(context, "cmd-$mdiIcon").icon ?: CommunityMaterial.Icon.cmd_bookmark
|
||||
}
|
||||
|
||||
private fun coverIcon(state: String?, entity: Entity<Map<String, Any>>?): IIcon? {
|
||||
val open = state !== "closed"
|
||||
|
||||
return when (entity?.attributes?.get("device_class")) {
|
||||
"garage" -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_up_box
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_down_box
|
||||
"closed" -> CommunityMaterial.Icon2.cmd_garage
|
||||
else -> CommunityMaterial.Icon2.cmd_garage_open
|
||||
}
|
||||
"gate" -> when (state) {
|
||||
"opening", "closing" -> CommunityMaterial.Icon2.cmd_gate_arrow_right
|
||||
"closed" -> CommunityMaterial.Icon2.cmd_gate
|
||||
else -> CommunityMaterial.Icon2.cmd_gate_open
|
||||
}
|
||||
"door" -> if (open) CommunityMaterial.Icon.cmd_door_open else CommunityMaterial.Icon.cmd_door_closed
|
||||
"damper" -> if (open) CommunityMaterial.Icon.cmd_circle else CommunityMaterial.Icon.cmd_circle_slice_8
|
||||
"shutter" -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_up_box
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_down_box
|
||||
"closed" -> CommunityMaterial.Icon3.cmd_window_shutter
|
||||
else -> CommunityMaterial.Icon3.cmd_window_shutter_open
|
||||
}
|
||||
"curtain" -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_split_vertical
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_collapse_horizontal
|
||||
"closed" -> CommunityMaterial.Icon.cmd_curtains_closed
|
||||
else -> CommunityMaterial.Icon.cmd_curtains
|
||||
}
|
||||
"blind", "shade" -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_up_box
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_down_box
|
||||
"closed" -> CommunityMaterial.Icon.cmd_blinds
|
||||
else -> CommunityMaterial.Icon.cmd_blinds_open
|
||||
}
|
||||
else -> when (state) {
|
||||
"opening" -> CommunityMaterial.Icon.cmd_arrow_up_box
|
||||
"closing" -> CommunityMaterial.Icon.cmd_arrow_down_box
|
||||
"closed" -> CommunityMaterial.Icon3.cmd_window_closed
|
||||
else -> CommunityMaterial.Icon3.cmd_window_open
|
||||
}
|
||||
}
|
||||
return simpleEntity.getIcon(context)
|
||||
}
|
||||
|
||||
fun onEntityClickedFeedback(isToastEnabled: Boolean, isHapticEnabled: Boolean, context: Context, friendlyName: String, haptic: HapticFeedback) {
|
||||
|
|
|
@ -15,7 +15,6 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.capitalize
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.wear.compose.material.Chip
|
||||
|
@ -25,10 +24,9 @@ import androidx.wear.compose.material.items
|
|||
import com.mikepenz.iconics.compose.Image
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.integration.getIcon
|
||||
import io.homeassistant.companion.android.data.SimplifiedEntity
|
||||
import io.homeassistant.companion.android.theme.WearAppTheme
|
||||
import io.homeassistant.companion.android.util.getIcon
|
||||
import io.homeassistant.companion.android.util.stringForDomain
|
||||
import java.util.Locale
|
||||
import io.homeassistant.companion.android.common.R as commonR
|
||||
|
@ -121,11 +119,7 @@ private fun ChooseEntityChip(
|
|||
onEntitySelected: (entity: SimplifiedEntity) -> Unit
|
||||
) {
|
||||
val attributes = entity.attributes as Map<*, *>
|
||||
val iconBitmap = getIcon(
|
||||
entity as Entity<Map<String, Any>>,
|
||||
entity.domain,
|
||||
LocalContext.current
|
||||
)
|
||||
val iconBitmap = entity.getIcon(LocalContext.current)
|
||||
Chip(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
|
|
Loading…
Reference in a new issue