Add support for entity cards

This commit is contained in:
Paulus Schoutsen 2016-02-16 23:26:56 -08:00
parent 1fb3f2bbf4
commit 09d0e529ed
6 changed files with 204 additions and 51 deletions

View File

@ -0,0 +1,37 @@
<link rel='import' href='../../bower_components/polymer/polymer.html'>
<link rel="import" href="../../bower_components/paper-material/paper-material.html">
<dom-module id='ha-camera-card'>
<style include="paper-material">
:host {
display: block;
position: relative;
font-size: 0px;
border-radius: 2px;
cursor: pointer;
}
.camera-feed {
width: 100%;
height: auto;
}
.caption {
position: absolute;
left: 0px;
right: 0px;
bottom: 0px;
background-color: rgba(0, 0, 0, 0.3);
padding: 16px;
text-transform: capitalize;
font-size: 16px;
font-weight: 500;
line-height: 16px;
color: white;
}
</style>
<template>
<img src='[[cameraFeedSrc]]' class='camera-feed'>
<div class='caption'>[[stateObj.entityDisplay]]</div>
</template>
</dom-module>

View File

@ -0,0 +1,52 @@
import Polymer from '../polymer';
import hass from '../util/home-assistant-js-instance';
const { moreInfoActions } = hass;
const UPDATE_INTERVAL = 10000; // ms
export default new Polymer({
is: 'ha-camera-card',
properties: {
stateObj: {
type: Object,
observer: 'updateCameraFeedSrc',
},
cameraFeedSrc: {
type: String,
},
/**
* The z-depth of the card, from 0-5.
*/
elevation: {
type: Number,
value: 1,
reflectToAttribute: true,
},
},
listeners: {
tap: 'cardTapped',
},
attached() {
this.timer = setInterval(() => this.updateCameraFeedSrc(this.stateObj),
UPDATE_INTERVAL);
},
detached() {
clearInterval(this.timer);
},
cardTapped() {
this.async(() => moreInfoActions.selectEntity(this.stateObj.entityId), 1);
},
updateCameraFeedSrc(stateObj) {
const time = (new Date()).getTime();
this.cameraFeedSrc = `${stateObj.attributes.entity_picture}?time=${time}`;
},
});

View File

@ -0,0 +1,5 @@
<link rel='import' href='../../bower_components/polymer/polymer.html'>
<link rel='import' href='./ha-camera-card.html'>
<link rel='import' href='./ha-entities-card.html'>
<link rel='import' href='./ha-introduction-card.html'>

View File

@ -0,0 +1,53 @@
import Polymer from '../polymer';
require('./ha-camera-card');
require('./ha-entities-card');
require('./ha-introduction-card');
export default new Polymer({
is: 'ha-card-chooser',
properties: {
cardData: {
type: Object,
observer: 'cardDataChanged',
},
},
cardDataChanged(newData, oldData) {
const root = Polymer.dom(this);
if (!newData) {
if (root.lastChild) {
root.removeChild(root.lastChild);
}
return;
}
const newElement = !oldData || oldData.cardType !== newData.cardType;
let card;
if (newElement) {
if (root.lastChild) {
root.removeChild(root.lastChild);
}
card = document.createElement(`ha-${newData.cardType}-card`);
} else {
card = root.lastChild;
}
Object.keys(newData).forEach(key => card[key] = newData[key]);
if (oldData) {
Object.keys(oldData).forEach(key => {
if (!(key in newData)) {
card[key] = undefined;
}
});
}
if (newElement) {
root.appendChild(card);
}
},
});

View File

