Add shuffle and repeat-mode of media_player to UI (#12052)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
NachtaktiverHalbaffe 2022-03-30 19:16:27 +02:00 committed by GitHub
parent 9444228907
commit b5861869e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 17 deletions

View File

@ -16,6 +16,11 @@ import {
mdiPlayPause, mdiPlayPause,
mdiPodcast, mdiPodcast,
mdiPower, mdiPower,
mdiRepeat,
mdiRepeatOff,
mdiRepeatOnce,
mdiShuffle,
mdiShuffleDisabled,
mdiSkipNext, mdiSkipNext,
mdiSkipPrevious, mdiSkipPrevious,
mdiStop, mdiStop,
@ -49,6 +54,8 @@ interface MediaPlayerEntityAttributes extends HassEntityAttributeBase {
entity_picture_local?: string; entity_picture_local?: string;
is_volume_muted?: boolean; is_volume_muted?: boolean;
volume_level?: number; volume_level?: number;
repeat?: string;
shuffle?: boolean;
source?: string; source?: string;
source_list?: string[]; source_list?: string[];
sound_mode?: string; sound_mode?: string;
@ -80,7 +87,9 @@ export const SUPPORT_VOLUME_BUTTONS = 1024;
export const SUPPORT_SELECT_SOURCE = 2048; export const SUPPORT_SELECT_SOURCE = 2048;
export const SUPPORT_STOP = 4096; export const SUPPORT_STOP = 4096;
export const SUPPORT_PLAY = 16384; export const SUPPORT_PLAY = 16384;
export const SUPPORT_REPEAT_SET = 262144;
export const SUPPORT_SELECT_SOUND_MODE = 65536; export const SUPPORT_SELECT_SOUND_MODE = 65536;
export const SUPPORT_SHUFFLE_SET = 32768;
export const SUPPORT_BROWSE_MEDIA = 131072; export const SUPPORT_BROWSE_MEDIA = 131072;
export type MediaPlayerBrowseAction = "pick" | "play"; export type MediaPlayerBrowseAction = "pick" | "play";
@ -233,7 +242,8 @@ export const computeMediaDescription = (
}; };
export const computeMediaControls = ( export const computeMediaControls = (
stateObj: MediaPlayerEntity stateObj: MediaPlayerEntity,
useExtendedControls = false
): ControlButton[] | undefined => { ): ControlButton[] | undefined => {
if (!stateObj) { if (!stateObj) {
return undefined; return undefined;
@ -266,6 +276,18 @@ export const computeMediaControls = (
} }
const assumedState = stateObj.attributes.assumed_state === true; const assumedState = stateObj.attributes.assumed_state === true;
const stateAttr = stateObj.attributes;
if (
(state === "playing" || state === "paused" || assumedState) &&
supportsFeature(stateObj, SUPPORT_SHUFFLE_SET) &&
useExtendedControls
) {
buttons.push({
icon: stateAttr.shuffle === true ? mdiShuffle : mdiShuffleDisabled,
action: "shuffle_set",
});
}
if ( if (
(state === "playing" || state === "paused" || assumedState) && (state === "playing" || state === "paused" || assumedState) &&
@ -337,6 +359,22 @@ export const computeMediaControls = (
}); });
} }
if (
(state === "playing" || state === "paused" || assumedState) &&
supportsFeature(stateObj, SUPPORT_REPEAT_SET) &&
useExtendedControls
) {
buttons.push({
icon:
stateAttr.repeat === "all"
? mdiRepeat
: stateAttr.repeat === "one"
? mdiRepeatOnce
: mdiRepeatOff,
action: "repeat_set",
});
}
return buttons.length > 0 ? buttons : undefined; return buttons.length > 0 ? buttons : undefined;
}; };
@ -375,3 +413,31 @@ export const setMediaPlayerVolume = (
volume_level: number volume_level: number
) => ) =>
hass.callService("media_player", "volume_set", { entity_id, volume_level }); hass.callService("media_player", "volume_set", { entity_id, volume_level });
export const handleMediaControlClick = (
hass: HomeAssistant,
stateObj: MediaPlayerEntity,
action: string
) =>
hass!.callService(
"media_player",
action,
action === "shuffle_set"
? {
entity_id: stateObj!.entity_id,
shuffle: !stateObj!.attributes.shuffle,
}
: action === "repeat_set"
? {
entity_id: stateObj!.entity_id,
repeat:
stateObj!.attributes.repeat === "all"
? "one"
: stateObj!.attributes.repeat === "off"
? "all"
: "off",
}
: {
entity_id: stateObj!.entity_id,
}
);

View File

