From daad46af058650393aea2d666707820ac02b13e6 Mon Sep 17 00:00:00 2001 From: Johan Frick Date: Sat, 24 Feb 2024 10:13:08 +0100 Subject: [PATCH] feature: use apply button for predefined groups as well --- src/sections/grouping.ts | 95 ++++++++++++++++++--------- src/services/media-control-service.ts | 35 +--------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/sections/grouping.ts b/src/sections/grouping.ts index e3334e01..78fe9327 100755 --- a/src/sections/grouping.ts +++ b/src/sections/grouping.ts @@ -7,13 +7,13 @@ import { dispatchActivePlayerId } from '../utils/utils'; import { listStyle } from '../constants'; import { MediaPlayer } from '../model/media-player'; import '../components/grouping-button'; +import { PredefinedGroup, PredefinedGroupPlayer } from '../types'; export class Grouping extends LitElement { @property({ attribute: false }) store!: Store; private groupingItems!: GroupingItem[]; private activePlayer!: MediaPlayer; private mediaControlService!: MediaControlService; - private allGroups!: MediaPlayer[]; private mediaPlayerIds!: string[]; private notJoinedPlayers!: string[]; private joinedPlayers!: string[]; @@ -21,7 +21,6 @@ export class Grouping extends LitElement { render() { this.activePlayer = this.store.activePlayer; - this.allGroups = this.store.allGroups; this.mediaControlService = this.store.mediaControlService; this.mediaPlayerIds = this.store.allMediaPlayers.map((player) => player.id); this.groupingItems = this.getGroupingItems(); @@ -42,7 +41,7 @@ export class Grouping extends LitElement { class="icon" selected=${item.isSelected || nothing} .icon="mdi:${item.icon}" - @click=${() => this.itemClick(item)} + @click=${() => this.toggleItem(item)} >
${item.name} @@ -145,19 +144,24 @@ export class Grouping extends LitElement { ]; } - itemClick(item: GroupingItem) { + toggleItem(item: GroupingItem) { if (item.isDisabled) { return; } + this.toggleItemWithoutDisabledCheck(item); + } + + private toggleItemWithoutDisabledCheck(item: GroupingItem) { if (this.modifiedItems.includes(item.player.id)) { this.modifiedItems = this.modifiedItems.filter((id) => id !== item.player.id); } else { this.modifiedItems = [...this.modifiedItems, item.player.id]; } } + async applyGrouping() { const isSelected = this.groupingItems.filter((item) => item.isSelected); - const unjoin = this.groupingItems + const unJoin = this.groupingItems .filter((item) => !item.isSelected && this.joinedPlayers.includes(item.player.id)) .map((item) => item.player.id); const join = this.groupingItems @@ -165,20 +169,33 @@ export class Grouping extends LitElement { .map((item) => item.player.id); let main = this.activePlayer.id; - if (unjoin.includes(this.activePlayer.id)) { - main = isSelected[0].player.id; - dispatchActivePlayerId(main, this.store.config, this); - } - if (unjoin.length > 0) { - await this.mediaControlService.unJoin(unjoin); + if (unJoin.length > 0) { + await this.mediaControlService.unJoin(unJoin); } if (join.length > 0) { await this.mediaControlService.join(main, join); } + await this.handlePredefinedGroupConfig(isSelected); + if (unJoin.includes(this.activePlayer.id)) { + main = isSelected[0].player.id; + dispatchActivePlayerId(main, this.store.config, this); + } this.modifiedItems = []; } + private async handlePredefinedGroupConfig(isSelected: GroupingItem[]) { + const predefinedGroup = this.store.predefinedGroups.find((pg) => { + return ( + pg.entities.length === isSelected.length && + pg.entities.every((pgp) => isSelected.some((s) => s.player.id === pgp.player.id)) + ); + }); + if (predefinedGroup) { + await this.mediaControlService.setVolumeAndMediaForPredefinedGroup(predefinedGroup); + } + } + private cancelGrouping() { this.groupingItems = this.getGroupingItems(); } @@ -196,14 +213,13 @@ export class Grouping extends LitElement { } private renderJoinAllButton() { - return when(this.notJoinedPlayers.length, () => { - return html` - await this.mediaControlService.join(this.activePlayer.id, this.notJoinedPlayers)} - .icon=${'mdi:checkbox-multiple-marked-outline'} - > - `; - }); + return when(this.notJoinedPlayers.length, () => + this.groupingButton('mdi:checkbox-multiple-marked-outline', this.selectAll), + ); + } + + private groupingButton(icon: string, click: () => void) { + return html` `; } private getNotJoinedPlayers() { @@ -213,14 +229,9 @@ export class Grouping extends LitElement { } private renderUnJoinAllButton() { - return when(this.joinedPlayers.length, () => { - return html` - await this.mediaControlService.unJoin(this.joinedPlayers)} - .icon=${'mdi:minus-box-multiple-outline'} - > - `; - }); + return when(this.joinedPlayers.length, () => + this.groupingButton('mdi:minus-box-multiple-outline', this.deSelectAll), + ); } private getJoinedPlayers() { @@ -233,16 +244,38 @@ export class Grouping extends LitElement { return this.store.predefinedGroups.map((predefinedGroup) => { return html` { - this.modifiedItems = []; - await this.mediaControlService.createGroup(predefinedGroup, this.allGroups, this); - }} + @click=${async () => this.selectPredefinedGroup(predefinedGroup)} .icon=${'mdi:speaker-multiple'} .name=${predefinedGroup.name} > `; }); } + + private selectPredefinedGroup(predefinedGroup: PredefinedGroup) { + this.groupingItems.forEach((item) => { + const inPG = predefinedGroup.entities.some((pgp) => pgp.player.id === item.player.id); + if ((inPG && !item.isSelected) || (!inPG && item.isSelected)) { + this.toggleItemWithoutDisabledCheck(item); + } + }); + } + + private selectAll() { + this.groupingItems.forEach((item) => { + if (!item.isSelected) { + this.toggleItem(item); + } + }); + } + + private deSelectAll() { + this.groupingItems.forEach((item) => { + if ((!item.isMain && item.isSelected) || (item.isMain && !item.isSelected)) { + this.toggleItem(item); + } + }); + } } class GroupingItem { diff --git a/src/services/media-control-service.ts b/src/services/media-control-service.ts index 06088867..3c24663c 100644 --- a/src/services/media-control-service.ts +++ b/src/services/media-control-service.ts @@ -1,6 +1,5 @@ import { CardConfig, MediaPlayerItem, PredefinedGroup } from '../types'; import HassService from './hass-service'; -import { dispatchActivePlayerId } from '../utils/utils'; import { MediaPlayer } from '../model/media-player'; export default class MediaControlService { @@ -19,45 +18,13 @@ export default class MediaControlService { }); } - private async joinPredefinedGroup(player: MediaPlayer, pg: PredefinedGroup) { - const ids = pg.entities.map(({ player }) => player.id); - await this.join(player.id, ids); - } - async unJoin(playerIds: string[]) { await this.hassService.callMediaService('unjoin', { entity_id: playerIds, }); } - async createGroup(predefinedGroup: PredefinedGroup, currentGroups: MediaPlayer[], element: Element) { - let candidateGroup!: MediaPlayer; - for (const group of currentGroups) { - if (predefinedGroup.entities.some((item) => item.player.id === group.id)) { - if (group.isPlaying()) { - await this.modifyExistingGroup(group, predefinedGroup, element); - return; - } - candidateGroup = candidateGroup || group; - } - } - if (candidateGroup) { - await this.modifyExistingGroup(candidateGroup, predefinedGroup, element); - } else { - const { player } = predefinedGroup.entities[0]; - dispatchActivePlayerId(player.id, this.config, element); - await this.joinPredefinedGroup(player, predefinedGroup); - } - } - - private async modifyExistingGroup(group: MediaPlayer, pg: PredefinedGroup, element: Element) { - const members = group.members; - const membersNotToBeGrouped = members.filter((member) => !pg.entities.some((item) => item.player.id === member.id)); - if (membersNotToBeGrouped?.length) { - await this.unJoin(membersNotToBeGrouped.map((member) => member.id)); - } - dispatchActivePlayerId(group.id, this.config, element); - await this.joinPredefinedGroup(group, pg); + async setVolumeAndMediaForPredefinedGroup(pg: PredefinedGroup) { for (const pgp of pg.entities) { const volume = pgp.volume ?? pg.volume; if (volume) {