Skip to content

Commit

Permalink
Add grid support to vacuum card
Browse files Browse the repository at this point in the history
  • Loading branch information
piitaya committed Mar 5, 2024
1 parent 3e2155c commit 64365b2
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 106 deletions.
40 changes: 8 additions & 32 deletions src/cards/climate-card/climate-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ registerCustomCard({
});

@customElement(CLIMATE_CARD_NAME)
export class ClimateCard extends MushroomBaseCard implements LovelaceCard {
export class ClimateCard extends MushroomBaseCard<ClimateCardConfig> implements LovelaceCard {
public static async getConfigElement(): Promise<LovelaceCardEditor> {
await import("./climate-card-editor");
return document.createElement(CLIMATE_CARD_EDITOR_NAME) as LovelaceCardEditor;
Expand All @@ -66,12 +66,8 @@ export class ClimateCard extends MushroomBaseCard implements LovelaceCard {
};
}

@state() private _config?: ClimateCardConfig;

@state() private _activeControl?: ClimateCardControl;

@state() private _inGrid = false;

private get _controls(): ClimateCardControl[] {
if (!this._config || !this.hass || !this._config.entity) return [];

Expand All @@ -89,31 +85,16 @@ export class ClimateCard extends MushroomBaseCard implements LovelaceCard {
return controls;
}

public getCardSize(): number | Promise<number> {
return 1;
}

public getGridSize(): [number, number] {
this._inGrid = true;
let column = 2;
let row = 1;
if (!this._config) return [column, row];

const appearance = computeAppearance(this._config);
if (appearance.layout === "vertical") {
row += 1;
}
if (appearance.layout === "horizontal") {
column = 4;
}
const size = super.getGridSize();
if (
this._controls.length &&
!this._config?.collapsible_controls &&
appearance.layout !== "horizontal"
this._appearance?.layout !== "horizontal"
) {
row += 1;
size[1] += 1;
}
return [column, row];
return size;
}

_onControlTap(ctrl, e): void {
Expand All @@ -122,15 +103,15 @@ export class ClimateCard extends MushroomBaseCard implements LovelaceCard {
}

setConfig(config: ClimateCardConfig): void {
this._config = {
super.setConfig({
tap_action: {
action: "toggle",
},
hold_action: {
action: "more-info",
},
...config,
};
});
this.updateActiveControl();
}

Expand Down Expand Up @@ -192,12 +173,7 @@ export class ClimateCard extends MushroomBaseCard implements LovelaceCard {
(!this._config.collapsible_controls || isActive(stateObj)) && this._controls.length;

return html`
<ha-card
class=${classMap({
"fill-container": appearance.fill_container,
"in-grid": this._inGrid,
})}
>
<ha-card class=${classMap({ "fill-container": appearance.fill_container })}>
<mushroom-card .appearance=${appearance} ?rtl=${rtl}>
<mushroom-state-item
?rtl=${rtl}
Expand Down
11 changes: 2 additions & 9 deletions src/cards/light-card/light-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,10 @@ export class LightCard extends MushroomBaseCard<LightCardConfig> implements Love

public getGridSize(): [number, number] {
const size = super.getGridSize();
if (!this._config) return size;
const appearance = computeAppearance(this._config);
if (
this._controls.length &&
!this._config?.collapsible_controls &&
appearance.layout !== "horizontal"
this._appearance?.layout !== "horizontal"
) {
size[1] += 1;
}
Expand Down Expand Up @@ -203,12 +201,7 @@ export class LightCard extends MushroomBaseCard<LightCardConfig> implements Love
(!this._config.collapsible_controls || isActive(stateObj)) && this._controls.length;

return html`
<ha-card
class=${classMap({
"fill-container": appearance.fill_container,
"in-grid": this._inGrid,
})}
>
<ha-card class=${classMap({ "fill-container": appearance.fill_container })}>
<mushroom-card .appearance=${appearance} ?rtl=${rtl}>
<mushroom-state-item
?rtl=${rtl}
Expand Down
23 changes: 0 additions & 23 deletions src/cards/media-player-card/media-player-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,29 +99,6 @@ export class MediaPlayerCard extends MushroomBaseCard implements LovelaceCard {
return 1;
}

public getGridSize(): [number, number] {
this._inGrid = true;
let column = 2;
let row = 1;
if (!this._config) return [column, row];

const appearance = computeAppearance(this._config);
if (appearance.layout === "vertical") {
row += 1;
}
if (appearance.layout === "horizontal") {
column = 4;
}
if (
this._controls.length &&
!this._config?.collapsible_controls &&
appearance.layout !== "horizontal"
) {
row += 1;
}
return [column, row];
}

_onControlTap(ctrl, e): void {
e.stopPropagation();
this._activeControl = ctrl;
Expand Down
76 changes: 46 additions & 30 deletions src/cards/vacuum-card/controls/vacuum-commands-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,88 +22,102 @@ import { VacuumCommand } from "../vacuum-card-config";
interface VacuumButton {
icon: string;
serviceName: string;
isVisible: (entity: VacuumEntity, commands: VacuumCommand[]) => boolean;
command: VacuumCommand;
isSupported: (entity: VacuumEntity) => boolean;
isVisible?: (entity: VacuumEntity) => boolean;
isDisabled: (entity: VacuumEntity) => boolean;
}

export const isButtonVisible = (
entity: VacuumEntity,
button: VacuumButton,
commands: VacuumCommand[]
) => isButtonSupported(entity, button, commands) && (!button.isVisible || button.isVisible(entity));

export const isButtonSupported = (
entity: VacuumEntity,
button: VacuumButton,
commands: VacuumCommand[]
) => button.isSupported(entity) && commands.includes(button.command);

export const isCommandsControlVisible = (entity: VacuumEntity, commands: VacuumCommand[]) =>
VACUUM_BUTTONS.some((item) => item.isVisible(entity, commands));
VACUUM_BUTTONS.some((button) => isButtonVisible(entity, button, commands));

export const isCommandsControlSupported = (entity: VacuumEntity, commands: VacuumCommand[]) =>
VACUUM_BUTTONS.some((button) => isButtonSupported(entity, button, commands));

export const VACUUM_BUTTONS: VacuumButton[] = [
{
icon: "mdi:power",
serviceName: "turn_on",
isVisible: (entity, commands) =>
supportsFeature(entity, VACUUM_SUPPORT_TURN_ON) &&
commands.includes("on_off") &&
!isActive(entity),
command: "on_off",
isSupported: (entity) => supportsFeature(entity, VACUUM_SUPPORT_TURN_ON),
isVisible: (entity) => !isActive(entity),
isDisabled: () => false,
},
{
icon: "mdi:power",
serviceName: "turn_off",
isVisible: (entity, commands) =>
supportsFeature(entity, VACUUM_SUPPORT_TURN_OFF) &&
commands.includes("on_off") &&
isActive(entity),
command: "on_off",
isSupported: (entity) => supportsFeature(entity, VACUUM_SUPPORT_TURN_OFF),
isVisible: (entity) => isActive(entity),
isDisabled: () => false,
},
{
icon: "mdi:play",
serviceName: "start",
isVisible: (entity, commands) =>
supportsFeature(entity, VACUUM_SUPPORT_START) &&
commands.includes("start_pause") &&
!isCleaning(entity),
command: "start_pause",
isSupported: (entity) => supportsFeature(entity, VACUUM_SUPPORT_START),
isVisible: (entity) => !isCleaning(entity),
isDisabled: () => false,
},
{
icon: "mdi:pause",
serviceName: "pause",
isVisible: (entity, commands) =>
command: "start_pause",
isSupported: (entity) =>
// We need also to check if Start is supported because if not we show play-pause
supportsFeature(entity, VACUUM_SUPPORT_START) &&
supportsFeature(entity, VACUUM_SUPPORT_PAUSE) &&
commands.includes("start_pause") &&
isCleaning(entity),
supportsFeature(entity, VACUUM_SUPPORT_PAUSE),
isVisible: (entity) => isCleaning(entity),
isDisabled: () => false,
},
{
icon: "mdi:play-pause",
serviceName: "start_pause",
isVisible: (entity, commands) =>
command: "start_pause",
isSupported: (entity) =>
// If start is supported, we don't show this button
!supportsFeature(entity, VACUUM_SUPPORT_START) &&
supportsFeature(entity, VACUUM_SUPPORT_PAUSE) &&
commands.includes("start_pause"),
supportsFeature(entity, VACUUM_SUPPORT_PAUSE),
isDisabled: () => false,
},
{
icon: "mdi:stop",
serviceName: "stop",
isVisible: (entity, commands) =>
supportsFeature(entity, VACUUM_SUPPORT_STOP) && commands.includes("stop"),
command: "stop",
isSupported: (entity) => supportsFeature(entity, VACUUM_SUPPORT_STOP),
isDisabled: (entity) => isStopped(entity),
},
{
icon: "mdi:target-variant",
serviceName: "clean_spot",
isVisible: (entity, commands) =>
supportsFeature(entity, VACUUM_SUPPORT_CLEAN_SPOT) && commands.includes("clean_spot"),
command: "clean_spot",
isSupported: (entity) => supportsFeature(entity, VACUUM_SUPPORT_CLEAN_SPOT),
isDisabled: () => false,
},
{
icon: "mdi:map-marker",
serviceName: "locate",
isVisible: (entity, commands) =>
supportsFeature(entity, VACUUM_SUPPORT_LOCATE) && commands.includes("locate"),
command: "locate",
isSupported: (entity) => supportsFeature(entity, VACUUM_SUPPORT_LOCATE),
isDisabled: (entity) => isReturningHome(entity),
},
{
icon: "mdi:home-map-marker",
serviceName: "return_to_base",
isVisible: (entity, commands) =>
supportsFeature(entity, VACUUM_SUPPORT_RETURN_HOME) && commands.includes("return_home"),
command: "return_home",
isSupported: (entity) => supportsFeature(entity, VACUUM_SUPPORT_RETURN_HOME),
isDisabled: () => false,
},
];
Expand Down Expand Up @@ -131,7 +145,9 @@ export class CoverButtonsControl extends LitElement {

return html`
<mushroom-button-group .fill=${this.fill} ?rtl=${rtl}>
${VACUUM_BUTTONS.filter((item) => item.isVisible(this.entity, this.commands)).map(
${VACUUM_BUTTONS.filter((item) =>
isButtonVisible(this.entity, item, this.commands)
).map(
(item) => html`
<mushroom-button
.entry=${item}
Expand Down
29 changes: 22 additions & 7 deletions src/cards/vacuum-card/vacuum-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import { registerCustomCard } from "../../utils/custom-cards";
import { computeEntityPicture } from "../../utils/info";
import { VACUUM_CARD_EDITOR_NAME, VACUUM_CARD_NAME, VACUUM_ENTITY_DOMAINS } from "./const";
import "./controls/vacuum-commands-control";
import { isCommandsControlVisible } from "./controls/vacuum-commands-control";
import {
isCommandsControlSupported,
isCommandsControlVisible,
} from "./controls/vacuum-commands-control";
import { isCleaning, isReturningHome } from "./utils";
import { VacuumCardConfig } from "./vacuum-card-config";

Expand All @@ -38,7 +41,7 @@ registerCustomCard({
});

@customElement(VACUUM_CARD_NAME)
export class VacuumCard extends MushroomBaseCard implements LovelaceCard {
export class VacuumCard extends MushroomBaseCard<VacuumCardConfig> implements LovelaceCard {
public static async getConfigElement(): Promise<LovelaceCardEditor> {
await import("./vacuum-card-editor");
return document.createElement(VACUUM_CARD_EDITOR_NAME) as LovelaceCardEditor;
Expand All @@ -53,22 +56,34 @@ export class VacuumCard extends MushroomBaseCard implements LovelaceCard {
};
}

@state() private _config?: VacuumCardConfig;
isControlSupported() {
if (!this._config || !this.hass || !this._config.entity) return false;

const entityId = this._config.entity;
const stateObj = this.hass.states[entityId] as VacuumEntity | undefined;
if (!stateObj) return false;

return isCommandsControlSupported(stateObj, this._config.commands ?? []);
}

getCardSize(): number | Promise<number> {
return 1;
public getGridSize(): [number, number] {
const size = super.getGridSize();
if (this.isControlSupported() && this._appearance?.layout !== "horizontal") {
size[1] += 1;
}
return size;
}

setConfig(config: VacuumCardConfig): void {
this._config = {
super.setConfig({
tap_action: {
action: "more-info",
},
hold_action: {
action: "more-info",
},
...config,
};
});
}

private _handleAction(ev: ActionHandlerEvent) {
Expand Down
13 changes: 8 additions & 5 deletions src/utils/base-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,20 @@ export class MushroomBaseCard<T extends BaseConfig = BaseConfig> extends Mushroo
this._config = config;
}

public get _appearance(): Appearance | undefined {
if (!this._config) return undefined;
return computeAppearance(this._config);
}

public getGridSize(): [number, number] {
this._inGrid = true;
let column = 2;
let row = 1;
if (!this._config) return [column, row];

const appearance = computeAppearance(this._config);
if (appearance.layout === "vertical") {
if (!this._appearance) return [column, row];
if (this._appearance.layout === "vertical") {
row += 1;
}
if (appearance.layout === "horizontal") {
if (this._appearance.layout === "horizontal") {
column = 4;
}
return [column, row];
Expand Down

0 comments on commit 64365b2

Please sign in to comment.