Skip to content

Commit acd563c

Browse files
committed
Build new remote card
1 parent 9f0e098 commit acd563c

File tree

9 files changed

+1283
-1146
lines changed

9 files changed

+1283
-1146
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@
5050
"lint": "eslint src/*.ts",
5151
"rollup": "rollup -c"
5252
}
53-
}
53+
}

rollup.config.dev.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { terser } from "rollup-plugin-terser";
66
import json from '@rollup/plugin-json';
77

88
export default {
9-
input: ["src/roku-card.ts"],
9+
input: ["src/remote-card.ts"],
1010
output: {
1111
dir: "./dist",
1212
format: "es",

rollup.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const plugins = [
3232

3333
export default [
3434
{
35-
input: 'src/roku-card.ts',
35+
input: 'src/remote-card.ts',
3636
output: {
3737
dir: 'dist',
3838
format: 'es',

src/action-handler-directive.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { directive, PropertyPart } from 'lit-html';
1+
import { directive, PropertyPart } from 'lit-html/lit-html';
22

33
import { fireEvent, ActionHandlerDetail, ActionHandlerOptions } from 'custom-card-helpers';
44

@@ -161,15 +161,15 @@ class ActionHandler extends HTMLElement implements ActionHandler {
161161
}
162162
}
163163

164-
customElements.define('action-handler-roku-card', ActionHandler);
164+
customElements.define('action-handler-remote-card', ActionHandler);
165165

166166
const getActionHandler = (): ActionHandler => {
167167
const body = document.body;
168-
if (body.querySelector('action-handler-roku-card')) {
169-
return body.querySelector('action-handler-roku-card') as ActionHandler;
168+
if (body.querySelector('action-handler-remote-card')) {
169+
return body.querySelector('action-handler-remote-card') as ActionHandler;
170170
}
171171

172-
const actionhandler = document.createElement('action-handler-roku-card');
172+
const actionhandler = document.createElement('action-handler-remote-card');
173173
body.appendChild(actionhandler);
174174

175175
return actionhandler as ActionHandler;

src/const.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const CARD_VERSION = '1.2.0';
1+
export const CARD_VERSION = '1.5.0';

src/remote-card.ts

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import {
2+
html,
3+
LitElement,
4+
TemplateResult,
5+
customElement,
6+
property,
7+
CSSResult,
8+
css,
9+
internalProperty,
10+
} from 'lit-element/lit-element';
11+
import { HomeAssistant, applyThemesOnElement, hasAction, handleClick } from 'custom-card-helpers';
12+
13+
import { RemoteCardConfig, RemoteButton, ActionRemoteButton } from './types';
14+
import { actionHandler } from './action-handler-directive';
15+
import { CARD_VERSION } from './const';
16+
17+
/* eslint no-console: 0 */
18+
console.info(
19+
`%c Remote-Card \n%c Version ${CARD_VERSION} `,
20+
'color: orange; font-weight: bold; background: black',
21+
'color: white; font-weight: bold; background: dimgray',
22+
);
23+
24+
@customElement('remote-card')
25+
export class RemoteCard extends LitElement {
26+
@property({ attribute: false }) public hass?: HomeAssistant;
27+
28+
@internalProperty() private _config?: RemoteCardConfig;
29+
30+
public getCardSize(): number {
31+
if (this._config && this._config.buttons.length > 0) {
32+
const lengths = this._config.buttons.map(row => row.row.length);
33+
return Math.max(...lengths);
34+
} else {
35+
return 3;
36+
}
37+
}
38+
39+
public setConfig(config: RemoteCardConfig): void {
40+
if (!config.entity || config.entity.split('.')[0] !== 'remote') {
41+
console.log("Invalid configuration. You'll need to provide a remote entity");
42+
return;
43+
}
44+
45+
this._config = {
46+
theme: 'default',
47+
haptic: 'success',
48+
...config,
49+
};
50+
}
51+
52+
protected render(): TemplateResult | void {
53+
if (!this._config || !this.hass) {
54+
return html``;
55+
}
56+
57+
const stateObj = this.hass.states[this._config.entity];
58+
59+
if (this._config.entity && !stateObj) {
60+
return html`
61+
<ha-card>
62+
<div class="warning">Entity Unavailable</div>
63+
</ha-card>
64+
`;
65+
}
66+
67+
const buttons = this._config.buttons.map(row => {
68+
const button_row = row.row.map(button => {
69+
return this._renderButton(button);
70+
});
71+
return html`
72+
<div class="row">
73+
${button_row}
74+
</div>
75+
`;
76+
});
77+
78+
return html`
79+
<ha-card .header="${this._config.title}">
80+
<div class="remote">
81+
${buttons}
82+
</div>
83+
</ha-card>
84+
`;
85+
}
86+
87+
protected updated(changedProps): void {
88+
if (!this._config) {
89+
return;
90+
}
91+
92+
if (this.hass) {
93+
const oldHass = changedProps.get('hass');
94+
if (!oldHass || oldHass.themes !== this.hass.themes) {
95+
applyThemesOnElement(this, this.hass.themes, this._config.theme);
96+
}
97+
}
98+
}
99+
100+
static get styles(): CSSResult {
101+
return css`
102+
.remote {
103+
padding: 16px 0 16px 0;
104+
}
105+
img,
106+
ha-icon-button {
107+
cursor: pointer;
108+
}
109+
ha-icon-button {
110+
--mdc-icon-button-size: 64px;
111+
--mdc-icon-size: 48px;
112+
}
113+
img {
114+
width: 64px;
115+
height: 64px;
116+
border-radius: 25px;
117+
}
118+
.row {
119+
display: flex;
120+
padding: 8px 36px 8px 36px;
121+
justify-content: space-evenly;
122+
align-items: center;
123+
}
124+
.warning {
125+
display: block;
126+
color: black;
127+
background-color: #fce588;
128+
padding: 8px;
129+
}
130+
.app {
131+
flex-grow: 3;
132+
font-size: 20px;
133+
}
134+
`;
135+
}
136+
137+
private _renderButton(button: RemoteButton): TemplateResult {
138+
if ('empty' in button && button.empty) {
139+
return html`
140+
<ha-icon-button></ha-icon-button>
141+
`;
142+
}
143+
button = button as ActionRemoteButton;
144+
const actionConfig = {
145+
remote_command: button.remote_command,
146+
...button.actions,
147+
};
148+
if (button.image && !button.icon) {
149+
return html`
150+
<img
151+
title=${button.title || ''}
152+
alt=${button.title || ''}
153+
src=${button.image || ''}
154+
.action_config=${actionConfig}
155+
@action=${this._handleAction}
156+
.actionHandler=${actionHandler({
157+
hasHold: hasAction(button.actions?.hold_action),
158+
hasDoubleClick: hasAction(button.actions?.double_tap_action),
159+
})}
160+
/>
161+
`;
162+
}
163+
return html`
164+
<ha-icon-button
165+
.button=${button}
166+
icon=${button.icon || 'mdi:radiobox-marked'}
167+
title=${button.title || ''}
168+
.action_config=${actionConfig}
169+
@action=${this._handleAction}
170+
.actionHandler=${actionHandler({
171+
hasHold: hasAction(button.actions?.hold_action),
172+
hasDoubleClick: hasAction(button.actions?.double_tap_action),
173+
})}
174+
></ha-icon-button>
175+
`;
176+
}
177+
178+
private _handleAction(ev): void {
179+
//const target = ev.currentTarget || ev.path[0];
180+
if (this.hass && this._config && ev.detail.action) {
181+
const actionConfig = ev.currentTarget.action_config;
182+
183+
handleClick(
184+
this,
185+
this.hass,
186+
{
187+
tap_action: {
188+
haptic: this._config.haptic,
189+
action: 'call-service',
190+
service: 'remote.send_command',
191+
service_data: {
192+
entity_id: this._config.entity,
193+
device: this._config.device,
194+
command: actionConfig.remote_command,
195+
},
196+
},
197+
...actionConfig,
198+
},
199+
ev.detail.action === 'hold',
200+
ev.detail.action === 'double_tap',
201+
);
202+
}
203+
}
204+
}

0 commit comments

Comments
 (0)