mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-26 06:17:20 +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,
|
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,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
@ -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,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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") {
|
||||||
|
@ -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"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user