diff --git a/src/components/ha-push-notifications-toggle.js b/src/components/ha-push-notifications-toggle.js
index fe76ec6de..6d5b0d7fe 100644
--- a/src/components/ha-push-notifications-toggle.js
+++ b/src/components/ha-push-notifications-toggle.js
@@ -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`
-
+
`;
}
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);
diff --git a/src/panels/config/core/ha-config-core.js b/src/panels/config/core/ha-config-core.js
index 8f090eba0..9ef6f6a05 100644
--- a/src/panels/config/core/ha-config-core.js
+++ b/src/panels/config/core/ha-config-core.js
@@ -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) {
}
-
-
-
-
- [[localize('ui.panel.config.core.caption')]]
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
`;
}
@@ -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);
diff --git a/src/panels/config/core/ha-config-section-push-notifications.js b/src/panels/config/core/ha-config-section-push-notifications.js
deleted file mode 100644
index eb5ac25a3..000000000
--- a/src/panels/config/core/ha-config-section-push-notifications.js
+++ /dev/null
@@ -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`
-
-
- [[localize('ui.panel.config.core.section.push_notifications.header')]]
-
- [[localize('ui.panel.config.core.section.push_notifications.introduction')]]
-
-
-
-
-
- [[localize('ui.panel.config.core.section.push_notifications.push_notifications')]]
-
-
-
-
-
-`;
- }
-
- static get properties() {
- return {
- hass: Object,
- isWide: Boolean,
- pushSupported: {
- type: Boolean,
- notify: true,
- },
- };
- }
-}
-
-customElements.define('ha-config-section-push-notifications', HaConfigSectionPushNotifications);
diff --git a/src/panels/profile/ha-change-password-card.js b/src/panels/profile/ha-change-password-card.js
index b841e630e..4e7657f5b 100644
--- a/src/panels/profile/ha-change-password-card.js
+++ b/src/panels/profile/ha-change-password-card.js
@@ -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'
>
-
-
+
+
+
+
diff --git a/src/panels/profile/ha-panel-profile.js b/src/panels/profile/ha-panel-profile.js
index 1dbd8d0d3..fc3744419 100644
--- a/src/panels/profile/ha-panel-profile.js
+++ b/src/panels/profile/ha-panel-profile.js
@@ -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;
}
@@ -46,6 +57,20 @@ class HaPanelProfile extends EventsMixin(PolymerElement) {
You are currently logged in as [[hass.user.name]].
You are an owner.
+
+
+
+
+
+
+
`;
diff --git a/src/panels/config/core/ha-config-section-translation.js b/src/panels/profile/ha-pick-language-row.js
similarity index 54%
rename from src/panels/config/core/ha-config-section-translation.js
rename to src/panels/profile/ha-pick-language-row.js
index 6128fc0cb..7fcfbf709 100644
--- a/src/panels/config/core/ha-config-section-translation.js
+++ b/src/panels/profile/ha-pick-language-row.js
@@ -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`
-
- [[localize('ui.panel.config.core.section.translation.header')]]
-
- [[localize('ui.panel.config.core.section.translation.introduction')]]
+
+
+ [[localize('ui.panel.profile.language.header')]]
+
+ [[localize('ui.panel.profile.language.link_promo')]]
-
-
-
-
-
-
- [[item.nativeName]]
-
-
- >
-
-
-
-`;
+
+
+
+ [[item.nativeName]]
+
+
+
+
+ `;
}
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);
diff --git a/src/panels/config/core/ha-config-section-themes.js b/src/panels/profile/ha-pick-theme-row.js
similarity index 50%
rename from src/panels/config/core/ha-config-section-themes.js
rename to src/panels/profile/ha-pick-theme-row.js
index 161b70075..b4f6b538f 100644
--- a/src/panels/config/core/ha-config-section-themes.js
+++ b/src/panels/profile/ha-pick-theme-row.js
@@ -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`
-
- [[localize('ui.panel.config.core.section.themes.header')]]
-
- [[localize('ui.panel.config.core.section.themes.introduction')]]
+
+
+ [[localize('ui.panel.profile.themes.header')]]
+
+
+ [[localize('ui.panel.profile.themes.error_no_theme')]]
+
+ [[localize('ui.panel.profile.themes.link_promo')]]
-
-
-
-
-
-
- [[theme]]
-
-
-
-
-
-
-`;
+
+
+
+ [[theme]]
+
+
+
+
+ `;
}
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);
diff --git a/src/panels/profile/ha-push-notifications-row.js b/src/panels/profile/ha-push-notifications-row.js
new file mode 100644
index 000000000..f967d7fe4
--- /dev/null
+++ b/src/panels/profile/ha-push-notifications-row.js
@@ -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`
+
+
+ [[localize('ui.panel.profile.push_notifications.header')]]
+
+ [[_description(_platformLoaded, _pushSupported)]]
+ [[localize('ui.panel.profile.push_notifications.link_promo')]]
+
+
+
+ `;
+ }
+
+ 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);
diff --git a/src/panels/profile/ha-settings-row.js b/src/panels/profile/ha-settings-row.js
new file mode 100644
index 000000000..c6584f012
--- /dev/null
+++ b/src/panels/profile/ha-settings-row.js
@@ -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`
+
+
+
+
+
+
+ `;
+ }
+
+ static get properties() {
+ return {
+ narrow: {
+ type: Boolean,
+ reflectToAttribute: true,
+ }
+ };
+ }
+}
+
+customElements.define('ha-settings-row', HaSettingsRow);
diff --git a/src/translations/en.json b/src/translations/en.json
index e7936c863..3d856d21e 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -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",