@ -2,8 +2,7 @@
<link rel="import" href="./ha-demo-badge.html">
<link rel="import" href="../cards/ha-badges-card.html">
<link rel="import" href="../cards/ha-entities-card.html">
<link rel="import" href="../cards/ha-introduction-card.html">
<link rel="import" href="../cards/ha-card-chooser.html">
<dom-module id="ha-cards">
<style>
@ -53,7 +52,7 @@
<template>
<div class='main'>
<template is='dom-if' if='[[cards._badges.length]]'>
<template is='dom-if' if='[[cards._badges]]'>
<div class='badges'>
<template is='dom-if' if='[[cards._demo]]'>
<ha-demo-badge></ha-demo-badge>
@ -62,29 +61,20 @@
<ha-badges-card states='[[cards._badges]]'></ha-badges-card>
</div>
</template>
<template is='dom-if' if='[[!cards._badges.length]]'>
<template is='dom-if' if='[[!cards._badges]]'>
<div class='no-badges'> </div>
</template>
<div class='horizontal layout'>
<template is='dom-repeat' items='[[cards._columns]]' as='column'>
<template is='dom-if'
if='[[computeShouldRenderColumn(index, column)]]'>
<div class='column flex-1'>
<template is='dom-if' if='[[computeShowIntroduction(index, showIntroduction, cards)]]'>
<div class='zone-card'>
<ha-introduction-card show-hide-instruction='[[computeShowHideInstruction(states, cards)]]'></ha-introduction-card>
</div>
</template>
<template is='dom-repeat' items='[[column]]' as='domain'>
<div class='zone-card'>
<ha-entities-card
states='[[computeStatesOfCard(cards, domain)]]'
group-entity='[[computeGroupEntityOfCard(cards, domain)]]'
></ha-entities-card>
</div>
</template>
</div>
</template>
<div class='column flex-1'>
<template is='dom-repeat' items='[[column]]' as='card'>
<div class='zone-card'>
<ha-card-chooser card-data='[[computeCardDataOfCard(cards, card)]]'
></ha-entities-card>
</div>
</template>
</div>
</template>
</div>
</template>

View File

@ -3,10 +3,12 @@ import hass from '../util/home-assistant-js-instance';
require('.//ha-demo-badge');
require('../cards/ha-badges-card');
require('../cards/ha-entities-card');
require('../cards/ha-introduction-card');
require('../cards/ha-card-chooser');
const { util } = hass;
const DOMAINS_WITH_CARD = ['camera'];
const PRIORITY = {
configurator: -20,
group: -10,
@ -15,7 +17,6 @@ const PRIORITY = {
sun: 1,
device_tracker: 2,
alarm_control_panel: 3,
camera: 4,
sensor: 5,
binary_sensor: 6,
scene: 7,
@ -77,15 +78,45 @@ export default new Polymer({
return old;
}
if (showIntroduction) {
increaseIndex();
cards._columns[increaseIndex()].push('ha-introduction');
cards['ha-introduction'] = {
cardType: 'introduction',
showHideInstruction: states.size > 0 && !__DEMO__,
};
}
function pushCard(name, entities, groupEntity = false) {
if (entities.length === 0) {
return;
function addEntitiesCard(name, entities, groupEntity = false) {
if (entities.length === 0) return;
const owncard = [];
const other = [];
entities.forEach(entity => {
if (DOMAINS_WITH_CARD.indexOf(entity.domain) === -1) {
other.push(entity);
} else {
owncard.push(entity);
}
});
const curIndex = increaseIndex();
if (other.length > 0) {
cards._columns[curIndex].push(name);
cards[name] = {
cardType: 'entities',
states: other,
groupEntity,
};
}
cards._columns[increaseIndex()].push(name);
cards[name] = { entities, groupEntity };
owncard.forEach(entity => {
cards._columns[curIndex].push(entity.entityId);
cards[entity.entityId] = {
cardType: entity.domain,
stateObj: entity,
};
});
}
byDomain.keySeq().sortBy(domain => getPriority(domain))
@ -106,34 +137,19 @@ export default new Polymer({
.forEach(groupState => {
const entities = util.expandGroup(groupState, states);
entities.forEach(entity => hasGroup[entity.entityId] = true);
pushCard(groupState.entityDisplay, entities.toArray(), groupState);
addEntitiesCard(groupState.entityId, entities.toArray(), groupState);
}
);
} else {
pushCard(domain, filterGrouped(byDomain.get(domain)).sortBy(entitySortBy).toArray());
addEntitiesCard(
domain, filterGrouped(byDomain.get(domain)).sortBy(entitySortBy).toArray());
}
}
);
return cards;
},
computeShouldRenderColumn(index, items) {
return index === 0 || items.length;
},
computeShowIntroduction(index, showIntroduction, cards) {
return index === 0 && (showIntroduction || cards._demo);
},
computeShowHideInstruction(states, cards) {
return states.size > 0 && !__DEMO__ && !cards._demo;
},
computeGroupEntityOfCard(cards, card) {
return card in cards && cards[card].groupEntity;
},
computeStatesOfCard(cards, card) {
return card in cards && cards[card].entities;
computeCardDataOfCard(cards, card) {
return cards[card];
},
});