diff --git a/README.md b/README.md index c455704..bbdd7b7 100755 --- a/README.md +++ b/README.md @@ -39,17 +39,25 @@ Double tap will cancel (reset) timer All following options which support colors can also be used with hexadecimal color identifier with opacity! -| Option | Type | Requirement | Description | -|---|---|---|---| -| entity | string | **required** | Timer entity ID | -| bins | int | optional | Number of bins (arcs). Default: 36 | -| pad_angle | float | optional | Seperating angle between each individual arc in degrees. Default: 1 | -| corner_radius | float | optional | Radius for rounded arc corners. Default: 4 | -| color | array of strings | optional | Color array used for filling remaining timer arc units. If array contains only single value, that color will be used to fill the whole timer, otherwise linear gradient will be created | -| color_state | boolean | optional | If set to `true` it will color remaining time in the middle of card with current state color from gradient | -| empty_bar_color | string | optional | Color for timer arcs which are inactive, by default they gave opacity of 0, therefore they are not visible | -| secondary_info_size | string or int | optional | CSS size for secondary info (Friendly name of timer). Default: "50%" | -| layout | string | optional | Layout mode for the card. Available options are "circle" or "minimal". Minimal layout is supposed to create bar timer similar in style to Mushroom cards. Default: "circle" | +| Option | Type | Requirement | Default | Description | +|---|---|---|---|---| +| entity | string | **required** | - | Timer entity ID | +| bins | int | optional | 36 | Number of bins (arcs). | +| pad_angle | float | optional | 1 | Seperating angle between each individual arc in degrees. | +| corner_radius | float | optional | 4 | Radius for rounded arc corners. | +| color | array of strings | optional | | Color array used for filling remaining timer arc units. If array contains only single value, that color will be used to fill the whole timer, otherwise linear gradient will be created. | +| color_state | boolean | optional | | If set to `true` it will color remaining time in the middle of card with current state color from gradient. | +| empty_bar_color | string | optional | | Color for timer arcs which are inactive, by default they gave opacity of 0, therefore they are not visible. | +| secondary_info_size | string or int | optional | 50% for cicle or 80% for minimal | CSS size for secondary info (Friendly name of timer). | +| layout | string | optional | circle | Layout mode for the card. Available options are "circle" or "minimal". Minimal layout is supposed to create bar timer similar in style to Mushroom cards. | +| name | string | optional | Entity friendly name | Name to be displayed. Can be a string or "none". | +| icon | string | optional | Etity Icon | Icon to be displayed in minimal layout. Can be a standard icon (e.g. "mdi:motion-sensor") or "none". | +| direction | string | optional | countdown | Direction of the timer. Can be "countdown" or "countup". | +| primary_info | string | optional | name | Primary information to be displayed. Can be a "none", "name" or "timer". | +| secondary_info | string | optional | timer | Secondary information to be displayed. Can be a "none", "name" or "timer". | +| tap_action | string | optional | toggle | Action triggered on a single tap. Can be a "none", "toggle", "more_info" or "cancel". | +| hold_action | string | optional | more_info | Action triggered on holding. Can be a "none", "toggle", "more_info" or "cancel". | +| double_tap_action | string | optional | cancel | Action triggered on a double tap. Can be a "none", "toggle", "more_info" or "cancel". | ## Example diff --git a/circular-timer-card.js b/circular-timer-card.js index 7b603b5..5f3a572 100755 --- a/circular-timer-card.js +++ b/circular-timer-card.js @@ -14,8 +14,17 @@ class CircularTimerCard extends LitElement { this._defaultTimerFill = getComputedStyle(document.documentElement).getPropertyValue('--primary-color'); this._gradientColors = [this._defaultTimerFill, this._defaultTimerFill]; this._defaultTimerEmptyFill = "#fdfdfd00"; - this._secondaryInfoSize = "50%"; + this._secondaryInfoSize; this._layout = "circle"; + + this._name = "use_entity_friendly_name"; + this._icon = "use_entity_icon"; + this._primaryInfo = "name"; + this._secondaryInfo = "timer"; + this._direction = "countdown"; + this._tapAction = "toggle"; + this._holdAction = "more_info"; + this._doubleTapAction = "cancel"; this._colorState = false; this._stateColor = getComputedStyle(document.documentElement).getPropertyValue("--primary-text-color"); @@ -29,6 +38,8 @@ class CircularTimerCard extends LitElement { this.addEventListener("click", this._tap); this._mouseIsDown = false; + this._mouseIsDownTriggered = false; + this._doubleClickTriggered = false; this.addEventListener("mousedown", this._mousedown); this.addEventListener("touchstart", this._mousedown); this.addEventListener("mouseup", this._mouseup); @@ -103,8 +114,46 @@ class CircularTimerCard extends LitElement { if (config.secondary_info_size) { this._secondaryInfoSize = config.secondary_info_size; + } else { + if (config.layout === "minimal") { + this._secondaryInfoSize = "80%"; + } else { + this._secondaryInfoSize = "50%"; + } + } + + if (config.name) { + this._name = config.name; } + if (config.icon) { + this._icon = config.icon; + } + + if (config.primary_info) { + this._primaryInfo = config.primary_info; + } + + if (config.secondary_info) { + this._secondaryInfo = config.secondary_info; + } + + if (config.direction) { + this._direction = config.direction; + } + + if (config.tap_action) { + this._tapAction = config.tap_action; + } + + if (config.hold_action) { + this._holdAction = config.hold_action; + } + + if (config.double_tap_action) { + this._doubleTapAction = config.double_tap_action; + } + this._colorScale = d3.scaleSequential(d3.interpolateRgbBasis(this._gradientColors)); this._arc = d3.arc() .innerRadius(30) @@ -131,15 +180,38 @@ class CircularTimerCard extends LitElement { return html` Unknown entity: ${this._config.entity} `; } + if (this._name == "use_entity_friendly_name") { + this._name = this._stateObj.attributes.friendly_name; + } + + var icon; + var icon_style; + if (this._icon == "use_entity_icon") { + icon = this._stateObj.attributes.icon; + } else if (this._icon == "none") { + icon = ""; + icon_style = "display:none;"; + } else { + icon = this._icon; + } + var a = this._stateObj.attributes.duration.split(':'); var d_sec = (+a[0]) * 60 * 60 + (+a[1]) * 60 + (+a[2]); var rem_sec; if (this._stateObj.state == "active") { - rem_sec = ((Date.parse(this._stateObj.attributes.finishes_at) - new Date()) / 1000); + if (this._direction == "countup") { + rem_sec = d_sec - ((Date.parse(this._stateObj.attributes.finishes_at) - new Date()) / 1000); + } else { + rem_sec = ((Date.parse(this._stateObj.attributes.finishes_at) - new Date()) / 1000); + } } else { if (this._stateObj.state == "paused") { var a1 = this._stateObj.attributes.remaining.split(':'); - rem_sec = (+a1[0]) * 60 * 60 + (+a1[1]) * 60 + (+a1[2]); + if (this._direction == "countup") { + rem_sec = d_sec - ((+a1[0]) * 60 * 60 + (+a1[1]) * 60 + (+a1[2])); + } else { + rem_sec = (+a1[0]) * 60 * 60 + (+a1[1]) * 60 + (+a1[2]); + } } else { rem_sec = d_sec; } @@ -149,18 +221,38 @@ class CircularTimerCard extends LitElement { var limitBin = Math.floor(this._bins * proc); var colorData = this._generateArcColorData(limitBin); var textColor = this._getTextColor(proc); + + var display_rem_sec = this._getTimeString(rem_sec); + + var primary_info; + if (this._primaryInfo == "none") { + primary_info = ''; + } else if (this._primaryInfo == "timer") { + primary_info = display_rem_sec; + } else { + primary_info = this._name; + } + + var secondary_info; + if (this._secondaryInfo == "none") { + secondary_info = ''; + } else if (this._secondaryInfo == "name") { + secondary_info = this._name; + } else { + secondary_info = display_rem_sec; + } if (this._layout === "minimal") { return html`
-
- -
+
+ +
- ${this._stateObj.attributes.friendly_name} - ${true ? this._getTimeString(rem_sec) : `${this._stateObj.state} | ${this._getTimeString(rem_sec)}`} + ${primary_info} + ${secondary_info}
@@ -188,10 +280,10 @@ class CircularTimerCard extends LitElement { )} - ${this._getTimeString(rem_sec)} + ${secondary_info} - ${this._stateObj.attributes.friendly_name} + ${primary_info}
@@ -266,42 +358,80 @@ class CircularTimerCard extends LitElement { return `${hours}:${minutes}:${seconds}` } - _tap(e) { - + _toggle_func() { const stateObj = this.hass.states[this._config.entity]; - const service = stateObj.state === "active" ? "pause" : "start"; - + const service = stateObj.state === "active" ? "pause" : "start"; this.hass.callService("timer", service, { entity_id: this._config.entity }); } - _double_tap(e) { - + _cancel_func() { const stateObj = this.hass.states[this._config.entity]; this.hass.callService("timer", "cancel", { entity_id: this._config.entity }); + } + _moreInfo_func() { + var event = new Event("hass-action", { + bubbles: true, + composed: true, + }); + event.detail = { + config: this._actionConfig, + action: "hold", + }; + this.dispatchEvent(event); + } + + _tap(e) { + if(this._mouseIsDownTriggered == false) { + setTimeout(() => { + if (this._doubleClickTriggered == false) { + if (this._tapAction == "toggle") { + this._toggle_func(); + } else if (this._tapAction == "more_info") { + this._moreInfo_func(); + } else if (this._tapAction == "cancel") { + this._cancel_func(); + } + } + }, 200); + } } - _mousedown(e) { + _double_tap(e) { + this._doubleClickTriggered = true; + if (this._doubleTapAction == "toggle") { + this._toggle_func(); + } else if (this._doubleTapAction == "more_info") { + this._moreInfo_func(); + } else if (this._doubleTapAction == "cancel") { + this._cancel_func(); + } + setTimeout(() => { + this._doubleClickTriggered = false; + }, 500); + } + _mousedown(e) { this._mouseIsDown = true; setTimeout(() => { - if(this._mouseIsDown) { - var event = new Event("hass-action", { - bubbles: true, - composed: true, - }); - event.detail = { - config: this._actionConfig, - action: "hold", - }; - this.dispatchEvent(event); + this._mouseIsDownTriggered = true; + if (this._holdAction == "toggle") { + this._toggle_func(); + } else if (this._holdAction == "more_info") { + this._moreInfo_func(); + } else if (this._holdAction == "cancel") { + this._cancel_func(); + } } - }, 1000); + }, 1000); } _mouseup(e) { - this._mouseIsDown = false; + setTimeout(() => { + this._mouseIsDown = false; + this._mouseIsDownTriggered = false; + }, 100); } static get styles() { @@ -332,8 +462,6 @@ class CircularTimerCard extends LitElement { font-size: 35%; } - - .header { display: flex; padding: 0px; @@ -372,8 +500,6 @@ class CircularTimerCard extends LitElement { .secondary { color: var(--secondary-text-color); - - font-size: 12px; text-transform: capitalize; } @@ -406,4 +532,4 @@ customElements.define("circular-timer-card", CircularTimerCard); console.info( `%c circular-timer-card | Version 1.1 `, "color: white; font-weight: bold; background: #FF4F00", -); \ No newline at end of file +);