mirror of
https://github.com/home-assistant/android
synced 2024-10-04 15:19:30 +00:00
Entity state complication improvements (more flexibility) (#3465)
* Add ComplicationType.LONG_TEXT support, friendly state - Makes it possible for watch faces to request a long text complication - Use the friendly state to support translated states and dates * Add show title option - Allows hiding the title of a complication in case it doesn't look right * Implement/fix reading state from database - When a entity ID is provided in the configuration request, load data for that complication from the database to allow easy reconfiguration - Provide more appropriate error messages when complication isn't configured / the entity doesn't exist * ktlint
This commit is contained in:
parent
95a322fc0b
commit
64ee62b8fa
|
@ -163,7 +163,6 @@ dependencies {
|
|||
implementation("com.google.android.material:material:1.8.0")
|
||||
implementation("androidx.fragment:fragment-ktx:1.5.6")
|
||||
|
||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.5")
|
||||
implementation("com.squareup.okhttp3:okhttp:4.10.0")
|
||||
implementation("com.squareup.picasso:picasso:2.8")
|
||||
|
|
|
@ -68,7 +68,7 @@ dependencies {
|
|||
|
||||
api("androidx.work:work-runtime-ktx:2.8.1")
|
||||
|
||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
api("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
implementation("com.squareup.retrofit2:converter-jackson:2.9.0")
|
||||
implementation("com.squareup.okhttp3:okhttp:4.10.0")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
|
||||
|
|
|
@ -0,0 +1,994 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 40,
|
||||
"identityHash": "9ec60cb96f3febd24dc5713f23f65e50",
|
||||
"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_id` INTEGER 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": "iconId",
|
||||
"columnName": "icon_id",
|
||||
"affinity": "INTEGER",
|
||||
"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_id` INTEGER, `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": "iconId",
|
||||
"columnName": "icon_id",
|
||||
"affinity": "INTEGER",
|
||||
"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, 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"
|
||||
}
|
||||
],
|
||||
"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, '9ec60cb96f3febd24dc5713f23f65e50')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -87,7 +87,7 @@ import io.homeassistant.companion.android.common.R as commonR
|
|||
Server::class,
|
||||
Setting::class
|
||||
],
|
||||
version = 39,
|
||||
version = 40,
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 24, to = 25),
|
||||
AutoMigration(from = 25, to = 26),
|
||||
|
@ -103,7 +103,8 @@ import io.homeassistant.companion.android.common.R as commonR
|
|||
AutoMigration(from = 35, to = 36),
|
||||
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 = 38, to = 39),
|
||||
AutoMigration(from = 39, to = 40)
|
||||
]
|
||||
)
|
||||
@TypeConverters(
|
||||
|
|
|
@ -13,5 +13,7 @@ data class EntityStateComplications(
|
|||
@ColumnInfo(name = "id")
|
||||
val id: Int,
|
||||
@ColumnInfo(name = "entity_id")
|
||||
val entityId: String
|
||||
val entityId: String,
|
||||
@ColumnInfo(name = "show_title", defaultValue = "1")
|
||||
val showTitle: Boolean
|
||||
)
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
<string name="complication_entity_invalid">Invalid entity</string>
|
||||
<string name="complication_entity_state_content_description">Entity state</string>
|
||||
<string name="complication_entity_state_label">Entity state</string>
|
||||
<string name="complication_entity_state_preview">preview</string>
|
||||
<string name="complication_entity_state_preview">Preview</string>
|
||||
<string name="config">Configuration</string>
|
||||
<string name="configure_service_call">Configure Service Call</string>
|
||||
<string name="configure_widget_label">Widget Label</string>
|
||||
|
@ -721,6 +721,7 @@
|
|||
<string name="show">Show</string>
|
||||
<string name="show_share_logs_summary">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</string>
|
||||
<string name="show_share_logs">Show and Share Logs</string>
|
||||
<string name="show_entity_title">Show entity name</string>
|
||||
<string name="sign_in_on_phone">Sign in on phone</string>
|
||||
<string name="slider_decreased">%1$s decreased</string>
|
||||
<string name="slider_increased">%1$s increased</string>
|
||||
|
|
|
@ -96,6 +96,7 @@ dependencies {
|
|||
implementation("com.google.android.material:material:1.8.0")
|
||||
|
||||
implementation("androidx.wear:wear:1.2.0")
|
||||
implementation("androidx.core:core-ktx:1.10.0")
|
||||
implementation("com.google.android.gms:play-services-wearable:18.0.0")
|
||||
implementation("androidx.wear:wear-input:1.2.0-alpha02")
|
||||
implementation("androidx.wear:wear-remote-interactions:1.0.0")
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
|
||||
<meta-data
|
||||
android:name="android.support.wearable.complications.SUPPORTED_TYPES"
|
||||
android:value="SHORT_TEXT" />
|
||||
android:value="SHORT_TEXT,LONG_TEXT" />
|
||||
<meta-data
|
||||
android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
|
||||
android:value="900" />
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.util.Log
|
|||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.content.IntentCompat
|
||||
import androidx.wear.watchface.complications.datasource.ComplicationDataSourceService.Companion.EXTRA_CONFIG_COMPLICATION_ID
|
||||
import androidx.wear.watchface.complications.datasource.ComplicationDataSourceService.Companion.EXTRA_CONFIG_COMPLICATION_TYPE
|
||||
import androidx.wear.watchface.complications.datasource.ComplicationDataSourceService.Companion.EXTRA_CONFIG_DATA_SOURCE_COMPONENT
|
||||
|
@ -33,9 +34,11 @@ class ComplicationConfigActivity : ComponentActivity() {
|
|||
|
||||
val id = intent.getIntExtra(EXTRA_CONFIG_COMPLICATION_ID, -1)
|
||||
val type = intent.getIntExtra(EXTRA_CONFIG_COMPLICATION_TYPE, -1)
|
||||
val component = intent.getParcelableExtra<ComponentName>(EXTRA_CONFIG_DATA_SOURCE_COMPONENT)
|
||||
val component = IntentCompat.getParcelableExtra(intent, EXTRA_CONFIG_DATA_SOURCE_COMPONENT, ComponentName::class.java)
|
||||
Log.i(TAG, "Config for id $id of type $type for component ${component?.className}")
|
||||
|
||||
complicationConfigViewModel.setDataFromIntent(id)
|
||||
|
||||
setContent {
|
||||
LoadConfigView(
|
||||
complicationConfigViewModel
|
||||
|
|
|
@ -15,6 +15,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import io.homeassistant.companion.android.HomeAssistantApplication
|
||||
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.friendlyName
|
||||
import io.homeassistant.companion.android.common.data.servers.ServerManager
|
||||
import io.homeassistant.companion.android.common.data.websocket.WebSocketState
|
||||
import io.homeassistant.companion.android.data.SimplifiedEntity
|
||||
|
@ -29,8 +30,8 @@ import javax.inject.Inject
|
|||
@HiltViewModel
|
||||
class ComplicationConfigViewModel @Inject constructor(
|
||||
application: Application,
|
||||
favoritesDao: FavoritesDao,
|
||||
private val serverManager: ServerManager,
|
||||
private val favoritesDao: FavoritesDao,
|
||||
private val entityStateComplicationsDao: EntityStateComplicationsDao
|
||||
) : AndroidViewModel(application) {
|
||||
companion object {
|
||||
|
@ -55,11 +56,28 @@ class ComplicationConfigViewModel @Inject constructor(
|
|||
private set
|
||||
var selectedEntity: SimplifiedEntity? by mutableStateOf(null)
|
||||
private set
|
||||
var entityShowTitle by mutableStateOf(true)
|
||||
private set
|
||||
|
||||
init {
|
||||
loadEntities()
|
||||
}
|
||||
|
||||
fun setDataFromIntent(id: Int) {
|
||||
viewModelScope.launch {
|
||||
if (!serverManager.isRegistered() || id <= 0) return@launch
|
||||
|
||||
val stored = entityStateComplicationsDao.get(id)
|
||||
stored?.let {
|
||||
selectedEntity = SimplifiedEntity(entityId = it.entityId)
|
||||
entityShowTitle = it.showTitle
|
||||
if (loadingState == LoadingState.READY) {
|
||||
updateSelectedEntity()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadEntities() {
|
||||
viewModelScope.launch {
|
||||
if (!serverManager.isRegistered()) {
|
||||
|
@ -73,6 +91,7 @@ class ComplicationConfigViewModel @Inject constructor(
|
|||
entities[it.entityId] = it
|
||||
}
|
||||
updateEntityDomains()
|
||||
updateSelectedEntity()
|
||||
|
||||
// Finished initial load, update state
|
||||
val webSocketState = serverManager.webSocketRepository().getConnectionState()
|
||||
|
@ -111,13 +130,32 @@ class ComplicationConfigViewModel @Inject constructor(
|
|||
entitiesByDomainOrder.addAll(domainsList)
|
||||
}
|
||||
|
||||
private fun updateSelectedEntity() {
|
||||
if (selectedEntity == null) return
|
||||
val fullEntity = entities[selectedEntity!!.entityId]
|
||||
|
||||
selectedEntity = if (fullEntity == null) {
|
||||
null // Clear invalid value
|
||||
} else {
|
||||
SimplifiedEntity(
|
||||
entityId = fullEntity.entityId,
|
||||
friendlyName = fullEntity.friendlyName,
|
||||
icon = (fullEntity.attributes as? Map<*, *>)?.get("icon") as? String ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setEntity(entity: SimplifiedEntity) {
|
||||
selectedEntity = entity
|
||||
}
|
||||
|
||||
fun setShowTitle(show: Boolean) {
|
||||
entityShowTitle = show
|
||||
}
|
||||
|
||||
fun addEntityStateComplication(id: Int, entity: SimplifiedEntity) {
|
||||
viewModelScope.launch {
|
||||
entityStateComplicationsDao.add(EntityStateComplications(id, entity.entityId))
|
||||
entityStateComplicationsDao.add(EntityStateComplications(id, entity.entityId, entityShowTitle))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.BroadcastReceiver
|
|||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.wear.watchface.complications.datasource.ComplicationDataSourceService.Companion.EXTRA_CONFIG_COMPLICATION_ID
|
||||
import androidx.wear.watchface.complications.datasource.ComplicationDataSourceUpdateRequester
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.homeassistant.companion.android.common.data.servers.ServerManager
|
||||
|
@ -92,6 +93,20 @@ class ComplicationReceiver : BroadcastReceiver() {
|
|||
)
|
||||
}
|
||||
|
||||
fun getComplicationConfigureIntent(
|
||||
context: Context,
|
||||
complicationInstanceId: Int
|
||||
): PendingIntent {
|
||||
return PendingIntent.getActivity(
|
||||
context,
|
||||
complicationInstanceId,
|
||||
Intent(context, ComplicationConfigActivity::class.java).apply {
|
||||
putExtra(EXTRA_CONFIG_COMPLICATION_ID, complicationInstanceId)
|
||||
},
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
}
|
||||
|
||||
fun getAssistIntent(context: Context): PendingIntent {
|
||||
return PendingIntent.getActivity(
|
||||
context,
|
||||
|
|
|
@ -3,8 +3,10 @@ package io.homeassistant.companion.android.complications
|
|||
import android.graphics.Color
|
||||
import android.graphics.drawable.Icon
|
||||
import android.util.Log
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.wear.watchface.complications.data.ComplicationData
|
||||
import androidx.wear.watchface.complications.data.ComplicationType
|
||||
import androidx.wear.watchface.complications.data.LongTextComplicationData
|
||||
import androidx.wear.watchface.complications.data.MonochromaticImage
|
||||
import androidx.wear.watchface.complications.data.PlainComplicationText
|
||||
import androidx.wear.watchface.complications.data.ShortTextComplicationData
|
||||
|
@ -15,9 +17,12 @@ import com.mikepenz.iconics.typeface.library.community.material.CommunityMateria
|
|||
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.friendlyName
|
||||
import io.homeassistant.companion.android.common.data.integration.friendlyState
|
||||
import io.homeassistant.companion.android.common.data.integration.getIcon
|
||||
import io.homeassistant.companion.android.common.data.servers.ServerManager
|
||||
import io.homeassistant.companion.android.database.wear.EntityStateComplicationsDao
|
||||
import retrofit2.HttpException
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
|
@ -34,60 +39,131 @@ class EntityStateDataSourceService : SuspendingComplicationDataSourceService() {
|
|||
}
|
||||
|
||||
override suspend fun onComplicationRequest(request: ComplicationRequest): ComplicationData? {
|
||||
if (request.complicationType != ComplicationType.SHORT_TEXT) {
|
||||
if (request.complicationType != ComplicationType.SHORT_TEXT && request.complicationType != ComplicationType.LONG_TEXT) {
|
||||
return null
|
||||
}
|
||||
|
||||
val id = request.complicationInstanceId
|
||||
|
||||
val entityId = entityStateComplicationsDao.get(id)?.entityId
|
||||
?: return ShortTextComplicationData.Builder(
|
||||
text = PlainComplicationText.Builder(getText(R.string.complication_entity_invalid)).build(),
|
||||
contentDescription = PlainComplicationText.Builder(getText(R.string.complication_entity_state_content_description))
|
||||
.build()
|
||||
).build()
|
||||
val settings = entityStateComplicationsDao.get(request.complicationInstanceId)
|
||||
val entityId = settings?.entityId
|
||||
?: return getErrorComplication(request, R.string.complication_entity_invalid, true)
|
||||
|
||||
val entity = try {
|
||||
serverManager.integrationRepository().getEntity(entityId)
|
||||
?: return ShortTextComplicationData.Builder(
|
||||
text = PlainComplicationText.Builder(getText(R.string.state_unknown)).build(),
|
||||
contentDescription = PlainComplicationText.Builder(getText(R.string.complication_entity_state_content_description))
|
||||
.build()
|
||||
).build()
|
||||
?: return getErrorComplication(request, R.string.state_unknown)
|
||||
} catch (t: Throwable) {
|
||||
Log.e(TAG, "Unable to get entity state for $entityId: ${t.message}")
|
||||
return null
|
||||
return if (t is HttpException && t.code() == 404) {
|
||||
getErrorComplication(request, R.string.complication_entity_invalid)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val attributes = entity.attributes as Map<*, *>
|
||||
val icon = entity.getIcon(applicationContext) ?: CommunityMaterial.Icon.cmd_bookmark
|
||||
val iconBitmap = IconicsDrawable(this, icon).apply {
|
||||
colorInt = Color.WHITE
|
||||
}.toBitmap()
|
||||
return ShortTextComplicationData.Builder(
|
||||
text = PlainComplicationText.Builder(entity.state).build(),
|
||||
contentDescription = PlainComplicationText.Builder(getText(R.string.complication_entity_state_content_description))
|
||||
.build()
|
||||
)
|
||||
.setTapAction(ComplicationReceiver.getComplicationToggleIntent(this, request.complicationInstanceId))
|
||||
.setMonochromaticImage(MonochromaticImage.Builder(Icon.createWithBitmap(iconBitmap)).build())
|
||||
.setTitle(PlainComplicationText.Builder(attributes["friendly_name"] as String? ?: entity.entityId).build())
|
||||
.build()
|
||||
|
||||
val title = if (settings.showTitle) {
|
||||
PlainComplicationText.Builder(entity.friendlyName).build()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val text = PlainComplicationText.Builder(entity.friendlyState(this)).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)
|
||||
|
||||
return when (request.complicationType) {
|
||||
ComplicationType.SHORT_TEXT -> {
|
||||
ShortTextComplicationData.Builder(
|
||||
text = text,
|
||||
contentDescription = contentDescription
|
||||
)
|
||||
.setTitle(title)
|
||||
.setTapAction(tapAction)
|
||||
.setMonochromaticImage(monochromaticImage)
|
||||
.build()
|
||||
}
|
||||
ComplicationType.LONG_TEXT -> {
|
||||
LongTextComplicationData.Builder(
|
||||
text = text,
|
||||
contentDescription = contentDescription
|
||||
)
|
||||
.setTitle(title)
|
||||
.setTapAction(tapAction)
|
||||
.setMonochromaticImage(monochromaticImage)
|
||||
.build()
|
||||
}
|
||||
else -> null // Already handled at the start of the function
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPreviewData(type: ComplicationType): ComplicationData =
|
||||
ShortTextComplicationData.Builder(
|
||||
text = PlainComplicationText.Builder(getText(R.string.complication_entity_state_preview)).build(),
|
||||
contentDescription = PlainComplicationText.Builder(getText(R.string.complication_entity_state_content_description)).build()
|
||||
)
|
||||
.setMonochromaticImage(
|
||||
MonochromaticImage.Builder(
|
||||
Icon.createWithResource(
|
||||
this,
|
||||
io.homeassistant.companion.android.R.drawable.ic_lightbulb
|
||||
)
|
||||
).build()
|
||||
override fun getPreviewData(type: ComplicationType): ComplicationData? {
|
||||
val text = PlainComplicationText.Builder(getText(R.string.complication_entity_state_preview)).build()
|
||||
val contentDescription = PlainComplicationText.Builder(getText(R.string.complication_entity_state_content_description)).build()
|
||||
val title = PlainComplicationText.Builder(getText(R.string.entity)).build()
|
||||
val monochromaticImage = MonochromaticImage.Builder(
|
||||
Icon.createWithResource(
|
||||
this,
|
||||
io.homeassistant.companion.android.R.drawable.ic_lightbulb
|
||||
)
|
||||
.setTitle(PlainComplicationText.Builder(getText(R.string.entity)).build())
|
||||
.build()
|
||||
).build()
|
||||
return when (type) {
|
||||
ComplicationType.SHORT_TEXT -> {
|
||||
ShortTextComplicationData.Builder(
|
||||
text = text,
|
||||
contentDescription = contentDescription
|
||||
)
|
||||
.setTitle(title)
|
||||
.setMonochromaticImage(monochromaticImage)
|
||||
.build()
|
||||
}
|
||||
ComplicationType.LONG_TEXT -> {
|
||||
LongTextComplicationData.Builder(
|
||||
text = text,
|
||||
contentDescription = contentDescription
|
||||
)
|
||||
.setTitle(title)
|
||||
.setMonochromaticImage(monochromaticImage)
|
||||
.build()
|
||||
}
|
||||
else -> {
|
||||
Log.w(TAG, "Preview for unsupported complication type $type requested")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a simple complication for errors with [textRes] in the text slot.
|
||||
*
|
||||
* @param setTapAction If tapping the complication should open configuration
|
||||
*/
|
||||
private fun getErrorComplication(
|
||||
request: ComplicationRequest,
|
||||
@StringRes textRes: Int,
|
||||
setTapAction: Boolean = false
|
||||
): ComplicationData {
|
||||
val text = PlainComplicationText.Builder(
|
||||
if (setTapAction) { "+" } else { getText(textRes) }
|
||||
).build()
|
||||
val contentDescription = PlainComplicationText.Builder(getText(R.string.complication_entity_state_content_description)).build()
|
||||
val tapAction = if (setTapAction) {
|
||||
ComplicationReceiver.getComplicationConfigureIntent(this, request.complicationInstanceId)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return if (request.complicationType == ComplicationType.SHORT_TEXT) {
|
||||
ShortTextComplicationData.Builder(
|
||||
text = text,
|
||||
contentDescription = contentDescription
|
||||
).setTapAction(tapAction).build()
|
||||
} else {
|
||||
LongTextComplicationData.Builder(
|
||||
text = text,
|
||||
contentDescription = contentDescription
|
||||
).setTapAction(tapAction).build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,25 +7,29 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Devices
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.wear.compose.material.Button
|
||||
import androidx.wear.compose.material.ButtonDefaults
|
||||
import androidx.wear.compose.material.Chip
|
||||
import androidx.wear.compose.material.ChipDefaults
|
||||
import androidx.wear.compose.material.ExperimentalWearMaterialApi
|
||||
import androidx.wear.compose.material.Icon
|
||||
import androidx.wear.compose.material.Text
|
||||
import androidx.wear.compose.material.ToggleChip
|
||||
import androidx.wear.compose.material.ToggleChipDefaults
|
||||
import androidx.wear.compose.navigation.SwipeDismissableNavHost
|
||||
import androidx.wear.compose.navigation.composable
|
||||
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
|
||||
import com.mikepenz.iconics.compose.Image
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import io.homeassistant.companion.android.HomeAssistantApplication
|
||||
import io.homeassistant.companion.android.common.R
|
||||
import io.homeassistant.companion.android.complications.ComplicationConfigViewModel
|
||||
import io.homeassistant.companion.android.data.SimplifiedEntity
|
||||
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.util.simplifiedEntity
|
||||
import io.homeassistant.companion.android.views.ChooseEntityView
|
||||
import io.homeassistant.companion.android.views.ListHeader
|
||||
import io.homeassistant.companion.android.views.ThemeLazyColumn
|
||||
|
@ -33,7 +37,6 @@ import io.homeassistant.companion.android.views.ThemeLazyColumn
|
|||
private const val SCREEN_MAIN = "main"
|
||||
private const val SCREEN_CHOOSE_ENTITY = "choose_entity"
|
||||
|
||||
@OptIn(ExperimentalWearMaterialApi::class)
|
||||
@Composable
|
||||
fun LoadConfigView(
|
||||
complicationConfigViewModel: ComplicationConfigViewModel,
|
||||
|
@ -48,15 +51,16 @@ fun LoadConfigView(
|
|||
composable(SCREEN_MAIN) {
|
||||
MainConfigView(
|
||||
entity = complicationConfigViewModel.selectedEntity,
|
||||
showTitle = complicationConfigViewModel.entityShowTitle,
|
||||
loadingState = complicationConfigViewModel.loadingState,
|
||||
onChooseEntityClicked = {
|
||||
swipeDismissableNavController.navigate(SCREEN_CHOOSE_ENTITY)
|
||||
},
|
||||
onShowTitleClicked = complicationConfigViewModel::setShowTitle,
|
||||
onAcceptClicked = onAcceptClicked
|
||||
)
|
||||
}
|
||||
composable(SCREEN_CHOOSE_ENTITY) {
|
||||
val app = complicationConfigViewModel.getApplication<HomeAssistantApplication>()
|
||||
ChooseEntityView(
|
||||
entitiesByDomainOrder = complicationConfigViewModel.entitiesByDomainOrder,
|
||||
entitiesByDomain = complicationConfigViewModel.entitiesByDomain,
|
||||
|
@ -76,8 +80,10 @@ fun LoadConfigView(
|
|||
@Composable
|
||||
fun MainConfigView(
|
||||
entity: SimplifiedEntity?,
|
||||
showTitle: Boolean,
|
||||
loadingState: ComplicationConfigViewModel.LoadingState,
|
||||
onChooseEntityClicked: () -> Unit,
|
||||
onShowTitleClicked: (Boolean) -> Unit,
|
||||
onAcceptClicked: () -> Unit
|
||||
) {
|
||||
ThemeLazyColumn {
|
||||
|
@ -119,6 +125,26 @@ fun MainConfigView(
|
|||
onClick = onChooseEntityClicked
|
||||
)
|
||||
}
|
||||
item {
|
||||
val isChecked = !loaded || showTitle
|
||||
ToggleChip(
|
||||
checked = isChecked,
|
||||
onCheckedChange = onShowTitleClicked,
|
||||
label = { Text(stringResource(R.string.show_entity_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(
|
||||
|
@ -139,3 +165,16 @@ fun MainConfigView(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(device = Devices.WEAR_OS_LARGE_ROUND)
|
||||
@Composable
|
||||
fun PreviewMainConfigView() {
|
||||
MainConfigView(
|
||||
entity = simplifiedEntity,
|
||||
showTitle = true,
|
||||
loadingState = ComplicationConfigViewModel.LoadingState.READY,
|
||||
onChooseEntityClicked = {},
|
||||
onShowTitleClicked = {},
|
||||
onAcceptClicked = {}
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue