Move user settings to profile page (#1560)

This commit is contained in:
Paulus Schoutsen 2018-08-11 08:46:16 +02:00 committed by GitHub
parent 1b2b62f04c
commit c39417c93d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 289 additions and 226 deletions

View File

@ -4,29 +4,31 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import EventsMixin from '../mixins/events-mixin.js';
export const pushSupported = (
'serviceWorker' in navigator && 'PushManager' in window &&
(document.location.protocol === 'https:' ||
document.location.hostname === 'localhost' ||
document.location.hostname === '127.0.0.1'));
/*
* @appliesMixin EventsMixin
*/
class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
static get template() {
return html`
<paper-toggle-button hidden$="[[!pushSupported]]" disabled="[[loading]]" checked="{{pushChecked}}"></paper-toggle-button>
<paper-toggle-button
disabled="[[_compDisabled(disabled, loading)]]"
checked="{{pushChecked}}"
></paper-toggle-button>
`;
}
static get properties() {
return {
hass: { type: Object, value: null },
pushSupported: {
disabled: {
type: Boolean,
readOnly: true,
notify: true,
value: (
'serviceWorker' in navigator && 'PushManager' in window &&
(document.location.protocol === 'https:' ||
document.location.hostname === 'localhost' ||
document.location.hostname === '127.0.0.1')
)
value: false,
},
pushChecked: {
type: Boolean,
@ -40,22 +42,20 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
};
}
connectedCallback() {
async connectedCallback() {
super.connectedCallback();
if (!this.pushSupported) return;
navigator.serviceWorker.ready.then(
(reg) => {
reg.pushManager.getSubscription().then((subscription) => {
this.loading = false;
this.pushChecked = !!subscription;
});
},
() => {
// no service worker.
this._setPushSupported(false);
}
);
if (!('serviceWorker' in navigator)) return;
try {
const reg = await navigator.serviceWorker.ready;
reg.pushManager.getSubscription().then((subscription) => {
this.loading = false;
this.pushChecked = !!subscription;
});
} catch (err) {
// We don't set loading to `false` so we remain disabled
}
}
handlePushChange(pushChecked) {
if (!this.pushSupported) return;
@ -121,6 +121,10 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
});
});
}
_compDisabled(disabled, loading) {
return disabled || loading;
}
}
customElements.define('ha-push-notifications-toggle', HaPushNotificationsToggle);

View File

