Lovelace: Add picture-glance card (#1309)

* Lovelace: Add glance-toggle card

* Update

* Option to force dialog

* Fix box height

* Rename const

* Change name, separate sensors

* Lint

* Lint
This commit is contained in:
c727 2018-06-21 05:16:35 +02:00 committed by Paulus Schoutsen
parent 63b123fc8f
commit f8b38ced26
3 changed files with 198 additions and 0 deletions

View File

@ -60,6 +60,14 @@ export const DOMAINS_MORE_INFO_NO_HISTORY = [
'scene',
];
/** States that we consider "on". */
export const STATES_ON = [
'home',
'locked',
'on',
'open',
];
/** States that we consider "off". */
export const STATES_OFF = [
'closed',

View File

@ -0,0 +1,188 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import '../../components/ha-card.js';
import { STATES_ON } from '../../common/const.js';
import computeDomain from '../../common/entity/compute_domain.js';
import computeStateDisplay from '../../common/entity/compute_state_display.js';
import computeStateName from '../../common/entity/compute_state_name.js';
import stateIcon from '../../common/entity/state_icon.js';
import EventsMixin from '../../mixins/events-mixin.js';
import LocalizeMixin from '../../mixins/localize-mixin.js';
const DOMAINS_FORCE_DIALOG = ['binary_sensor', 'device_tracker', 'sensor'];
/*
* @appliesMixin EventsMixin
* @appliesMixin LocalizeMixin
*/
class HuiPictureGlanceCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<style>
ha-card {
position: relative;
min-height: 48px;
line-height: 0;
}
img {
width: 100%;
height: auto;
border-radius: 2px;
}
.box {
@apply --paper-font-common-nowrap;
position: absolute;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
padding: 4px 16px;
font-size: 16px;
line-height: 40px;
color: white;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
display: flex;
justify-content: space-between;
}
.box .title {
font-weight: 500;
}
paper-icon-button, iron-icon {
color: #A9A9A9;
}
paper-icon-button.state-on, iron-icon.state-on {
color: white;
}
iron-icon {
padding: 8px;
}
.error {
background-color: red;
color: white;
text-align: center;
}
</style>
<ha-card>
<img src="[[config.image]]">
<div class="box">
<div class="title">[[config.title]]</div>
<div>
<template is="dom-repeat" items="[[_entitiesDialog]]">
<template is="dom-if" if="[[_showEntity(item, hass.states)]]">
<paper-icon-button
on-click="_openDialog"
class$="[[_computeClass(item, hass.states)]]"
icon="[[_computeIcon(item, hass.states)]]"
title="[[_computeTooltip(item, hass.states)]]"
></paper-icon-button>
</template>
</template>
</div>
<div>
<template is="dom-repeat" items="[[_entitiesService]]">
<template is="dom-if" if="[[_showEntity(item, hass.states)]]">
<paper-icon-button
on-click="_callService"
class$="[[_computeClass(item, hass.states)]]"
icon="[[_computeIcon(item, hass.states)]]"
title="[[_computeTooltip(item, hass.states)]]"
></paper-icon-button>
</template>
</template>
</div>
</div>
<template is="dom-if" if="[[_error]]">
<div class="error">[[_error]]</div>
</template>
</ha-card>
`;
}
static get properties() {
return {
hass: Object,
config: {
type: Object,
observer: '_configChanged'
},
_entitiesDialog: Array,
_entitiesService: Array,
_error: String
};
}
getCardSize() {
return 3;
}
_configChanged(config) {
let dialog = [];
let service = [];
let _error = null;
if (config && config.entities && Array.isArray(config.entities) && config.image) {
if (config.force_dialog) {
dialog = config.entities;
} else {
dialog = config.entities
.filter(entity => DOMAINS_FORCE_DIALOG.includes(computeDomain(entity)));
service = config.entities.filter(entity => !dialog.includes(entity));
}
} else {
_error = 'Error in card configuration.';
}
this.setProperties({
_entitiesDialog: dialog,
_entitiesService: service,
_error
});
}
_showEntity(entityId, states) {
return entityId in states;
}
_computeIcon(entityId, states) {
return stateIcon(states[entityId]);
}
_computeClass(entityId, states) {
return STATES_ON.includes(states[entityId].state) ? 'state-on' : '';
}
_computeTooltip(entityId, states) {
return `${computeStateName(states[entityId])}: ${computeStateDisplay(this.localize, states[entityId])}`;
}
_openDialog(ev) {
this.fire('hass-more-info', { entityId: ev.model.item });
}
_callService(ev) {
const entityId = ev.model.item;
const domain = computeDomain(entityId);
const isOn = STATES_ON.includes(this.hass.states[entityId].state);
let service;
switch (domain) {
case 'lock':
service = isOn ? 'unlock' : 'lock';
break;
case 'cover':
service = isOn ? 'close' : 'open';
break;
case 'scene':
service = 'turn_on';
break;
default:
service = isOn ? 'turn_off' : 'turn_on';
}
this.hass.callService(domain, service, { entity_id: entityId });
}
}
customElements.define('hui-picture-glance-card', HuiPictureGlanceCard);

View File

@ -7,6 +7,7 @@ import './hui-entity-filter-card.js';
import './hui-glance-card';
import './hui-history-graph-card.js';
import './hui-media-control-card.js';
import './hui-picture-glance-card';
import './hui-plant-status-card.js';
import './hui-weather-forecast-card';
import './hui-error-card.js';
@ -20,6 +21,7 @@ const VALID_TYPES = [
'glance',
'history-graph',
'media-control',
'picture-glance',
'plant-status',
'weather-forecast'
];