diff --git a/src/components/media-player/dialog-media-player-browse.ts b/src/components/media-player/dialog-media-player-browse.ts index a67bf5366a..47df56ca4c 100644 --- a/src/components/media-player/dialog-media-player-browse.ts +++ b/src/components/media-player/dialog-media-player-browse.ts @@ -1,11 +1,20 @@ -import { mdiArrowLeft, mdiClose } from "@mdi/js"; -import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; +import { ActionDetail } from "@material/mwc-list"; +import { + mdiAlphaABoxOutline, + mdiArrowLeft, + mdiClose, + mdiDotsVertical, + mdiGrid, + mdiListBoxOutline, +} from "@mdi/js"; +import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property, query, state } from "lit/decorators"; -import { fireEvent, HASSDomEvent } from "../../common/dom/fire_event"; +import { HASSDomEvent, fireEvent } from "../../common/dom/fire_event"; import type { MediaPickedEvent, MediaPlayerBrowseAction, MediaPlayerItem, + MediaPlayerLayoutType, } from "../../data/media-player"; import { haStyleDialog } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; @@ -18,6 +27,7 @@ import type { MediaPlayerItemId, } from "./ha-media-player-browse"; import { MediaPlayerBrowseDialogParams } from "./show-media-browser-dialog"; +import { stopPropagation } from "../../common/dom/stop_propagation"; @customElement("dialog-media-player-browse") class DialogMediaPlayerBrowse extends LitElement { @@ -29,6 +39,8 @@ class DialogMediaPlayerBrowse extends LitElement { @state() private _params?: MediaPlayerBrowseDialogParams; + @state() _preferredLayout: MediaPlayerLayoutType = "auto"; + @query("ha-media-player-browse") private _browser!: HaMediaPlayerBrowse; public showDialog(params: MediaPlayerBrowseDialogParams): void { @@ -45,6 +57,7 @@ class DialogMediaPlayerBrowse extends LitElement { this._params = undefined; this._navigateIds = undefined; this._currentItem = undefined; + this._preferredLayout = "auto"; fireEvent(this, "dialog-closed", { dialog: this.localName }); } @@ -84,13 +97,54 @@ class DialogMediaPlayerBrowse extends LitElement { ) : this._currentItem.title} - + + + + ${this.hass.localize("ui.components.media-browser.auto")} + + + + ${this.hass.localize("ui.components.media-browser.grid")} + + + + ${this.hass.localize("ui.components.media-browser.list")} + + + ) { + switch (ev.detail.index) { + case 0: + this._preferredLayout = "auto"; + break; + case 1: + this._preferredLayout = "grid"; + break; + case 2: + this._preferredLayout = "list"; + break; + } + } + private _goBack() { this._navigateIds = this._navigateIds?.slice(0, -1); this._currentItem = undefined; diff --git a/src/components/media-player/ha-media-player-browse.ts b/src/components/media-player/ha-media-player-browse.ts index de52e29bf8..916ff13ed4 100644 --- a/src/components/media-player/ha-media-player-browse.ts +++ b/src/components/media-player/ha-media-player-browse.ts @@ -35,6 +35,7 @@ import { MediaClassBrowserSettings, MediaPickedEvent, MediaPlayerBrowseAction, + MediaPlayerLayoutType, } from "../../data/media-player"; import { browseLocalMediaPlayer } from "../../data/media_source"; import { isTTSMediaSource } from "../../data/tts"; @@ -87,6 +88,8 @@ export class HaMediaPlayerBrowse extends LitElement { @property() public action: MediaPlayerBrowseAction = "play"; + @property() public preferredLayout: MediaPlayerLayoutType = "auto"; + @property({ type: Boolean }) public dialog = false; @property() public navigateIds!: MediaPlayerItemId[]; @@ -477,7 +480,9 @@ export class HaMediaPlayerBrowse extends LitElement { )} ` - : childrenMediaClass.layout === "grid" + : this.preferredLayout === "grid" || + (this.preferredLayout === "auto" && + childrenMediaClass.layout === "grid") ? html` ` @@ -634,26 +640,37 @@ export class HaMediaPlayerBrowse extends LitElement { .graphic=${mediaClass.show_list_images ? "medium" : "avatar"} dir=${computeRTLDirection(this.hass)} > -
- -
+ ${backgroundImage === "none" && !child.can_play + ? html`` + : html`
+ ${child.can_play + ? html`` + : nothing} +
`} ${child.title} `; @@ -899,7 +916,6 @@ export class HaMediaPlayerBrowse extends LitElement { overflow-y: auto; box-sizing: border-box; height: 100%; - position: relative; } /* HEADER */ @@ -913,7 +929,7 @@ export class HaMediaPlayerBrowse extends LitElement { top: 0; right: 0; left: 0; - z-index: 5; + z-index: 3; padding: 16px; } .header_button { @@ -1154,6 +1170,8 @@ export class HaMediaPlayerBrowse extends LitElement { mwc-list-item .graphic { background-size: contain; + background-repeat: no-repeat; + background-position: center; border-radius: 2px; display: flex; align-content: center; diff --git a/src/data/media-player.ts b/src/data/media-player.ts index 65f34dba53..deccb121dd 100644 --- a/src/data/media-player.ts +++ b/src/data/media-player.ts @@ -106,6 +106,8 @@ export type MediaPlayerBrowseAction = "pick" | "play"; export const BROWSER_PLAYER = "browser"; +export type MediaPlayerLayoutType = "grid" | "list" | "auto"; + export type MediaClassBrowserSetting = { icon: string; thumbnail_ratio?: string; @@ -117,12 +119,13 @@ export const MediaClassBrowserSettings: { [type: string]: MediaClassBrowserSetting; } = { album: { icon: mdiAlbum, layout: "grid" }, - app: { icon: mdiApplication, layout: "grid" }, + app: { icon: mdiApplication, layout: "grid", show_list_images: true }, artist: { icon: mdiAccountMusic, layout: "grid", show_list_images: true }, channel: { icon: mdiTelevisionClassic, thumbnail_ratio: "portrait", layout: "grid", + show_list_images: true, }, composer: { icon: mdiAccountMusicOutline, @@ -139,6 +142,7 @@ export const MediaClassBrowserSettings: { icon: mdiTelevisionClassic, layout: "grid", thumbnail_ratio: "portrait", + show_list_images: true, }, game: { icon: mdiGamepadVariant, @@ -146,15 +150,21 @@ export const MediaClassBrowserSettings: { thumbnail_ratio: "portrait", }, genre: { icon: mdiDramaMasks, layout: "grid", show_list_images: true }, - image: { icon: mdiImage, layout: "grid" }, - movie: { icon: mdiMovie, thumbnail_ratio: "portrait", layout: "grid" }, - music: { icon: mdiMusic }, + image: { icon: mdiImage, layout: "grid", show_list_images: true }, + movie: { + icon: mdiMovie, + thumbnail_ratio: "portrait", + layout: "grid", + show_list_images: true, + }, + music: { icon: mdiMusic, show_list_images: true }, playlist: { icon: mdiPlaylistMusic, layout: "grid", show_list_images: true }, podcast: { icon: mdiPodcast, layout: "grid" }, season: { icon: mdiTelevisionClassic, layout: "grid", thumbnail_ratio: "portrait", + show_list_images: true, }, track: { icon: mdiFileMusic }, tv_show: { @@ -163,7 +173,7 @@ export const MediaClassBrowserSettings: { thumbnail_ratio: "portrait", }, url: { icon: mdiWeb }, - video: { icon: mdiVideo, layout: "grid" }, + video: { icon: mdiVideo, layout: "grid", show_list_images: true }, }; export interface MediaPickedEvent { diff --git a/src/panels/media-browser/ha-panel-media-browser.ts b/src/panels/media-browser/ha-panel-media-browser.ts index 986cb57c22..56bca1c6bf 100644 --- a/src/panels/media-browser/ha-panel-media-browser.ts +++ b/src/panels/media-browser/ha-panel-media-browser.ts @@ -1,4 +1,11 @@ -import { mdiArrowLeft } from "@mdi/js"; +import { + mdiGrid, + mdiListBoxOutline, + mdiArrowLeft, + mdiAlphaABoxOutline, + mdiDotsVertical, +} from "@mdi/js"; +import { ActionDetail } from "@material/mwc-list"; import "@material/mwc-button"; import { css, @@ -26,6 +33,7 @@ import { MediaPickedEvent, MediaPlayerItem, mediaPlayerPlayMedia, + MediaPlayerLayoutType, } from "../../data/media-player"; import { ResolvedMediaSource, @@ -64,6 +72,8 @@ class PanelMediaBrowser extends LitElement { @state() _currentItem?: MediaPlayerItem; + @state() _preferredLayout: MediaPlayerLayoutType = "auto"; + private _navigateIds: MediaPlayerItemId[] = [ { media_content_id: undefined, @@ -113,10 +123,48 @@ class PanelMediaBrowser extends LitElement { .currentItem=${this._currentItem} @media-refresh=${this._refreshMedia} > + + + + ${this.hass.localize("ui.components.media-browser.auto")} + + + + ${this.hass.localize("ui.components.media-browser.grid")} + + + + ${this.hass.localize("ui.components.media-browser.list")} + + + @@ -130,6 +178,20 @@ class PanelMediaBrowser extends LitElement { `; } + private async _handleMenuAction(ev: CustomEvent) { + switch (ev.detail.index) { + case 0: + this._preferredLayout = "auto"; + break; + case 1: + this._preferredLayout = "grid"; + break; + case 2: + this._preferredLayout = "list"; + break; + } + } + public willUpdate(changedProps: PropertyValues): void { super.willUpdate(changedProps); @@ -288,6 +350,9 @@ class PanelMediaBrowser extends LitElement { :host([narrow]) ha-media-player-browse { height: calc(100vh - (57px + var(--header-height))); } + .selected_menu_item { + color: var(--primary-color); + } ha-bar-media-player { position: fixed; diff --git a/src/translations/en.json b/src/translations/en.json index 17e01be2ab..95601f7fc2 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -703,7 +703,10 @@ "url": "URL", "video": "Video" }, - "media_player_unavailable": "The selected media player is unavailable." + "media_player_unavailable": "The selected media player is unavailable.", + "auto": "Auto", + "grid": "Grid", + "list": "List" }, "calendar": { "label": "Calendar",