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,
mdiPodcast,
mdiPower,
mdiRepeat,
mdiRepeatOff,
mdiRepeatOnce,
mdiShuffle,
mdiShuffleDisabled,
mdiSkipNext,
mdiSkipPrevious,
mdiStop,
@ -49,6 +54,8 @@ interface MediaPlayerEntityAttributes extends HassEntityAttributeBase {
entity_picture_local?: string;
is_volume_muted?: boolean;
volume_level?: number;
repeat?: string;
shuffle?: boolean;
source?: string;
source_list?: string[];
sound_mode?: string;
@ -80,7 +87,9 @@ export const SUPPORT_VOLUME_BUTTONS = 1024;
export const SUPPORT_SELECT_SOURCE = 2048;
export const SUPPORT_STOP = 4096;
export const SUPPORT_PLAY = 16384;
export const SUPPORT_REPEAT_SET = 262144;
export const SUPPORT_SELECT_SOUND_MODE = 65536;
export const SUPPORT_SHUFFLE_SET = 32768;
export const SUPPORT_BROWSE_MEDIA = 131072;
export type MediaPlayerBrowseAction = "pick" | "play";
@ -233,7 +242,8 @@ export const computeMediaDescription = (
};
export const computeMediaControls = (
stateObj: MediaPlayerEntity
stateObj: MediaPlayerEntity,
useExtendedControls = false
): ControlButton[] | undefined => {
if (!stateObj) {
return undefined;
@ -266,6 +276,18 @@ export const computeMediaControls = (
}
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 (
(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;
};
@ -375,3 +413,31 @@ export const setMediaPlayerVolume = (
volume_level: number
) =>
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 {
computeMediaControls,
handleMediaControlClick,
MediaPickedEvent,
MediaPlayerEntity,
SUPPORT_BROWSE_MEDIA,
@ -47,7 +48,7 @@ class MoreInfoMediaPlayer extends LitElement {
}
const stateObj = this.stateObj;
const controls = computeMediaControls(stateObj);
const controls = computeMediaControls(stateObj, true);
return html`
<div class="controls">
@ -202,6 +203,7 @@ class MoreInfoMediaPlayer extends LitElement {
}
.basic-controls {
display: inline-flex;
flex-grow: 1;
}
@ -231,12 +233,10 @@ class MoreInfoMediaPlayer extends LitElement {
}
private _handleClick(e: MouseEvent): void {
this.hass!.callService(
"media_player",
(e.currentTarget! as HTMLElement).getAttribute("action")!,
{
entity_id: this.stateObj!.entity_id,
}
handleMediaControlClick(
this.hass!,
this.stateObj!,
(e.currentTarget as HTMLElement).getAttribute("action")!
);
}

View File

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

View File

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

View File

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