@ -23,6 +23,7 @@ import { showMediaBrowserDialog } from "../../../components/media-player/show-me
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity"; import { UNAVAILABLE, UNKNOWN } from "../../../data/entity";
import { import {
computeMediaControls, computeMediaControls,
handleMediaControlClick,
MediaPickedEvent, MediaPickedEvent,
MediaPlayerEntity, MediaPlayerEntity,
SUPPORT_BROWSE_MEDIA, SUPPORT_BROWSE_MEDIA,
@ -47,7 +48,7 @@ class MoreInfoMediaPlayer extends LitElement {
} }
const stateObj = this.stateObj; const stateObj = this.stateObj;
const controls = computeMediaControls(stateObj); const controls = computeMediaControls(stateObj, true);
return html` return html`
<div class="controls"> <div class="controls">
@ -202,6 +203,7 @@ class MoreInfoMediaPlayer extends LitElement {
} }
.basic-controls { .basic-controls {
display: inline-flex;
flex-grow: 1; flex-grow: 1;
} }
@ -231,12 +233,10 @@ class MoreInfoMediaPlayer extends LitElement {
} }
private _handleClick(e: MouseEvent): void { private _handleClick(e: MouseEvent): void {
this.hass!.callService( handleMediaControlClick(
"media_player", this.hass!,
(e.currentTarget! as HTMLElement).getAttribute("action")!, this.stateObj!,
{ (e.currentTarget as HTMLElement).getAttribute("action")!
entity_id: this.stateObj!.entity_id,
}
); );
} }

View File

@ -28,6 +28,7 @@ import {
computeMediaControls, computeMediaControls,
computeMediaDescription, computeMediaDescription,
getCurrentProgress, getCurrentProgress,
handleMediaControlClick,
MediaPickedEvent, MediaPickedEvent,
MediaPlayerEntity, MediaPlayerEntity,
SUPPORT_BROWSE_MEDIA, SUPPORT_BROWSE_MEDIA,
@ -174,7 +175,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
UNAVAILABLE_STATES.includes(entityState) || UNAVAILABLE_STATES.includes(entityState) ||
(entityState === "off" && !supportsFeature(stateObj, SUPPORT_TURN_ON)); (entityState === "off" && !supportsFeature(stateObj, SUPPORT_TURN_ON));
const hasNoImage = !this._image; const hasNoImage = !this._image;
const controls = computeMediaControls(stateObj); const controls = computeMediaControls(stateObj, false);
const showControls = const showControls =
controls && controls &&
(!this._veryNarrow || (!this._veryNarrow ||
@ -504,10 +505,11 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
} }
private _handleClick(e: MouseEvent): void { private _handleClick(e: MouseEvent): void {
const action = (e.currentTarget! as HTMLElement).getAttribute("action")!; handleMediaControlClick(
this.hass!.callService("media_player", action, { this.hass!,
entity_id: this._config!.entity, this._stateObj!,
}); (e.currentTarget as HTMLElement).getAttribute("action")!
);
} }
private _updateProgressBar(): void { private _updateProgressBar(): void {

View File

@ -39,6 +39,7 @@ import {
computeMediaDescription, computeMediaDescription,
formatMediaTime, formatMediaTime,
getCurrentProgress, getCurrentProgress,
handleMediaControlClick,
MediaPlayerEntity, MediaPlayerEntity,
MediaPlayerItem, MediaPlayerItem,
setMediaPlayerVolume, setMediaPlayerVolume,
@ -173,7 +174,7 @@ export class BarMediaPlayer extends LitElement {
} }
const controls = !this.narrow const controls = !this.narrow
? computeMediaControls(stateObj) ? computeMediaControls(stateObj, true)
: (stateObj.state === "playing" && : (stateObj.state === "playing" &&
(supportsFeature(stateObj, SUPPORT_PAUSE) || (supportsFeature(stateObj, SUPPORT_PAUSE) ||
supportsFeature(stateObj, SUPPORT_STOP))) || supportsFeature(stateObj, SUPPORT_STOP))) ||
@ -490,9 +491,11 @@ export class BarMediaPlayer extends LitElement {
const action = (e.currentTarget! as HTMLElement).getAttribute("action")!; const action = (e.currentTarget! as HTMLElement).getAttribute("action")!;
if (!this._browserPlayer) { if (!this._browserPlayer) {
this.hass!.callService("media_player", action, { handleMediaControlClick(
entity_id: this.entityId, this.hass!,
}); this._stateObj!,
(e.currentTarget as HTMLElement).getAttribute("action")!
);
return; return;
} }
if (action === "media_pause") { if (action === "media_pause") {

View File

@ -211,6 +211,8 @@
"media_volume_down": "Volume down", "media_volume_down": "Volume down",
"media_volume_mute": "Volume mute", "media_volume_mute": "Volume mute",
"media_volume_unmute": "Volume unmute", "media_volume_unmute": "Volume unmute",
"repeat_set": "Repeat mode",
"shuffle_set": "Shuffle",
"text_to_speak": "Text to speak", "text_to_speak": "Text to speak",
"nothing_playing": "Nothing Playing" "nothing_playing": "Nothing Playing"
}, },