@ -4,15 +4,11 @@ import '@polymer/paper-icon-button/paper-icon-button.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../../layouts/ha-app-layout.js';
import '../../../layouts/hass-subpage.js';
import '../../../resources/ha-style.js';
import './ha-config-section-core.js';
import './ha-config-section-push-notifications.js';
import './ha-config-section-themes.js';
import './ha-config-section-translation.js';
import isComponentLoaded from '../../../common/config/is_component_loaded.js';
import LocalizeMixin from '../../../mixins/localize-mixin.js';
/*
@ -37,33 +33,11 @@ class HaConfigCore extends LocalizeMixin(PolymerElement) {
}
</style>
<ha-app-layout has-scrolling-region="">
<app-header slot="header" fixed="">
<app-toolbar>
<paper-icon-button icon="hass:arrow-left" on-click="_backTapped"></paper-icon-button>
<div main-title="">[[localize('ui.panel.config.core.caption')]]</div>
</app-toolbar>
</app-header>
<hass-subpage header="[[localize('ui.panel.config.core.caption')]]">
<div class$="[[computeClasses(isWide)]]">
<ha-config-section-core is-wide="[[isWide]]" hass="[[hass]]"></ha-config-section-core>
<template is="dom-if" if="[[pushSupported]]">
<div class="border"></div>
<ha-config-section-push-notifications is-wide="[[isWide]]" hass="[[hass]]" push-supported="{{pushSupported}}"></ha-config-section-push-notifications>
</template>
<template is="dom-if" if="[[computeIsTranslationLoaded(hass)]]">
<div class="border"></div>
<ha-config-section-translation is-wide="[[isWide]]" hass="[[hass]]"></ha-config-section-translation>
</template>
<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>
</div>
</ha-app-layout>
</hass-subpage>
`;
}
@ -71,34 +45,12 @@ class HaConfigCore extends LocalizeMixin(PolymerElement) {
return {
hass: Object,
isWide: Boolean,
pushSupported: {
type: Boolean,
value: true,
},
};
}
computeClasses(isWide) {
return isWide ? 'content' : 'content narrow';
}
computeIsZwaveLoaded(hass) {
return isComponentLoaded(hass, 'config.zwave');
}
computeIsTranslationLoaded(hass) {
return hass.translationMetadata &&
Object.keys(hass.translationMetadata.translations).length;
}
computeIsThemesLoaded(hass) {
return hass.themes && hass.themes.themes &&
Object.keys(hass.themes.themes).length;
}
_backTapped() {
history.back();
}
}
customElements.define('ha-config-core', HaConfigCore);

View File

@ -1,53 +0,0 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import '@polymer/iron-label/iron-label.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../../components/ha-push-notifications-toggle.js';
import '../ha-config-section.js';
import LocalizeMixin from '../../../mixins/localize-mixin.js';
/*
* @appliesMixin LocalizeMixin
*/
class HaConfigSectionPushNotifications extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex iron-flex-alignment iron-positioning">
ha-push-notifications-toggle {
margin-left: 16px;
}
</style>
<ha-config-section is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.core.section.push_notifications.header')]]</span>
<span slot="introduction">
[[localize('ui.panel.config.core.section.push_notifications.introduction')]]
</span>
<paper-card>
<div class="card-content">
<iron-label class="horizontal layout">
[[localize('ui.panel.config.core.section.push_notifications.push_notifications')]]
<ha-push-notifications-toggle hass="[[hass]]" push-supported="{{pushSupported}}"></ha-push-notifications-toggle>
</iron-label>
</div>
</paper-card>
</ha-config-section>
`;
}
static get properties() {
return {
hass: Object,
isWide: Boolean,
pushSupported: {
type: Boolean,
notify: true,
},
};
}
}
customElements.define('ha-config-section-push-notifications', HaConfigSectionPushNotifications);

View File

@ -23,8 +23,6 @@ class HaChangePasswordCard extends PolymerElement {
}
paper-card {
display: block;
max-width: 600px;
margin: 16px auto;
}
.currentPassword {
margin-top: -4px;
@ -48,22 +46,24 @@ class HaChangePasswordCard extends PolymerElement {
auto-validate
error-message='Required'
></paper-input>
<paper-input
label='New Password'
type='password'
value='{{_password1}}'
required
auto-validate
error-message='Required'
></paper-input>
<paper-input
label='Confirm New Password'
type='password'
value='{{_password2}}'
required
auto-validate
error-message='Required'
></paper-input>
<template is='dom-if' if='[[_currentPassword]]'>
<paper-input
label='New Password'
type='password'
value='{{_password1}}'
required
auto-validate
error-message='Required'
></paper-input>
<paper-input
label='Confirm New Password'
type='password'
value='{{_password2}}'
required
auto-validate
error-message='Required'
></paper-input>
</template>
</div>
<div class="card-actions">
<template is="dom-if" if="[[_loading]]">

View File

@ -1,6 +1,8 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-item/paper-item-body.js';
import '@polymer/paper-item/paper-item.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
@ -8,10 +10,14 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../components/ha-menu-button.js';
import '../../resources/ha-style.js';
import './ha-change-password-card.js';
import EventsMixin from '../../mixins/events-mixin.js';
import './ha-change-password-card.js';
import './ha-pick-language-row.js';
import './ha-pick-theme-row.js';
import './ha-push-notifications-row.js';
/*
* @appliesMixin EventsMixin
*/
@ -25,10 +31,15 @@ class HaPanelProfile extends EventsMixin(PolymerElement) {
-moz-user-select: initial;
}
paper-card {
.content {
display: block;
max-width: 600px;
margin: 16px auto;
margin: 0 auto;
}
.content > * {
display: block;
margin: 24px 0;
}
</style>
@ -46,6 +57,20 @@ class HaPanelProfile extends EventsMixin(PolymerElement) {
You are currently logged in as [[hass.user.name]].
<template is='dom-if' if='[[hass.user.is_owner]]'>You are an owner.</template>
</div>
<ha-pick-language-row
narrow="[[narrow]]"
hass="[[hass]]"
></ha-pick-language-row>
<ha-pick-theme-row
narrow="[[narrow]]"
hass="[[hass]]"
></ha-pick-theme-row>
<ha-push-notifications-row
narrow="[[narrow]]"
hass="[[hass]]"
></ha-push-notifications-row>
<div class='card-actions'>
<paper-button
class='warning'
@ -53,9 +78,11 @@ class HaPanelProfile extends EventsMixin(PolymerElement) {
>Log out</paper-button>
</div>
</paper-card>
<template is="dom-if" if="[[_canChangePassword(hass.user)]]">
<ha-change-password-card hass="[[hass]]"></ha-change-password-card>
</template>
</div>
</app-header-layout>
`;

View File

