Add theme-choosing UI to config panel (#363)

* Add theme-choosing UI to config panel

* Add Backend-selected option

* Use Object.assign to change hass

* Fix #368 - support theme-color update.
This commit is contained in:
Andrey 2017-08-05 09:09:25 +03:00 committed by Paulus Schoutsen
parent 1ea7137c78
commit ebc0c776e2
5 changed files with 145 additions and 26 deletions

View File

@ -8,6 +8,7 @@
<!-- <link rel="import" href="./group/ha-config-section-group.html"> -->
<link rel="import" href="./hassbian/ha-config-section-hassbian.html">
<link rel="import" href="./z-wave/ha-config-section-zwave.html">
<link rel="import" href="themes/ha-config-section-themes.html">
<dom-module id="ha-panel-config">
<template>
@ -53,6 +54,14 @@
hass='[[hass]]'
></ha-config-section-core>
<template is='dom-if' if='[[computeIsThemesLoaded(hass)]]'>
<div class='border'></div>
<ha-config-section-themes
is-wide='[[isWide]]'
hass='[[hass]]'
></ha-config-section-themes>
</template>
<template is='dom-if' if='[[computeIsHassbianLoaded(hass)]]'>
<div class='border'></div>
<ha-config-section-hassbian
@ -120,5 +129,10 @@ Polymer({
computeIsZwaveLoaded: function (hass) {
return window.hassUtil.isComponentLoaded(hass, 'config.zwave');
},
computeIsThemesLoaded: function (hass) {
return hass.themes && hass.themes.themes &&
Object.keys(hass.themes.themes).length;
},
});
</script>

View File

@ -0,0 +1,85 @@
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel='import' href='../../../bower_components/paper-listbox/paper-listbox.html'>
<link rel='import' href='../../../bower_components/paper-item/paper-item.html'>
<link rel="import" href="../ha-config-section.html">
<dom-module id="ha-config-section-themes">
<template>
<ha-config-section is-wide='[[isWide]]'>
<span slot='header'>Set a theme</span>
<span slot='introduction'>
Choose 'default' to use whatever theme the backend chooses or pick a theme for this device.
</span>
<paper-card>
<div class='card-content'>
<paper-dropdown-menu label='Theme' vertical-align='bottom'>
<paper-listbox
slot="dropdown-content"
selected='{{selectedTheme}}'
>
<template is='dom-repeat' items='[[themes]]' as='theme'>
<paper-item>[[theme]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
</paper-card>
</ha-config-section>
</template>
</dom-module>
<script>
Polymer({
is: 'ha-config-section-themes',
properties: {
hass: {
type: Object,
},
isWide: {
type: Boolean,
},
themes: {
type: Array,
computed: 'computeThemes(hass)',
},
selectedTheme: {
type: Number,
},
},
ready: function () {
if (this.hass.selectedTheme && this.themes.indexOf(this.hass.selectedTheme) > 0) {
this.selectedTheme = this.themes.indexOf(this.hass.selectedTheme);
} else if (!this.hass.selectedTheme) {
this.selectedTheme = 0;
}
},
observers: [
'selectionChanged(hass, selectedTheme)',
],
computeThemes: function (hass) {
if (!hass) return [];
return ['Backend-selected', 'default'].concat(Object.keys(hass.themes.themes).sort());
},
selectionChanged: function (hass, selection) {
if (selection > 0 && selection < this.themes.length) {
if (hass.selectedTheme !== this.themes[selection]) {
this.fire('settheme', this.themes[selection]);
}
} else if (selection === 0 && hass.selectedTheme !== '') {
this.fire('settheme', '');
}
}
});
</script>

View File

@ -85,6 +85,10 @@ Polymer({
},
},
listeners: {
settheme: 'setTheme',
},
computeShowMain: function (hass, iconsLoaded) {
return hass && hass.states && hass.config && iconsLoaded;
},
@ -158,13 +162,13 @@ Polymer({
}, this.$.storage.getStoredState());
var reconnected = () => {
this.hass = Object.assign({}, this.hass, { connected: true });
this._updateHass({ connected: true });
};
conn.addEventListener('ready', reconnected);
var disconnected = () => {
this.hass = Object.assign({}, this.hass, { connected: false });
this._updateHass({ connected: false });
};
conn.addEventListener('disconnected', disconnected);
@ -172,7 +176,7 @@ Polymer({
var unsubEntities;
window.HAWS.subscribeEntities(conn, (states) => {
this.hass = Object.assign({}, this.hass, { states: states });
this._updateHass({ states: states });
}).then(function (unsub) {
unsubEntities = unsub;
});
@ -180,7 +184,7 @@ Polymer({
var unsubConfig;
window.HAWS.subscribeConfig(conn, (config) => {
this.hass = Object.assign({}, this.hass, { config: config });
this._updateHass({ config: config });
}).then(function (unsub) {
unsubConfig = unsub;
});
@ -188,12 +192,12 @@ Polymer({
var unsubThemes;
this.hass.callApi('get', 'themes').then((themes) => {
this.hass.themes = themes;
window.hassUtil.applyThemesOnElement(this, themes);
this._updateHass({ themes: themes });
window.hassUtil.applyThemesOnElement(this, themes, this.hass.selectedTheme, true);
});
conn.subscribeEvents((event) => {
this.hass.themes = event.data;
window.hassUtil.applyThemesOnElement(this, event.data);
this._updateHass({ themes: event.data });
window.hassUtil.applyThemesOnElement(this, event.data, this.hass.selectedTheme, true);
}, 'themes_updated').then(function (unsub) {
unsubThemes = unsub;
});
@ -220,16 +224,12 @@ Polymer({
handleMoreInfo: function (ev) {
ev.stopPropagation();
this.hass = Object.assign(
{}, this.hass,
{ moreInfoEntityId: ev.detail.entityId });
this._updateHass({ moreInfoEntityId: ev.detail.entityId });
},
handleDockSidebar: function (ev) {
ev.stopPropagation();
this.hass = Object.assign(
{}, this.hass,
{ dockedSidebar: ev.detail.dock });
this._updateHass({ dockedSidebar: ev.detail.dock });
this.$.storage.storeState();
},
@ -253,5 +253,15 @@ Polymer({
ready: function () {
this.loadIcons();
},
setTheme: function (event) {
this._updateHass({ selectedTheme: event.detail });
window.hassUtil.applyThemesOnElement(this, this.hass.themes, this.hass.selectedTheme, true);
this.$.storage.storeState();
},
_updateHass: function (obj) {
this.hass = Object.assign({}, this.hass, obj);
},
});
</script>

View File

@ -2,6 +2,7 @@
(function () {
var STORED_STATE = [
'dockedSidebar',
'selectedTheme',
];
Polymer({

View File

@ -492,25 +492,34 @@ window.hassUtil.computeLocationName = function (hass) {
return hass && hass.config.core.location_name;
};
window.hassUtil.applyThemesOnElement = function (element, themes, localTheme) {
window.hassUtil.applyThemesOnElement = function (element, themes, localTheme, updateMeta) {
if (!element._themes) {
element._themes = {};
}
var themeName = themes.default_theme;
let themeName = themes.default_theme;
if (localTheme === 'default' || (localTheme && themes.themes[localTheme])) {
themeName = localTheme;
}
if (themeName === 'default') {
element.updateStyles(element._themes);
return;
const styles = Object.assign({}, element._themes);
if (themeName !== 'default') {
var theme = themes.themes[themeName];
Object.keys(theme).forEach((key) => {
var prefixedKey = '--' + key;
element._themes[prefixedKey] = '';
styles[prefixedKey] = theme[key];
});
}
var theme = themes.themes[themeName];
var styles = Object.assign({}, element._themes);
Object.keys(theme).forEach(function (key) {
var prefixedKey = '--' + key;
element._themes[prefixedKey] = '';
styles[prefixedKey] = theme[key];
});
element.updateStyles(styles);
if (!updateMeta) return;
const meta = document.querySelector('meta[name=theme-color]');
if (meta) {
if (!meta.hasAttribute('default-content')) {
meta.setAttribute('default-content', meta.getAttribute('content'));
}
const themeColor = styles['--primary-color'] || meta.getAttribute('default-content');
meta.setAttribute('content', themeColor);
}
};
</script>