diff --git a/src/cards/ha-weather-card.js b/src/cards/ha-weather-card.js index ea145c6b67..00388857a5 100644 --- a/src/cards/ha-weather-card.js +++ b/src/cards/ha-weather-card.js @@ -365,18 +365,12 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { computeDate(data) { const date = new Date(data); - return date.toLocaleDateString( - this.hass.selectedLanguage || this.hass.language, - { weekday: "short" } - ); + return date.toLocaleDateString(this.hass.language, { weekday: "short" }); } computeTime(data) { const date = new Date(data); - return date.toLocaleTimeString( - this.hass.selectedLanguage || this.hass.language, - { hour: "numeric" } - ); + return date.toLocaleTimeString(this.hass.language, { hour: "numeric" }); } _computeRTL(hass) { diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 202576d044..035d1c1802 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -17,6 +17,7 @@ import "./ha-icon"; import isComponentLoaded from "../common/config/is_component_loaded"; import { HomeAssistant, Panel } from "../types"; import { fireEvent } from "../common/dom/fire_event"; +import { DEFAULT_PANEL } from "../common/const"; const computeInitials = (name: string) => { if (!name) { @@ -82,7 +83,12 @@ const computePanels = (hass: HomeAssistant) => { */ class HaSidebar extends LitElement { public hass?: HomeAssistant; - public defaultPage?: string; + public _defaultPage?: string; + + constructor() { + super(); + this._defaultPage = localStorage.defaultPage || DEFAULT_PANEL; + } protected render() { const hass = this.hass; @@ -114,8 +120,8 @@ class HaSidebar extends LitElement { @@ -214,7 +220,7 @@ class HaSidebar extends LitElement { static get properties(): PropertyDeclarations { return { hass: {}, - defaultPage: {}, + _defaultPage: {}, }; } diff --git a/src/components/state-history-chart-timeline.js b/src/components/state-history-chart-timeline.js index 3fcc9a5902..2c31443f8b 100644 --- a/src/components/state-history-chart-timeline.js +++ b/src/components/state-history-chart-timeline.js @@ -190,7 +190,7 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) { yaxe.maxWidth = yaxe.chart.width * 0.18; }, position: this.hass.translationMetadata.translations[ - this.hass.selectedLanguage || this.hass.language + this.hass.language ].isRTL ? "right" : "left", diff --git a/src/dialogs/more-info/controls/more-info-weather.js b/src/dialogs/more-info/controls/more-info-weather.js index e64bb5dcf1..38ee714986 100644 --- a/src/dialogs/more-info/controls/more-info-weather.js +++ b/src/dialogs/more-info/controls/more-info-weather.js @@ -178,20 +178,18 @@ class MoreInfoWeather extends LocalizeMixin(PolymerElement) { provider === "Data provided by OpenWeatherMap" ) { if (new Date().getDay() === date.getDay()) { - return date.toLocaleTimeString( - this.hass.selectedLanguage || this.hass.language, - { hour: "numeric" } - ); + return date.toLocaleTimeString(this.hass.language, { hour: "numeric" }); } - return date.toLocaleDateString( - this.hass.selectedLanguage || this.hass.language, - { weekday: "long", hour: "numeric" } - ); + return date.toLocaleDateString(this.hass.language, { + weekday: "long", + hour: "numeric", + }); } - return date.toLocaleDateString( - this.hass.selectedLanguage || this.hass.language, - { weekday: "long", month: "short", day: "numeric" } - ); + return date.toLocaleDateString(this.hass.language, { + weekday: "long", + month: "short", + day: "numeric", + }); } getUnit(measure) { diff --git a/src/layouts/app/sidebar-mixin.js b/src/layouts/app/sidebar-mixin.js deleted file mode 100644 index 443d81a26d..0000000000 --- a/src/layouts/app/sidebar-mixin.js +++ /dev/null @@ -1,16 +0,0 @@ -import { storeState } from "../../util/ha-pref-storage"; - -export default (superClass) => - class extends superClass { - firstUpdated(changedProps) { - super.firstUpdated(changedProps); - this.addEventListener("hass-dock-sidebar", (e) => - this._handleDockSidebar(e) - ); - } - - _handleDockSidebar(ev) { - this._updateHass({ dockedSidebar: ev.detail.dock }); - storeState(this.hass); - } - }; diff --git a/src/layouts/app/sidebar-mixin.ts b/src/layouts/app/sidebar-mixin.ts new file mode 100644 index 0000000000..3d0f4f5946 --- /dev/null +++ b/src/layouts/app/sidebar-mixin.ts @@ -0,0 +1,30 @@ +import { storeState } from "../../util/ha-pref-storage"; +import { Constructor, LitElement } from "lit-element"; +import { HassBaseEl } from "./hass-base-mixin"; +import { HASSDomEvent } from "../../common/dom/fire_event"; + +interface DockSidebarParams { + dock: boolean; +} + +declare global { + // for fire event + interface HASSDomEvents { + "hass-dock-sidebar": DockSidebarParams; + } + // for add event listener + interface HTMLElementEventMap { + "hass-dock-sidebar": HASSDomEvent; + } +} + +export default (superClass: Constructor) => + class extends superClass { + protected firstUpdated(changedProps) { + super.firstUpdated(changedProps); + this.addEventListener("hass-dock-sidebar", (ev) => { + this._updateHass({ dockedSidebar: ev.detail.dock }); + storeState(this.hass); + }); + } + }; diff --git a/src/layouts/app/translations-mixin.ts b/src/layouts/app/translations-mixin.ts index c069fea240..cac66a1728 100644 --- a/src/layouts/app/translations-mixin.ts +++ b/src/layouts/app/translations-mixin.ts @@ -4,6 +4,8 @@ import { storeState } from "../../util/ha-pref-storage"; import { Constructor, LitElement } from "lit-element"; import { HassBaseEl } from "./hass-base-mixin"; import { computeLocalize } from "../../common/translations/localize"; +import { computeRTL } from "../../common/util/compute_rtl"; +import { HomeAssistant } from "../../types"; /* * superClass needs to contain `this.hass` and `this._updateHass`. @@ -22,6 +24,7 @@ export default (superClass: Constructor) => protected hassConnected() { super.hassConnected(); this._loadBackendTranslations(); + this.style.direction = computeRTL(this.hass!) ? "rtl" : "ltr"; } protected hassReconnected() { @@ -79,15 +82,17 @@ export default (superClass: Constructor) => ...data, }, }; - this._updateHass({ - language, - resources, - localize: computeLocalize(this, language, resources), - }); + const changes: Partial = { resources }; + if (language === this.hass!.language) { + changes.localize = computeLocalize(this, language, resources); + } + this._updateHass(changes); } private _selectLanguage(event) { - this._updateHass({ selectedLanguage: event.detail.language }); + const language: string = event.detail.language; + this._updateHass({ language, selectedLanguage: language }); + this.style.direction = computeRTL(this.hass!) ? "rtl" : "ltr"; storeState(this.hass); this._loadResources(); this._loadBackendTranslations(); diff --git a/src/layouts/home-assistant-main.js b/src/layouts/home-assistant-main.js deleted file mode 100644 index 768b3968d8..0000000000 --- a/src/layouts/home-assistant-main.js +++ /dev/null @@ -1,152 +0,0 @@ -import "@polymer/app-layout/app-drawer-layout/app-drawer-layout"; -import "@polymer/app-layout/app-drawer/app-drawer"; -import "@polymer/app-route/app-route"; -import "@polymer/iron-media-query/iron-media-query"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../util/ha-url-sync"; - -import "./partial-panel-resolver"; -import EventsMixin from "../mixins/events-mixin"; -import NavigateMixin from "../mixins/navigate-mixin"; -import { computeRTL } from "../common/util/compute_rtl"; -import { DEFAULT_PANEL } from "../common/const"; - -import(/* webpackChunkName: "ha-sidebar" */ "../components/ha-sidebar"); -import(/* webpackChunkName: "voice-command-dialog" */ "../dialogs/ha-voice-command-dialog"); - -const NON_SWIPABLE_PANELS = ["kiosk", "map"]; - -class HomeAssistantMain extends NavigateMixin(EventsMixin(PolymerElement)) { - static get template() { - return html` - - - - - - - - - - - - - - `; - } - - static get properties() { - return { - hass: Object, - narrow: Boolean, - route: { - type: Object, - observer: "_routeChanged", - }, - dockedSidebar: { - type: Boolean, - computed: "computeDockedSidebar(hass)", - }, - rtl: { - type: Boolean, - reflectToAttribute: true, - computed: "_computeRTL(hass)", - }, - }; - } - - ready() { - super.ready(); - this._defaultPage = localStorage.defaultPage || DEFAULT_PANEL; - this.addEventListener("hass-open-menu", () => this.handleOpenMenu()); - this.addEventListener("hass-close-menu", () => this.handleCloseMenu()); - this.addEventListener("hass-start-voice", (ev) => - this.handleStartVoice(ev) - ); - } - - _routeChanged() { - if (this.narrow) { - this.$.drawer.close(); - } - } - - handleStartVoice(ev) { - ev.stopPropagation(); - this.$.voiceDialog.opened = true; - } - - handleOpenMenu() { - if (this.narrow) { - this.$.drawer.open(); - } else { - this.fire("hass-dock-sidebar", { dock: true }); - } - } - - handleCloseMenu() { - this.$.drawer.close(); - if (this.dockedSidebar) { - this.fire("hass-dock-sidebar", { dock: false }); - } - } - - computeForceNarrow(narrow, dockedSidebar) { - return narrow || !dockedSidebar; - } - - computeDockedSidebar(hass) { - return hass.dockedSidebar; - } - - _computeDisableSwipe(hass) { - return NON_SWIPABLE_PANELS.indexOf(hass.panelUrl) !== -1; - } - - _computeRTL(hass) { - return computeRTL(hass); - } -} - -customElements.define("home-assistant-main", HomeAssistantMain); diff --git a/src/layouts/home-assistant-main.ts b/src/layouts/home-assistant-main.ts new file mode 100644 index 0000000000..2e6c8a5dc6 --- /dev/null +++ b/src/layouts/home-assistant-main.ts @@ -0,0 +1,151 @@ +import { + LitElement, + html, + TemplateResult, + PropertyDeclarations, + CSSResult, + css, + PropertyValues, +} from "lit-element"; +import "@polymer/app-layout/app-drawer-layout/app-drawer-layout"; +import "@polymer/app-layout/app-drawer/app-drawer"; +// Not a duplicate, it's for typing +// tslint:disable-next-line +import { AppDrawerElement } from "@polymer/app-layout/app-drawer/app-drawer"; +import "@polymer/app-route/app-route"; +import "@polymer/iron-media-query/iron-media-query"; + +import "../util/ha-url-sync"; + +import "./partial-panel-resolver"; +import { HomeAssistant, Route } from "../types"; +import { fireEvent } from "../common/dom/fire_event"; +import { PolymerChangedEvent } from "../polymer-types"; + +import(/* webpackChunkName: "ha-sidebar" */ "../components/ha-sidebar"); +import(/* webpackChunkName: "voice-command-dialog" */ "../dialogs/ha-voice-command-dialog"); + +const NON_SWIPABLE_PANELS = ["kiosk", "map"]; + +class HomeAssistantMain extends LitElement { + public hass?: HomeAssistant; + public route?: Route; + private _narrow?: boolean; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + narrow: {}, + route: {}, + }; + } + + protected render(): TemplateResult | void { + const hass = this.hass; + + if (!hass) { + return; + } + + const disableSwipe = NON_SWIPABLE_PANELS.indexOf(hass.panelUrl) !== -1; + + return html` + + + + + + + + + + + + `; + } + + protected firstUpdated() { + this.addEventListener("hass-open-menu", () => { + if (this._narrow) { + this.drawer.open(); + } else { + fireEvent(this, "hass-dock-sidebar", { dock: true }); + } + }); + this.addEventListener("hass-close-menu", () => { + this.drawer.close(); + if (this.hass!.dockedSidebar) { + fireEvent(this, "hass-dock-sidebar", { dock: false }); + } + }); + this.addEventListener("hass-start-voice", () => { + (this.voiceDialog as any).opened = true; + }); + } + + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + + if (changedProps.has("route") && this._narrow) { + this.drawer.close(); + } + + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + + // Make app-drawer adjust to a potential LTR/RTL change + if (oldHass && oldHass.language !== this.hass!.language) { + this.drawer._resetPosition(); + } + } + + private _narrowChanged(ev: PolymerChangedEvent) { + this._narrow = ev.detail.value; + } + + private get drawer(): AppDrawerElement { + return this.shadowRoot!.querySelector("app-drawer")!; + } + + private get voiceDialog() { + return this.shadowRoot!.querySelector("ha-voice-command-dialog")!; + } + + static get styles(): CSSResult { + return css` + :host { + color: var(--primary-text-color); + /* remove the grey tap highlights in iOS on the fullscreen touch targets */ + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + } + partial-panel-resolver, + ha-sidebar { + /* allow a light tap highlight on the actual interface elements */ + -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1); + } + partial-panel-resolver { + height: 100%; + } + `; + } +} + +customElements.define("home-assistant-main", HomeAssistantMain); diff --git a/src/panels/lovelace/components/hui-generic-entity-row.ts b/src/panels/lovelace/components/hui-generic-entity-row.ts index ef2afdd5e3..2409179b65 100644 --- a/src/panels/lovelace/components/hui-generic-entity-row.ts +++ b/src/panels/lovelace/components/hui-generic-entity-row.ts @@ -9,9 +9,11 @@ import { html, css, CSSResult, + PropertyValues, } from "lit-element"; import { HomeAssistant } from "../../../types"; import { EntitiesCardEntityConfig } from "../cards/hui-entities-card"; +import { computeRTL } from "../../../common/util/compute_rtl"; class HuiGenericEntityRow extends LitElement { public hass?: HomeAssistant; @@ -76,6 +78,13 @@ class HuiGenericEntityRow extends LitElement { }; } + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + if (changedProps.has("hass")) { + this.toggleAttribute("rtl", computeRTL(this.hass!)); + } + } + static get styles(): CSSResult { return css` :host { @@ -119,6 +128,14 @@ class HuiGenericEntityRow extends LitElement { state-badge { flex: 0 0 40px; } + :host([rtl]) .flex { + margin-left: 0; + margin-right: 16px; + } + :host([rtl]) .flex ::slotted(*) { + margin-left: 0; + margin-right: 8px; + } `; } } diff --git a/src/panels/profile/ha-pick-language-row.js b/src/panels/profile/ha-pick-language-row.js index 5e73e24e16..698d647bda 100644 --- a/src/panels/profile/ha-pick-language-row.js +++ b/src/panels/profile/ha-pick-language-row.js @@ -21,6 +21,12 @@ class HaPickLanguageRow extends LocalizeMixin(EventsMixin(PolymerElement)) { a { color: var(--primary-color); } + paper-item { + direction: ltr; + } + paper-item[is-rtl] { + direction: rtl; + } @@ -76,9 +82,10 @@ class HaPickLanguageRow extends LocalizeMixin(EventsMixin(PolymerElement)) { if (!hass || !hass.translationMetadata) { return []; } - return Object.keys(hass.translationMetadata.translations).map((key) => ({ - tag: key, - nativeName: hass.translationMetadata.translations[key].nativeName, + const translations = hass.translationMetadata.translations; + return Object.keys(translations).map((key) => ({ + key, + ...translations[key], })); }