@ -5,49 +5,44 @@ import '@polymer/paper-listbox/paper-listbox.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import EventsMixin from '../../mixins/events-mixin.js';
import LocalizeMixin from '../../mixins/localize-mixin.js';
import '../ha-config-section.js';
import EventsMixin from '../../../mixins/events-mixin.js';
import LocalizeMixin from '../../../mixins/localize-mixin.js';
import './ha-settings-row.js';
/*
* @appliesMixin LocalizeMixin
* @appliesMixin EventsMixin
*/
class HaConfigSectionTranslation extends
class HaPickLanguageRow extends
LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<ha-config-section is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.core.section.translation.header')]]</span>
<span slot="introduction">
[[localize('ui.panel.config.core.section.translation.introduction')]]
<style>
a { color: var(--primary-color); }
</style>
<ha-settings-row narrow='[[narrow]]'>
<span slot='heading'>[[localize('ui.panel.profile.language.header')]]</span>
<span slot='description'>
<a
href='https://developers.home-assistant.io/docs/en/internationalization_translation.html'
target='_blank'>[[localize('ui.panel.profile.language.link_promo')]]</a>
</span>
<paper-card>
<div class="card-content">
<paper-dropdown-menu label="[[localize('ui.panel.config.core.section.translation.language')]]" dynamic-align="">
<paper-listbox slot="dropdown-content" attr-for-selected="language-tag" selected="{{languageSelection}}">
<template is="dom-repeat" items="[[languages]]">
<paper-item language-tag$="[[item.tag]]">[[item.nativeName]]</paper-item>
</template>
</paper-listbox>
&gt;</paper-dropdown-menu>
</div>
</paper-card>
</ha-config-section>
`;
<paper-dropdown-menu label="[[localize('ui.panel.profile.language.dropdown_label')]]" dynamic-align="">
<paper-listbox slot="dropdown-content" attr-for-selected="language-tag" selected="{{languageSelection}}">
<template is="dom-repeat" items="[[languages]]">
<paper-item language-tag$="[[item.tag]]">[[item.nativeName]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</ha-settings-row>
`;
}
static get properties() {
return {
hass: {
type: Object,
},
isWide: {
type: Boolean,
},
hass: Object,
narrow: Boolean,
languageSelection: {
type: String,
observer: 'languageSelectionChanged',
@ -83,4 +78,4 @@ class HaConfigSectionTranslation extends
}
}
customElements.define('ha-config-section-translation', HaConfigSectionTranslation);
customElements.define('ha-pick-language-row', HaPickLanguageRow);

View File

@ -6,54 +6,57 @@ import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../ha-config-section.js';
import EventsMixin from '../../../mixins/events-mixin.js';
import LocalizeMixin from '../../../mixins/localize-mixin.js';
import EventsMixin from '../../mixins/events-mixin.js';
import LocalizeMixin from '../../mixins/localize-mixin.js';
/*
* @appliesMixin LocalizeMixin
* @appliesMixin EventsMixin
*/
class HaConfigSectionThemes extends
class HaPickThemeRow extends
LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<ha-config-section is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.core.section.themes.header')]]</span>
<span slot="introduction">
[[localize('ui.panel.config.core.section.themes.introduction')]]
<style>
a { color: var(--primary-color); }
</style>
<ha-settings-row narrow='[[narrow]]'>
<span slot='heading'>[[localize('ui.panel.profile.themes.header')]]</span>
<span slot='description'>
<template is='dom-if' if='[[!_hasThemes]]'>
[[localize('ui.panel.profile.themes.error_no_theme')]]
</template>
<a
href='https://www.home-assistant.io/components/frontend/#defining-themes'
target='_blank'>[[localize('ui.panel.profile.themes.link_promo')]]</a>
</span>
<paper-card>
<div class="card-content">
<paper-dropdown-menu label="[[localize('ui.panel.config.core.section.themes.header')]]" dynamic-align="">
<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>
`;
<paper-dropdown-menu
label="[[localize('ui.panel.profile.themes.dropdown_label')]]"
dynamic-align
disabled='[[!_hasThemes]]'
>
<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>
</ha-settings-row>
`;
}
static get properties() {
return {
hass: {
type: Object,
},
isWide: {
hass: Object,
narrow: Boolean,
_hasThemes: {
type: Boolean,
computed: '_compHasThemes(hass)',
},
themes: {
type: Array,
computed: 'computeThemes(hass)',
computed: '_computeThemes(hass)',
},
selectedTheme: {
type: Number,
},
@ -66,6 +69,11 @@ class HaConfigSectionThemes extends
];
}
_compHasThemes(hass) {
return hass.themes && hass.themes.themes &&
Object.keys(hass.themes.themes).length;
}
ready() {
super.ready();
if (this.hass.selectedTheme && this.themes.indexOf(this.hass.selectedTheme) > 0) {
@ -75,7 +83,7 @@ class HaConfigSectionThemes extends
}
}
computeThemes(hass) {
_computeThemes(hass) {
if (!hass) return [];
return ['Backend-selected', 'default'].concat(Object.keys(hass.themes.themes).sort());
}
@ -91,4 +99,4 @@ class HaConfigSectionThemes extends
}
}
customElements.define('ha-config-section-themes', HaConfigSectionThemes);
customElements.define('ha-pick-theme-row', HaPickThemeRow);

