From 3db34ec408f947010edc48e66e761b990694444e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20L=C3=B6vdahl?= Date: Tue, 25 Jul 2023 21:37:31 +0300 Subject: [PATCH] Show measurement unit in Wear OS complication (#3703) * Show measurement unit in Wear OS complication * Extend existing `friendlyState` method * Make showing unit configurable (defaulting to false) * Feedback fixes --- .../42.json | 1001 +++++++++++++++++ .../android/common/data/integration/Entity.kt | 11 +- .../companion/android/database/AppDatabase.kt | 5 +- .../database/wear/EntityStateComplications.kt | 4 +- common/src/main/res/values/strings.xml | 1 + .../ComplicationConfigViewModel.kt | 9 +- .../EntityStateDataSourceService.kt | 10 +- .../views/ComplicationConfigMainView.kt | 26 + 8 files changed, 1061 insertions(+), 6 deletions(-) create mode 100644 common/schemas/io.homeassistant.companion.android.database.AppDatabase/42.json diff --git a/common/schemas/io.homeassistant.companion.android.database.AppDatabase/42.json b/common/schemas/io.homeassistant.companion.android.database.AppDatabase/42.json new file mode 100644 index 00000000000..586bd41fa1a --- /dev/null +++ b/common/schemas/io.homeassistant.companion.android.database.AppDatabase/42.json @@ -0,0 +1,1001 @@ +{ + "formatVersion": 1, + "database": { + "version": 42, + "identityHash": "a5ee0d40a2fdeb5cd7f5332d64400e8b", + "entities": [ + { + "tableName": "sensor_attributes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`sensor_id` TEXT NOT NULL, `name` TEXT NOT NULL, `value` TEXT NOT NULL, `value_type` TEXT NOT NULL, PRIMARY KEY(`sensor_id`, `name`))", + "fields": [ + { + "fieldPath": "sensorId", + "columnName": "sensor_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "valueType", + "columnName": "value_type", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "sensor_id", + "name" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "authentication_list", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, PRIMARY KEY(`host`))", + "fields": [ + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "host" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sensors", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `server_id` INTEGER NOT NULL DEFAULT 0, `enabled` INTEGER NOT NULL, `registered` INTEGER DEFAULT NULL, `state` TEXT NOT NULL, `last_sent_state` TEXT DEFAULT NULL, `last_sent_icon` TEXT DEFAULT NULL, `state_type` TEXT NOT NULL, `type` TEXT NOT NULL, `icon` TEXT NOT NULL, `name` TEXT NOT NULL, `device_class` TEXT, `unit_of_measurement` TEXT, `state_class` TEXT, `entity_category` TEXT, `core_registration` TEXT, `app_registration` TEXT, PRIMARY KEY(`id`, `server_id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "serverId", + "columnName": "server_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registered", + "columnName": "registered", + "affinity": "INTEGER", + "notNull": false, + "defaultValue": "NULL" + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastSentState", + "columnName": "last_sent_state", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "NULL" + }, + { + "fieldPath": "lastSentIcon", + "columnName": "last_sent_icon", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "NULL" + }, + { + "fieldPath": "stateType", + "columnName": "state_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "icon", + "columnName": "icon", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deviceClass", + "columnName": "device_class", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "unitOfMeasurement", + "columnName": "unit_of_measurement", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "stateClass", + "columnName": "state_class", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "entityCategory", + "columnName": "entity_category", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "coreRegistration", + "columnName": "core_registration", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "appRegistration", + "columnName": "app_registration", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "server_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sensor_settings", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`sensor_id` TEXT NOT NULL, `name` TEXT NOT NULL, `value` TEXT NOT NULL, `value_type` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `entries` TEXT NOT NULL, PRIMARY KEY(`sensor_id`, `name`))", + "fields": [ + { + "fieldPath": "sensorId", + "columnName": "sensor_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "valueType", + "columnName": "value_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entries", + "columnName": "entries", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "sensor_id", + "name" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "button_widgets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `server_id` INTEGER NOT NULL DEFAULT 0, `icon_name` TEXT NOT NULL, `domain` TEXT NOT NULL, `service` TEXT NOT NULL, `service_data` TEXT NOT NULL, `label` TEXT, `background_type` TEXT NOT NULL DEFAULT 'DAYNIGHT', `text_color` TEXT, `require_authentication` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "serverId", + "columnName": "server_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "iconName", + "columnName": "icon_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "domain", + "columnName": "domain", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "serviceData", + "columnName": "service_data", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "backgroundType", + "columnName": "background_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'DAYNIGHT'" + }, + { + "fieldPath": "textColor", + "columnName": "text_color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "requireAuthentication", + "columnName": "require_authentication", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "camera_widgets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `server_id` INTEGER NOT NULL DEFAULT 0, `entity_id` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "serverId", + "columnName": "server_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "entityId", + "columnName": "entity_id", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "media_player_controls_widgets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `server_id` INTEGER NOT NULL DEFAULT 0, `entity_id` TEXT NOT NULL, `label` TEXT, `show_skip` INTEGER NOT NULL, `show_seek` INTEGER NOT NULL, `show_volume` INTEGER NOT NULL, `show_source` INTEGER NOT NULL DEFAULT false, `background_type` TEXT NOT NULL DEFAULT 'DAYNIGHT', `text_color` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "serverId", + "columnName": "server_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "entityId", + "columnName": "entity_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "showSkip", + "columnName": "show_skip", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "showSeek", + "columnName": "show_seek", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "showVolume", + "columnName": "show_volume", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "showSource", + "columnName": "show_source", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "false" + }, + { + "fieldPath": "backgroundType", + "columnName": "background_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'DAYNIGHT'" + }, + { + "fieldPath": "textColor", + "columnName": "text_color", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "static_widget", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `server_id` INTEGER NOT NULL DEFAULT 0, `entity_id` TEXT NOT NULL, `attribute_ids` TEXT, `label` TEXT, `text_size` REAL NOT NULL, `state_separator` TEXT NOT NULL, `attribute_separator` TEXT NOT NULL, `last_update` TEXT NOT NULL, `background_type` TEXT NOT NULL DEFAULT 'DAYNIGHT', `text_color` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "serverId", + "columnName": "server_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "entityId", + "columnName": "entity_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributeIds", + "columnName": "attribute_ids", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "textSize", + "columnName": "text_size", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stateSeparator", + "columnName": "state_separator", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributeSeparator", + "columnName": "attribute_separator", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastUpdate", + "columnName": "last_update", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backgroundType", + "columnName": "background_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'DAYNIGHT'" + }, + { + "fieldPath": "textColor", + "columnName": "text_color", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "template_widgets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `server_id` INTEGER NOT NULL DEFAULT 0, `template` TEXT NOT NULL, `text_size` REAL NOT NULL DEFAULT 12.0, `last_update` TEXT NOT NULL, `background_type` TEXT NOT NULL DEFAULT 'DAYNIGHT', `text_color` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "serverId", + "columnName": "server_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "template", + "columnName": "template", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "textSize", + "columnName": "text_size", + "affinity": "REAL", + "notNull": true, + "defaultValue": "12.0" + }, + { + "fieldPath": "lastUpdate", + "columnName": "last_update", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backgroundType", + "columnName": "background_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'DAYNIGHT'" + }, + { + "fieldPath": "textColor", + "columnName": "text_color", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "notification_history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `received` INTEGER NOT NULL, `message` TEXT NOT NULL, `data` TEXT NOT NULL, `source` TEXT NOT NULL, `server_id` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "received", + "columnName": "received", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "source", + "columnName": "source", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "serverId", + "columnName": "server_id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "qs_tiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `tile_id` TEXT NOT NULL, `added` INTEGER NOT NULL DEFAULT 1, `server_id` INTEGER NOT NULL DEFAULT 0, `icon_name` TEXT, `entity_id` TEXT NOT NULL, `label` TEXT NOT NULL, `subtitle` TEXT, `should_vibrate` INTEGER NOT NULL DEFAULT 0, `auth_required` INTEGER NOT NULL DEFAULT 0)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tileId", + "columnName": "tile_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "added", + "columnName": "added", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "serverId", + "columnName": "server_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "iconName", + "columnName": "icon_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "entityId", + "columnName": "entity_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subtitle", + "columnName": "subtitle", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shouldVibrate", + "columnName": "should_vibrate", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "authRequired", + "columnName": "auth_required", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "favorites", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `position` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "favorite_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `friendly_name` TEXT NOT NULL, `icon` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "friendlyName", + "columnName": "friendly_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "icon", + "columnName": "icon", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "entity_state_complications", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `entity_id` TEXT NOT NULL, `show_title` INTEGER NOT NULL DEFAULT 1, `show_unit` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entityId", + "columnName": "entity_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "showTitle", + "columnName": "show_title", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "showUnit", + "columnName": "show_unit", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "servers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `_name` TEXT NOT NULL, `name_override` TEXT, `_version` TEXT, `list_order` INTEGER NOT NULL, `device_name` TEXT, `external_url` TEXT NOT NULL, `internal_url` TEXT, `cloud_url` TEXT, `webhook_id` TEXT, `secret` TEXT, `cloudhook_url` TEXT, `use_cloud` INTEGER NOT NULL, `internal_ssids` TEXT NOT NULL, `prioritize_internal` INTEGER NOT NULL, `access_token` TEXT, `refresh_token` TEXT, `token_expiration` INTEGER, `token_type` TEXT, `install_id` TEXT, `user_id` TEXT, `user_name` TEXT, `user_is_owner` INTEGER, `user_is_admin` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "_name", + "columnName": "_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "nameOverride", + "columnName": "name_override", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "_version", + "columnName": "_version", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "listOrder", + "columnName": "list_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceName", + "columnName": "device_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "connection.externalUrl", + "columnName": "external_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "connection.internalUrl", + "columnName": "internal_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "connection.cloudUrl", + "columnName": "cloud_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "connection.webhookId", + "columnName": "webhook_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "connection.secret", + "columnName": "secret", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "connection.cloudhookUrl", + "columnName": "cloudhook_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "connection.useCloud", + "columnName": "use_cloud", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "connection.internalSsids", + "columnName": "internal_ssids", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "connection.prioritizeInternal", + "columnName": "prioritize_internal", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "session.accessToken", + "columnName": "access_token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "session.refreshToken", + "columnName": "refresh_token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "session.tokenExpiration", + "columnName": "token_expiration", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "session.tokenType", + "columnName": "token_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "session.installId", + "columnName": "install_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "user.id", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "user.name", + "columnName": "user_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "user.isOwner", + "columnName": "user_is_owner", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "user.isAdmin", + "columnName": "user_is_admin", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "settings", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `websocket_setting` TEXT NOT NULL, `sensor_update_frequency` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "websocketSetting", + "columnName": "websocket_setting", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sensorUpdateFrequency", + "columnName": "sensor_update_frequency", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a5ee0d40a2fdeb5cd7f5332d64400e8b')" + ] + } +} \ No newline at end of file diff --git a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/Entity.kt b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/Entity.kt index 2a1bbc0019e..2700b2d6604 100644 --- a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/Entity.kt +++ b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/Entity.kt @@ -604,7 +604,7 @@ suspend fun Entity.onPressed( val Entity.friendlyName: String get() = (attributes as? Map<*, *>)?.get("friendly_name")?.toString() ?: entityId -fun Entity.friendlyState(context: Context, options: EntityRegistryOptions? = null): String { +fun Entity.friendlyState(context: Context, options: EntityRegistryOptions? = null, appendUnitOfMeasurement: Boolean = false): String { var friendlyState = when (state) { "closed" -> context.getString(commonR.string.state_closed) "closing" -> context.getString(commonR.string.state_closing) @@ -649,6 +649,15 @@ fun Entity.friendlyState(context: Context, options: EntityRegistryOptions } } } + + if (appendUnitOfMeasurement) { + val unit = (attributes as? Map<*, *>)?.get("unit_of_measurement")?.toString() + + if (unit?.isNotBlank() == true) { + return "$friendlyState $unit" + } + } + return friendlyState } diff --git a/common/src/main/java/io/homeassistant/companion/android/database/AppDatabase.kt b/common/src/main/java/io/homeassistant/companion/android/database/AppDatabase.kt index a6d48973066..7f8dd123405 100644 --- a/common/src/main/java/io/homeassistant/companion/android/database/AppDatabase.kt +++ b/common/src/main/java/io/homeassistant/companion/android/database/AppDatabase.kt @@ -90,7 +90,7 @@ import io.homeassistant.companion.android.common.R as commonR Server::class, Setting::class ], - version = 41, + version = 42, autoMigrations = [ AutoMigration(from = 24, to = 25), AutoMigration(from = 25, to = 26), @@ -107,7 +107,8 @@ import io.homeassistant.companion.android.common.R as commonR AutoMigration(from = 36, to = 37, spec = AppDatabase.Companion.Migration36to37::class), AutoMigration(from = 37, to = 38, spec = AppDatabase.Companion.Migration37to38::class), AutoMigration(from = 38, to = 39), - AutoMigration(from = 39, to = 40) + AutoMigration(from = 39, to = 40), + AutoMigration(from = 41, to = 42) ] ) @TypeConverters( diff --git a/common/src/main/java/io/homeassistant/companion/android/database/wear/EntityStateComplications.kt b/common/src/main/java/io/homeassistant/companion/android/database/wear/EntityStateComplications.kt index a90523ed800..354f731e820 100644 --- a/common/src/main/java/io/homeassistant/companion/android/database/wear/EntityStateComplications.kt +++ b/common/src/main/java/io/homeassistant/companion/android/database/wear/EntityStateComplications.kt @@ -15,5 +15,7 @@ data class EntityStateComplications( @ColumnInfo(name = "entity_id") val entityId: String, @ColumnInfo(name = "show_title", defaultValue = "1") - val showTitle: Boolean + val showTitle: Boolean, + @ColumnInfo(name = "show_unit", defaultValue = "0") + val showUnit: Boolean ) diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index cd5bcf05e4c..ff938b5d8ae 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -742,6 +742,7 @@ Sharing logs with the Home Assistant team will help to solve issues. Please share the logs only if you have been asked to do so by a Home Assistant developer Show and Share Logs Show entity name + Show entity unit Sign in on phone %1$s decreased %1$s increased diff --git a/wear/src/main/java/io/homeassistant/companion/android/complications/ComplicationConfigViewModel.kt b/wear/src/main/java/io/homeassistant/companion/android/complications/ComplicationConfigViewModel.kt index 4266a82bba5..621ab488c5c 100644 --- a/wear/src/main/java/io/homeassistant/companion/android/complications/ComplicationConfigViewModel.kt +++ b/wear/src/main/java/io/homeassistant/companion/android/complications/ComplicationConfigViewModel.kt @@ -58,6 +58,8 @@ class ComplicationConfigViewModel @Inject constructor( private set var entityShowTitle by mutableStateOf(true) private set + var entityShowUnit by mutableStateOf(true) + private set init { loadEntities() @@ -71,6 +73,7 @@ class ComplicationConfigViewModel @Inject constructor( stored?.let { selectedEntity = SimplifiedEntity(entityId = it.entityId) entityShowTitle = it.showTitle + entityShowUnit = it.showUnit if (loadingState == LoadingState.READY) { updateSelectedEntity() } @@ -153,9 +156,13 @@ class ComplicationConfigViewModel @Inject constructor( entityShowTitle = show } + fun setShowUnit(show: Boolean) { + entityShowUnit = show + } + fun addEntityStateComplication(id: Int, entity: SimplifiedEntity) { viewModelScope.launch { - entityStateComplicationsDao.add(EntityStateComplications(id, entity.entityId, entityShowTitle)) + entityStateComplicationsDao.add(EntityStateComplications(id, entity.entityId, entityShowTitle, entityShowUnit)) } } diff --git a/wear/src/main/java/io/homeassistant/companion/android/complications/EntityStateDataSourceService.kt b/wear/src/main/java/io/homeassistant/companion/android/complications/EntityStateDataSourceService.kt index d7ca889089d..ce669d454be 100644 --- a/wear/src/main/java/io/homeassistant/companion/android/complications/EntityStateDataSourceService.kt +++ b/wear/src/main/java/io/homeassistant/companion/android/complications/EntityStateDataSourceService.kt @@ -79,7 +79,15 @@ class EntityStateDataSourceService : SuspendingComplicationDataSourceService() { } else { null } - val text = PlainComplicationText.Builder(entity.friendlyState(this, entityOptions)).build() + + val text = PlainComplicationText.Builder( + entity.friendlyState( + this, + entityOptions, + appendUnitOfMeasurement = settings.showUnit + ) + ).build() + val contentDescription = PlainComplicationText.Builder(getText(R.string.complication_entity_state_content_description)).build() val monochromaticImage = MonochromaticImage.Builder(Icon.createWithBitmap(iconBitmap)).build() val tapAction = ComplicationReceiver.getComplicationToggleIntent(this, request.complicationInstanceId) diff --git a/wear/src/main/java/io/homeassistant/companion/android/complications/views/ComplicationConfigMainView.kt b/wear/src/main/java/io/homeassistant/companion/android/complications/views/ComplicationConfigMainView.kt index 4bc0e2d9d0e..d348c94f649 100644 --- a/wear/src/main/java/io/homeassistant/companion/android/complications/views/ComplicationConfigMainView.kt +++ b/wear/src/main/java/io/homeassistant/companion/android/complications/views/ComplicationConfigMainView.kt @@ -52,11 +52,13 @@ fun LoadConfigView( MainConfigView( entity = complicationConfigViewModel.selectedEntity, showTitle = complicationConfigViewModel.entityShowTitle, + showUnit = complicationConfigViewModel.entityShowUnit, loadingState = complicationConfigViewModel.loadingState, onChooseEntityClicked = { swipeDismissableNavController.navigate(SCREEN_CHOOSE_ENTITY) }, onShowTitleClicked = complicationConfigViewModel::setShowTitle, + onShowUnitClicked = complicationConfigViewModel::setShowUnit, onAcceptClicked = onAcceptClicked ) } @@ -81,9 +83,11 @@ fun LoadConfigView( fun MainConfigView( entity: SimplifiedEntity?, showTitle: Boolean, + showUnit: Boolean, loadingState: ComplicationConfigViewModel.LoadingState, onChooseEntityClicked: () -> Unit, onShowTitleClicked: (Boolean) -> Unit, + onShowUnitClicked: (Boolean) -> Unit, onAcceptClicked: () -> Unit ) { ThemeLazyColumn { @@ -145,6 +149,26 @@ fun MainConfigView( enabled = loaded && entity != null ) } + item { + val isChecked = !loaded || showUnit + ToggleChip( + checked = isChecked, + onCheckedChange = onShowUnitClicked, + label = { Text(stringResource(R.string.show_unit_title)) }, + toggleControl = { + Icon( + imageVector = ToggleChipDefaults.switchIcon(isChecked), + contentDescription = if (isChecked) { + stringResource(R.string.enabled) + } else { + stringResource(R.string.disabled) + } + ) + }, + modifier = Modifier.fillMaxWidth(), + enabled = loaded && entity != null + ) + } item { Button( @@ -172,9 +196,11 @@ fun PreviewMainConfigView() { MainConfigView( entity = simplifiedEntity, showTitle = true, + showUnit = true, loadingState = ComplicationConfigViewModel.LoadingState.READY, onChooseEntityClicked = {}, onShowTitleClicked = {}, + onShowUnitClicked = {}, onAcceptClicked = {} ) }