Love: Rework PictureEntityCard (#1359)

* Love: Rework picture-entity-card

* Rework

* Use OFFLINE const

* Add optional title

* Fix issue, lint
This commit is contained in:
c727 2018-06-29 04:36:52 +02:00 committed by Paulus Schoutsen
parent 3442700e1f
commit 038f5b644b
5 changed files with 169 additions and 147 deletions

View File

@ -12,7 +12,7 @@ class HuiColumnCard extends PolymerElement {
#root { #root {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-top: -4px margin-top: -4px;
margin-bottom: -8px; margin-bottom: -8px;
} }
#root > * { #root > * {

View File

@ -1,144 +0,0 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.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 LocalizeMixin from '../../../mixins/localize-mixin.js';
const DOMAINS_NO_STATE = ['scene', 'script', 'weblink'];
/*
* @appliesMixin LocalizeMixin
*/
class HuiPictureCard extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style>
ha-card {
position: relative;
cursor: pointer;
min-height: 48px;
line-height: 0;
}
img {
width: 100%;
height: auto;
border-radius: 2px;
}
img.state-off {
filter: grayscale(100%);
}
.text {
@apply --paper-font-common-nowrap;
position: absolute;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
padding: 16px;
font-size: 16px;
line-height: 16px;
color: white;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
display: flex;
justify-content: space-between;
}
.text .title {
font-weight: 500;
}
.error {
background-color: red;
color: white;
text-align: center;
}
</style>
<ha-card on-click="_cardClicked">
<img class$="[[_computeClass(config.entity, hass.states)]]" src="[[config.image]]">
<div class="text">
<div class="title">[[_computeTitle(config.entity, hass.states)]]</div>
<div>[[_computeState(config.entity, hass.states)]]</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'
},
_error: String
};
}
getCardSize() {
return 3;
}
_configChanged(config) {
if (config && config.entity && config.image) {
this._error = null;
} else {
this._error = 'Error in card configuration.';
}
}
_computeClass(entityId, states) {
return DOMAINS_NO_STATE.includes(computeDomain(entityId)) ||
STATES_ON.includes(states[entityId].state) ? '' : 'state-off';
}
_computeTitle(entityId, states) {
return entityId && entityId in states && computeStateName(states[entityId]);
}
_computeState(entityId, states) {
const domain = computeDomain(entityId);
switch (domain) {
case 'scene':
return this.localize('ui.card.scene.activate');
case 'script':
return this.localize('ui.card.script.execute');
case 'weblink':
return 'Open';
default:
return computeStateDisplay(this.localize, states[entityId]);
}
}
_cardClicked() {
const entityId = this.config.entity;
const domain = computeDomain(entityId);
if (domain === 'weblink') {
window.open(this.hass.states[entityId].state);
} else {
const turnOn = !STATES_ON.includes(this.hass.states[entityId].state);
let service;
switch (domain) {
case 'lock':
service = turnOn ? 'unlock' : 'lock';
break;
case 'cover':
service = turnOn ? 'open_cover' : 'close_cover';
break;
default:
service = turnOn ? 'turn_on' : 'turn_off';
}
this.hass.callService(domain, service, { entity_id: entityId });
}
}
}
customElements.define('hui-entity-picture-card', HuiPictureCard);

View File

@ -2,6 +2,7 @@ import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import './hui-error-card.js'; import './hui-error-card.js';
import '../../../components/ha-card.js';
import '../../../components/state-history-charts.js'; import '../../../components/state-history-charts.js';
import '../../../data/ha-state-history-data.js'; import '../../../data/ha-state-history-data.js';

View File