View File

@ -0,0 +1,81 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import '@polymer/iron-label/iron-label.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import isComponentLoaded from '../../common/config/is_component_loaded.js';
import { pushSupported } from '../../components/ha-push-notifications-toggle.js';
import LocalizeMixin from '../../mixins/localize-mixin.js';
import './ha-settings-row.js';
/*
* @appliesMixin LocalizeMixin
*/
class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style>
a { color: var(--primary-color); }
</style>
<ha-settings-row narrow='[[narrow]]'>
<span slot='heading'>[[localize('ui.panel.profile.push_notifications.header')]]</span>
<span
slot='description'
>
[[_description(_platformLoaded, _pushSupported)]]
<a
href='https://www.home-assistant.io/components/notify.html5/'
target='_blank'>[[localize('ui.panel.profile.push_notifications.link_promo')]]</a>
</span>
<ha-push-notifications-toggle
hass="[[hass]]"
disabled='[[_error]]'
></ha-push-notifications-toggle>
</ha-settings-row>
`;
}
static get properties() {
return {
hass: Object,
narrow: Boolean,
_platformLoaded: {
type: Boolean,
computed: '_compPlatformLoaded(hass)'
},
_pushSupported: {
type: Boolean,
value: pushSupported,
},
_error: {
type: Boolean,
computed: '_compError(_platformLoaded, _pushSupported)',
},
};
}
_compPlatformLoaded(hass) {
return isComponentLoaded(hass, 'notify.html5');
}
_compError(platformLoaded, pushSupported_) {
return !platformLoaded || !pushSupported_;
}
_description(platformLoaded, pushSupported_) {
let key;
if (!pushSupported_) {
key = 'error_use_https';
} else if (!platformLoaded) {
key = 'error_load_platform';
} else {
key = 'description';
}
return this.localize(`ui.panel.profile.push_notifications.${key}`);
}
}
customElements.define('ha-push-notifications-row', HaPushNotificationsRow);

View File

@ -0,0 +1,43 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
class HaSettingsRow extends PolymerElement {
static get template() {
return html`
<style>
:host {
display: flex;
padding: 0 16px;
align-content: normal;
align-self: auto;
align-items: center;
}
:host([narrow]) {
align-items: normal;
flex-direction: column;
border-top: 1px solid var(--divider-color);
padding-bottom: 8px;
}
paper-item-body {
padding-right: 16px;
}
</style>
<paper-item-body two-line>
<slot name="heading"></slot>
<div secondary><slot name="description"></slot></div>
</paper-item-body>
<slot></slot>
`;
}
static get properties() {
return {
narrow: {
type: Boolean,
reflectToAttribute: true,
}
};
}
}
customElements.define('ha-settings-row', HaSettingsRow);

View File

@ -516,21 +516,6 @@
"restart": "Restart",
"stop": "Stop"
}
},
"push_notifications": {
"header": "Configure push notifications",
"introduction": "Enable this setting to receive push notifications on this device",
"push_notifications": "Push notifications"
},
"translation": {
"header": "Choose a language",
"introduction": "Choose a language for the Home Assistant interface on this device",
"language": "Language"
},
"themes": {
"header": "Set a theme",
"introduction": "Choose 'Backend-selected' to use whatever theme the backend chooses or pick a theme for this device",
"theme": "Theme"
}
}
},
@ -732,6 +717,27 @@
"delete_prompt": "Delete this message?",
"delete_button": "Delete"
},
"profile": {
"push_notifications": {
"header": "Push Notifications",
"description": "Send notifications to this device",
"error_load_platform": "Configure notify.html5.",
"error_use_https": "Requires SSL enabled for frontend.",
"push_notifications": "Push notifications",
"link_promo": "Learn more"
},
"language": {
"header": "Language",
"link_promo": "Help translating",
"dropdown_label": "Language"
},
"themes": {
"header": "Theme",
"error_no_theme": "No themes available.",
"link_promo": "Learn about themes",
"dropdown_label": "Theme"
}
},
"shopping-list": {
"clear_completed": "Clear completed",
"add_item": "Add item",