mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-24 21:37:21 +00:00
Add shuffle and repeat-mode of media_player to UI (#12052)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
9444228907
commit
b5861869e3
@ -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,
|
||||
}
|
||||
);
|
||||
|
@ -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")!
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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") {
|
||||
|
@ -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"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user