@ -0,0 +1,165 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import './hui-error-card.js';
import '../../../components/ha-card.js';
import { STATES_OFF } from '../../../common/const.js';
import computeDomain from '../../../common/entity/compute_domain.js';
import computeStateDisplay from '../../../common/entity/compute_state_display.js';
import computeStateDomain from '../../../common/entity/compute_state_domain.js';
import computeStateName from '../../../common/entity/compute_state_name.js';
import createErrorCardConfig from '../common/create-error-card-config.js';
import LocalizeMixin from '../../../mixins/localize-mixin.js';
const OFFLINE = 'Offline';
/*
* @appliesMixin LocalizeMixin
*/
class HuiPictureEntityCard extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style>
ha-card {
position: relative;
cursor: pointer;
overflow: hidden;
}
img {
display: block;
width: 100%;
height: auto;
}
.box {
@apply --paper-font-common-nowrap;
position: absolute;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
padding: 16px;
font-size: 16px;
line-height: 16px;
color: white;
display: flex;
justify-content: space-between;
}
#title {
font-weight: 500;
}
</style>
<ha-card on-click="_cardClicked">
<img id="image" src="">
<div class="box">
<div id="title"></div>
<div id="state"></div>
</div>
<template is="dom-if" if="[[_error]]">
<hui-error-card config="[[_error]]"></hui-error-card>
</template>
</ha-card>
`;
}
static get properties() {
return {
hass: {
type: Object,
observer: '_hassChanged'
},
config: {
type: Object,
observer: '_configChanged'
},
_error: Object
};
}
getCardSize() {
return 3;
}
_configChanged(config) {
if (!config || !config.entity || (!config.image && !config.state_image)) {
const error = 'Error in card configuration.';
this._error = createErrorCardConfig(error, config);
return;
}
this._error = null;
}
_hassChanged(hass) {
const config = this.config;
const entityId = config && config.entity;
if (!entityId) {
return;
}
if (!(entityId in hass.states) && this._oldState === OFFLINE) {
return;
}
if (!(entityId in hass.states) || hass.states[entityId].state !== this._oldState) {
this._updateState(hass, entityId, config);
}
}
_updateState(hass, entityId, config) {
const state = entityId in hass.states ? hass.states[entityId].state : OFFLINE;
const stateImg = config.state_image &&
(config.state_image[state] || config.state_image.default);
this.$.image.src = stateImg || config.image;
this.$.image.style.filter = stateImg || (!STATES_OFF.includes(state) && state !== OFFLINE) ?
'' : 'grayscale(100%)';
this.$.title.innerText = config.title || (state === OFFLINE ?
entityId : computeStateName(hass.states[entityId]));
this.$.state.innerText = state === OFFLINE ?
OFFLINE : this._computeState(hass.states[entityId]);
this._oldState = state;
}
_computeState(stateObj) {
const domain = computeStateDomain(stateObj);
switch (domain) {
case 'scene':
return this.localize('ui.card.scene.activate');
case 'script':
return this.localize('ui.card.script.execute');
case 'weblink':
return 'Open';
default:
return computeStateDisplay(this.localize, stateObj);
}
}
_cardClicked() {
const entityId = this.config && this.config.entity;
if (!(entityId in this.hass.states)) {
return;
}
const stateDomain = computeDomain(entityId);
if (stateDomain === 'weblink') {
window.open(this.hass.states[entityId].state);
} else {
const turnOn = STATES_OFF.includes(this.hass.states[entityId].state);
let service;
switch (stateDomain) {
case 'lock':
service = turnOn ? 'unlock' : 'lock';
break;
case 'cover':
service = turnOn ? 'open_cover' : 'close_cover';
break;
default:
service = turnOn ? 'turn_on' : 'turn_off';
}
const serviceDomain = stateDomain === 'group' ? 'homeassistant' : stateDomain;
this.hass.callService(serviceDomain, service, { entity_id: entityId });
}
}
}
customElements.define('hui-picture-entity-card', HuiPictureEntityCard);

View File

@ -10,8 +10,8 @@ import '../cards/hui-history-graph-card.js';
import '../cards/hui-iframe-card.js'; import '../cards/hui-iframe-card.js';
import '../cards/hui-markdown-card.js'; import '../cards/hui-markdown-card.js';
import '../cards/hui-media-control-card.js'; import '../cards/hui-media-control-card.js';
import '../cards/hui-entity-picture-card.js';
import '../cards/hui-picture-elements-card'; import '../cards/hui-picture-elements-card';
import '../cards/hui-picture-entity-card';
import '../cards/hui-picture-glance-card'; import '../cards/hui-picture-glance-card';
import '../cards/hui-plant-status-card.js'; import '../cards/hui-plant-status-card.js';
import '../cards/hui-row-card.js'; import '../cards/hui-row-card.js';
@ -24,7 +24,6 @@ const CARD_TYPES = [
'column', 'column',
'entities', 'entities',
'entity-filter', 'entity-filter',
'entity-picture',
'error', 'error',
'glance', 'glance',
'history-graph', 'history-graph',
@ -32,6 +31,7 @@ const CARD_TYPES = [
'markdown', 'markdown',
'media-control', 'media-control',
'picture-elements', 'picture-elements',
'picture-entity',
'picture-glance', 'picture-glance',
'plant-status', 'plant-status',
'row', 'row',