Compare commits

...
7 Commits
Author SHA1 Message Date
GeorgeSG 526a52f630 1.0.1 2020-07-17 20:24:39 +03:00
GeorgeSG 72d82d7c0a Merge pull request #7 from GeorgeSG/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-07-17 20:24:26 +03:00
dependabot[bot] 21f66a9066 Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-17 17:23:17 +00:00
GeorgeSG fe93d385e9 1.0.0 2020-07-17 20:22:38 +03:00
GeorgeSG 05e0952624 Implements #5: Add link_values option 2020-07-17 20:20:42 +03:00
GeorgeSG 3c10a9ab44 Fixes #6: Inherit border-radius from theme. Add variable for border radius 2020-07-17 19:09:34 +03:00
GeorgeSG 9a2a57af5c Update README 2020-05-18 22:22:32 +03:00
11 changed files with 163 additions and 57 deletions
+22 -8
View File
@@ -15,7 +15,19 @@ Requires an [Input Datetime](https://www.home-assistant.io/integrations/input_da
## Installation
Install using [HACS](https://hacs.xyz) or follow this [guide](https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins)
### HACS
Install using [HACS](https://hacs.xyz) and add the following to your config:
```yaml
resources:
- url: /hacsfiles/lovelace-time-picker-card/time-picker-card.js
type: module
```
### Manual
Download time-picker-card.js from the [latest realease](https://github.com/GeorgeSG/lovelace-time-picker-card/releases/latest) and place it in your `config/www` folder. Add the following to your config:
```yaml
resources:
@@ -91,6 +103,7 @@ layout:
| type | string | **Required** | `custom:time-picker-card` | |
| entity | string | **Required** | [Input Datetime](https://www.home-assistant.io/integrations/input_datetime/) entity with `has_time: true` | |
| name | string | **Optional** | Card name | Entity's `friendly_name` |
| link_values | boolean | **Optional** | If enabled, will change hour when minutes overflow. E.g. will go from 11:55 to 12:00, instead of 11:00 | `false` |
| hour_mode | `12` or `24` | **Optional** | Hour format. If `12`, card will show AM/PM picker | `24` |
| hour_step | number | **Optional** | Hour change when clicking arrows | `1` |
| minute_step | number | **Optional** | Minute change when clicking arrows | `5` |
@@ -116,13 +129,14 @@ layout:
Time Picker Card will automatically pick up colors from your lovelace theme, but if you want to customize some of them,
you can use the following variables in your theme's config file:
| Name | Default | Description |
| ------------------------------------- | ---------------------------- | -------------------------------------- |
| time-picker-elements-background-color | `var(--primary-color)` | Background color for header and inputs |
| time-picker-icon-color | `var(--primary-text-color)` | Arrow color |
| time-picker-text-color | `white` | Text color |
| time-picker-accent-color | `var(--primary-color)` | AM / PM active color |
| time-picker-off-color | `var(--disabled-text-color)` | AM / PM inactive color |
| Name | Default | Description |
| ------------------------------------- | ------------------------------ | -------------------------------------- |
| time-picker-elements-background-color | `var(--primary-color)` | Background color for header and inputs |
| time-picker-icon-color | `var(--primary-text-color)` | Arrow color |
| time-picker-text-color | `white` | Text color |
| time-picker-accent-color | `var(--primary-color)` | AM / PM active color |
| time-picker-off-color | `var(--disabled-text-color)` | AM / PM inactive color |
| time-picker-border-radius | `var(--ha-card-border-radius)` | Border radius of the card |
## Meta
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "time-picker-card",
"version": "0.1.1",
"version": "1.0.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -2546,9 +2546,9 @@
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
"dev": true
},
"lodash.get": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "time-picker-card",
"version": "0.1.1",
"version": "1.0.1",
"author": "Georgi Gardev <georgi@gardev.com>",
"description": "Lovelace time-picker-card",
"keywords": [
+4 -7
View File
@@ -16,6 +16,7 @@ import { Direction } from '../types';
@customElement('time-unit')
export class TimeUnitComponent extends LitElement {
static readonly EVENT_UPDATE = 'update';
static readonly EVENT_STEP_CHANGE = 'stepChange';
@property() private unit!: TimeUnit;
@@ -39,16 +40,12 @@ export class TimeUnitComponent extends LitElement {
onInputChange({ target: { value } }: { target: HTMLInputElement }): void {
this.unit.setStringValue(value);
this.emitUpdate();
const event = new CustomEvent(TimeUnitComponent.EVENT_UPDATE);
this.dispatchEvent(event);
}
onStepChangerClick(direction: Direction): void {
this.unit.stepUpdate(direction);
this.emitUpdate();
}
private emitUpdate(): void {
const event = new CustomEvent(TimeUnitComponent.EVENT_UPDATE);
const event = new CustomEvent(TimeUnitComponent.EVENT_STEP_CHANGE, { detail: { direction } });
this.dispatchEvent(event);
}
+39 -20
View File
@@ -61,14 +61,15 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
@value-changed=${this.onValueChange}
></paper-input>
<div class="side-by-side">
<ha-switch
style="margin-left: 10px"
.checked="${!Boolean(this.config.hide?.name)}"
.configValue="${'hide_name'}"
@change="${this.onHideNameChange}"
>
<div>
<ha-switch
style="margin-left: 10px"
.checked="${!Boolean(this.config.hide?.name)}"
.configValue="${'hide_name'}"
@change="${this.onHideNameChange}"
></ha-switch>
Show name?
</ha-switch>
</div>
<paper-dropdown-menu
style="width: 100%"
label="Name Position (Optional)"
@@ -101,20 +102,24 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
></paper-input>
</div>
<div class="side-by-side">
<ha-switch
.checked="${this.config.hour_mode === 12}"
.configValue="${'hour_mode'}"
@change="${this.onHourModeChange}"
>
<div>
<ha-switch
.checked="${this.config.hour_mode === 12}"
.configValue="${'hour_mode'}"
@change="${this.onHourModeChange}"
></ha-switch>
12-Hour mode
</ha-switch>
<ha-switch
.checked="${this.config.layout?.hour_mode === 'single'}"
.configValue="${'hour_mode_layout'}"
@change="${this.onHourModeLayoutChange}"
>
"Single" hour mode layout (in 12-Hour mode only)
</ha-switch>
</div>
${this.config.hour_mode === 12
? html`<div>
<ha-switch
.checked="${this.config.layout?.hour_mode === 'single'}"
.configValue="${'hour_mode_layout'}"
@change="${this.onHourModeLayoutChange}"
></ha-switch>
"Single" hour mode layout
</div>`
: ''}
</div>
<div class="side-by-side">
<paper-dropdown-menu
@@ -131,6 +136,14 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
${Object.values(Layout.AlignControls).map((a) => html`<paper-item>${a}</paper-item>`)}
</paper-listbox>
</paper-dropdown-menu>
<div>
<ha-switch
.checked="${this.config.link_values}"
.configValue="${'link_values'}"
@change="${this.onLinkValuesChange}"
></ha-switch>
Link Values
</div>
</div>
</div>`;
}
@@ -173,6 +186,11 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
this.dispatch(newConfig);
}
private onLinkValuesChange({ target: { checked } }): void {
const newConfig = { ...this.config, link_values: checked };
this.dispatch(newConfig);
}
private onValueChange(e: CustomEvent): void {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const property = (e.target as any).configValue;
@@ -209,6 +227,7 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
return css`
ha-switch {
padding: 16px 0;
margin-right: 16px;
}
.side-by-side {
display: flex;
+10
View File
@@ -1,5 +1,6 @@
import { DEFAULT_MINUTE_STEP } from '../const';
import { TimeUnit } from './time-unit';
import { Direction } from '../types';
/**
* * Represents the minute value of a datetime.
@@ -13,4 +14,13 @@ export class Minute extends TimeUnit {
constructor(value: number, step = DEFAULT_MINUTE_STEP) {
super(value, step, Minute.VALUE_LIMIT);
}
/**
* Returns true if the minutes will overflow to a different hour when changed in {@param direction}.
* @param direction
*/
willOverflow(direction: Direction): boolean {
const newValue = direction === Direction.UP ? this.value + this._step : this.value - this._step;
return newValue >= this._limit || newValue < 0;
}
}
+10 -6
View File
@@ -39,23 +39,27 @@ export abstract class TimeUnit {
* Updates the value in {@param direction} by the step size specified in the constructoor.
* @param direction
*/
stepUpdate(direction: Direction): void {
direction === Direction.UP ? this.increment() : this.decrement();
stepUpdate(direction: Direction, step: number = this._step): void {
direction === Direction.UP ? this.increment(step) : this.decrement(step);
}
toString(): string {
return this.value < 10 ? `0${this.value}` : this.value.toString();
}
private increment(): void {
this.setValue(this.value + this._step);
private increment(step: number = this._step): void {
this.setValue(this.value + step);
}
private decrement(): void {
this.setValue(this.value - this._step);
private decrement(step: number = this._step): void {
this.setValue(this.value - step);
}
protected setValue(newValue: number): void {
if (isNaN(newValue)) {
return;
}
if (newValue >= this._limit || newValue < 0) {
newValue = (newValue + this._limit) % this._limit;
}
+23
View File
@@ -0,0 +1,23 @@
import { Hour } from './hour';
import { Minute } from './minute';
import { Direction } from '../types';
export class Time {
constructor(public hour: Hour, public minute: Minute, private _linkValues: boolean = false) {}
hourStep(direction: Direction): void {
this.hour.stepUpdate(direction);
}
minuteStep(direction: Direction): void {
if (this._linkValues && this.minute.willOverflow(direction)) {
this.hour.stepUpdate(direction, 1);
}
this.minute.stepUpdate(direction);
}
get value(): string {
return `${this.hour.value}:${this.minute.value}`;
}
}
+32 -11
View File
@@ -19,6 +19,7 @@ import {
} from './const';
import { Hour } from './models/hour';
import { Minute } from './models/minute';
import { Time } from './models/time';
import { Partial } from './partials';
import { Period, TimePickerCardConfig, Layout } from './types';
@@ -43,8 +44,7 @@ window.customCards.push({
export class TimePickerCard extends LitElement implements LovelaceCard {
@property({ type: Object }) hass!: HomeAssistant;
@property() private config!: TimePickerCardConfig;
@property() private hour!: Hour;
@property() private minute!: Minute;
@property() private time!: Time;
@property() private period!: Period;
private get entity(): HassEntity | undefined {
@@ -110,9 +110,10 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
}
const { hour, minute } = this.entity!.attributes;
this.hour = new Hour(hour, this.config.hour_step, this.config.hour_mode);
this.minute = new Minute(minute, this.config.minute_step);
this.period = this.hour.value >= 12 ? Period.PM : Period.AM;
const hourInstance = new Hour(hour, this.config.hour_step, this.config.hour_mode);
const minuteInstance = new Minute(minute, this.config.minute_step);
this.time = new Time(hourInstance, minuteInstance, this.config.link_values);
this.period = hourInstance.value >= 12 ? Period.PM : Period.AM;
return html`
<ha-card>
@@ -121,9 +122,17 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
${this.hasNameInside ? Partial.nestedName(this.name!, this.entity) : ''}
<div class=${classMap(this.contentClass)}>
<time-unit .unit=${this.hour} @update=${this.callHassService}></time-unit>
<time-unit
.unit=${this.time.hour}
@stepChange=${this.onHourStepChange}
@update=${this.callHassService}
></time-unit>
<div class="time-separator">:</div>
<time-unit .unit=${this.minute} @update=${this.callHassService}></time-unit>
<time-unit
.unit=${this.time.minute}
@stepChange=${this.onMinuteStepChange}
@update=${this.callHassService}
></time-unit>
${this.shouldShowPeriod
? html`<time-period
@@ -159,7 +168,17 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
}
private onPeriodToggle(): void {
this.hour.togglePeriod();
this.time.hour.togglePeriod();
this.callHassService();
}
private onHourStepChange(event: CustomEvent): void {
this.time.hourStep(event.detail.direction);
this.callHassService();
}
private onMinuteStepChange(event: CustomEvent): void {
this.time.minuteStep(event.detail.direction);
this.callHassService();
}
@@ -168,11 +187,9 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
throw new Error('Unable to update datetime');
}
const time = `${this.hour.value}:${this.minute.value}:00`;
return this.hass.callService(ENTITY_DOMAIN, 'set_datetime', {
entity_id: this.entity!.entity_id,
time,
time: this.time.value,
});
}
@@ -188,12 +205,16 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
--tpc-text-color: var(--time-picker-text-color, #fff);
--tpc-accent-color: var(--time-picker-accent-color, var(--primary-color));
--tpc-off-color: var(--time-picker-off-color, var(--disabled-text-color));
--tpc-border-radius: var(--time-picker-border-radius, var(--ha-card-border-radius, 4px));
}
.time-picker-header {
padding: 16px;
color: var(--tpc-text-color);
background-color: var(--tpc-elements-background-color);
border-top-left-radius: var(--tpc-border-radius);
border-top-right-radius: var(--tpc-border-radius);
font-size: 1em;
text-align: center;
}
+1
View File
@@ -3,6 +3,7 @@ import { LovelaceCardConfig } from 'custom-card-helpers';
export interface TimePickerCardConfig extends LovelaceCardConfig {
entity: string;
name?: string;
link_values?: boolean;
hour_mode?: HourMode;
hour_step?: number;
minute_step?: number;
+17
View File
@@ -99,4 +99,21 @@ describe('Minute', () => {
expect(minute.value).to.equal(47);
});
});
describe('will overflow', () => {
it('returns true if the minutes will overflow an hour up', () => {
minute.setStringValue('59');
expect(minute.willOverflow(Direction.UP)).to.be.true;
});
it('returns true if the minutes will overflow an hour down', () => {
minute.setStringValue('0');
expect(minute.willOverflow(Direction.DOWN)).to.be.true;
});
it('returns true if the minutes will not overflow', () => {
minute.setStringValue('55');
expect(minute.willOverflow(Direction.DOWN)).to.be.false;
});
});
});