diff --git a/src/data/weather.ts b/src/data/weather.ts index 9e66ada7f34e..b23bfdd85d80 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -36,7 +36,9 @@ export const enum WeatherEntityFeature { FORECAST_TWICE_DAILY = 4, } -export type ForecastType = "legacy" | "hourly" | "daily" | "twice_daily"; +export type ModernForecastType = "hourly" | "daily" | "twice_daily"; + +export type ForecastType = ModernForecastType | "legacy"; interface ForecastAttribute { temperature: number; @@ -636,7 +638,7 @@ export const getForecast = ( export const subscribeForecast = ( hass: HomeAssistant, entity_id: string, - forecast_type: "daily" | "hourly" | "twice_daily", + forecast_type: ModernForecastType, callback: (forecastevent: ForecastEvent) => void ) => hass.connection.subscribeMessage(callback, { @@ -645,6 +647,22 @@ export const subscribeForecast = ( entity_id, }); +export const getSupportedForecastTypes = ( + stateObj: HassEntityBase +): ModernForecastType[] => { + const supported: ModernForecastType[] = []; + if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_DAILY)) { + supported.push("daily"); + } + if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_TWICE_DAILY)) { + supported.push("twice_daily"); + } + if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_HOURLY)) { + supported.push("hourly"); + } + return supported; +}; + export const getDefaultForecastType = (stateObj: HassEntityBase) => { if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_DAILY)) { return "daily"; diff --git a/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts b/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts index 0a66aabcf674..2bf8a5b44b40 100644 --- a/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts +++ b/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts @@ -1,6 +1,4 @@ import "@material/mwc-button"; -import "@material/mwc-tab-bar/mwc-tab-bar"; -import "@material/mwc-tab/mwc-tab"; import { mdiEyedropper } from "@mdi/js"; import { css, diff --git a/src/dialogs/more-info/controls/more-info-weather.ts b/src/dialogs/more-info/controls/more-info-weather.ts index 123d3ca4de30..5da649ae4f0e 100644 --- a/src/dialogs/more-info/controls/more-info-weather.ts +++ b/src/dialogs/more-info/controls/more-info-weather.ts @@ -1,3 +1,5 @@ +import "@material/mwc-tab"; +import "@material/mwc-tab-bar"; import { mdiEye, mdiGauge, @@ -14,14 +16,17 @@ import { nothing, } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { formatDateWeekdayDay } from "../../../common/datetime/format_date"; import { formatTimeWeekday } from "../../../common/datetime/format_time"; import "../../../components/ha-svg-icon"; import { ForecastEvent, + ModernForecastType, WeatherEntity, getDefaultForecastType, getForecast, + getSupportedForecastTypes, getWind, subscribeForecast, weatherIcons, @@ -36,6 +41,8 @@ class MoreInfoWeather extends LitElement { @state() private _forecastEvent?: ForecastEvent; + @state() private _forecastType?: ModernForecastType; + @state() private _subscribed?: Promise<() => void>; private _unsubscribeForecastEvents() { @@ -43,25 +50,28 @@ class MoreInfoWeather extends LitElement { this._subscribed.then((unsub) => unsub()); this._subscribed = undefined; } + this._forecastEvent = undefined; } private async _subscribeForecastEvents() { this._unsubscribeForecastEvents(); - if (!this.isConnected || !this.hass || !this.stateObj) { + if ( + !this.isConnected || + !this.hass || + !this.stateObj || + !this._forecastType + ) { return; } - const forecastType = getDefaultForecastType(this.stateObj); - if (forecastType) { - this._subscribed = subscribeForecast( - this.hass!, - this.stateObj!.entity_id, - forecastType, - (event) => { - this._forecastEvent = event; - } - ); - } + this._subscribed = subscribeForecast( + this.hass!, + this.stateObj!.entity_id, + this._forecastType, + (event) => { + this._forecastEvent = event; + } + ); } public connectedCallback() { @@ -93,10 +103,10 @@ class MoreInfoWeather extends LitElement { return false; } - protected updated(changedProps: PropertyValues): void { - super.updated(changedProps); + protected willUpdate(changedProps: PropertyValues): void { + super.willUpdate(changedProps); - if (changedProps.has("stateObj") || !this._subscribed) { + if ((changedProps.has("stateObj") || !this._subscribed) && this.stateObj) { const oldState = changedProps.get("stateObj") as | WeatherEntity | undefined; @@ -104,16 +114,25 @@ class MoreInfoWeather extends LitElement { oldState?.entity_id !== this.stateObj?.entity_id || !this._subscribed ) { + this._forecastType = getDefaultForecastType(this.stateObj); this._subscribeForecastEvents(); } + } else if (changedProps.has("_forecastType")) { + this._subscribeForecastEvents(); } } + private _supportedForecasts = memoizeOne((stateObj: WeatherEntity) => + getSupportedForecastTypes(stateObj) + ); + protected render() { if (!this.hass || !this.stateObj) { return nothing; } + const supportedForecasts = this._supportedForecasts(this.stateObj); + const forecastData = getForecast( this.stateObj.attributes, this._forecastEvent @@ -210,6 +229,23 @@ class MoreInfoWeather extends LitElement {
${this.hass.localize("ui.card.weather.forecast")}:
+ ${supportedForecasts.length > 1 + ? html` item === this._forecastType + )} + @MDCTabBar:activated=${this._handleForecastTypeChanged} + > + ${supportedForecasts.map( + (forecastType) => + html`` + )} + ` + : nothing} ${forecast.map((item) => this._showValue(item.templow) || this._showValue(item.temperature) ? html`
@@ -283,12 +319,23 @@ class MoreInfoWeather extends LitElement { `; } + private _handleForecastTypeChanged(ev: CustomEvent): void { + this._forecastType = this._supportedForecasts(this.stateObj!)[ + ev.detail.index + ]; + } + static get styles(): CSSResultGroup { return css` ha-svg-icon { color: var(--paper-item-icon-color); margin-left: 8px; } + + mwc-tab-bar { + margin-bottom: 4px; + } + .section { margin: 16px 0 8px 0; font-size: 1.2em; diff --git a/src/dialogs/more-info/ha-more-info-settings.ts b/src/dialogs/more-info/ha-more-info-settings.ts index b3a4c2eed176..2446da780508 100644 --- a/src/dialogs/more-info/ha-more-info-settings.ts +++ b/src/dialogs/more-info/ha-more-info-settings.ts @@ -1,5 +1,3 @@ -import "@material/mwc-tab"; -import "@material/mwc-tab-bar"; import { css, CSSResultGroup, diff --git a/src/panels/config/network/supervisor-hostname.ts b/src/panels/config/network/supervisor-hostname.ts index ac0389626084..5b1eed76bc2c 100644 --- a/src/panels/config/network/supervisor-hostname.ts +++ b/src/panels/config/network/supervisor-hostname.ts @@ -1,8 +1,6 @@ import "@material/mwc-button/mwc-button"; import "@material/mwc-list/mwc-list"; import "@material/mwc-list/mwc-list-item"; -import "@material/mwc-tab"; -import "@material/mwc-tab-bar"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import "../../../components/ha-alert"; diff --git a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts index 500a6a12b972..4df0433bdad5 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -1,5 +1,3 @@ -import "@material/mwc-tab-bar/mwc-tab-bar"; -import "@material/mwc-tab/mwc-tab"; import Fuse from "fuse.js"; import { css, diff --git a/src/translations/en.json b/src/translations/en.json index 03f59207539d..6c5e1e191839 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -261,6 +261,9 @@ "forecast_daily": "Forecast daily", "forecast_hourly": "Forecast hourly", "forecast_twice_daily": "Forecast twice daily", + "daily": "Daily", + "hourly": "Hourly", + "twice_daily": "Twice daily", "high": "High", "low": "Low" }