Skip to content

Commit

Permalink
Added new option show_completed.
Browse files Browse the repository at this point in the history
Minor fixes and code improvements.
  • Loading branch information
Konstantin Grinkevich committed Mar 7, 2021
1 parent 578312f commit 4d76b3f
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 65 deletions.
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Typical example of using this card in YAML config would look like this:
type: 'custom:todoist-card'
entity: sensor.to_do_list
show_header: true
show_completed: 5
show_item_add: true
show_item_close: true
show_item_delete: true
Expand All @@ -86,20 +87,25 @@ only_today_overdue: false

Here is what every option means:

| Name | Type | Default | Description |
| -------------------- | :-------: | :----------: | --------------------------------------------------------------- |
| `type` | `string` | **required** | `custom:todoist-card` |
| `entity` | `string` | **required** | An entity_id within the `sensor` domain. |
| `show_header` | `boolean` | `true` | Show friendly name of the selected `sensor` in the card header. |
| `show_item_add` | `boolean` | `true` | Show text input element for adding new items to the list. |
| `show_item_close` | `boolean` | `true` | Show `close/complete` buttons. |
| `show_item_delete` | `boolean` | `true` | Show `delete` buttons. |
| `only_today_overdue` | `boolean` | `false` | Only show tasks that are overdue or due today. |
| Name | Type | Default | Description |
| -------------------- | :-------: | :----------: | ---------------------------------------------------------------------- |
| `type` | `string` | **required** | `custom:todoist-card` |
| `entity` | `string` | **required** | An entity_id within the `sensor` domain. |
| `show_completed` | `integer` | `5` | Number of completed tasks shown at the end of the list (0 to disable). |
| `show_header` | `boolean` | `true` | Show friendly name of the selected `sensor` in the card header. |
| `show_item_add` | `boolean` | `true` | Show text input element for adding new items to the list. |
| `show_item_close` | `boolean` | `true` | Show `close/complete` and `uncomplete` buttons. |
| `show_item_delete` | `boolean` | `true` | Show `delete` buttons. |
| `only_today_overdue` | `boolean` | `false` | Only show tasks that are overdue or due today. |

` `
> Note that the completed tasks list is cleared when the page is refreshed.

## Actions

- _Circle_ marks selected task as completed.
- _Trash bin_ deletes selected task.
- _Plus_ "uncompletes" selected task, adding it back to the list.
- _Trash bin_ deletes selected task (gray one deletes it only from the list of completed items, not from Todoist archive).
- _Input_ adds new item to the list after pressing `Enter`.

## License
Expand Down
213 changes: 158 additions & 55 deletions todoist-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ class TodoistCardEditor extends LitElement {

return '';
}

get _show_completed() {
if (this._config) {
return (this._config.show_completed !== undefined) ? this._config.show_completed : 5;
}

return 5;
}

get _show_header() {
if (this._config) {
Expand Down Expand Up @@ -76,6 +84,10 @@ class TodoistCardEditor extends LitElement {
? Object.keys(this.hass.states).filter(entity => entity.substr(0, entity.indexOf('.')) === type)
: [];
}

isNumeric(v) {
return !isNaN(parseFloat(v)) && isFinite(v);
}

valueChanged(e) {
if (
Expand All @@ -88,15 +100,15 @@ class TodoistCardEditor extends LitElement {

if (e.target.configValue) {
if (e.target.value === '') {
if (e.target.configValue !== 'entity') {
if (!['entity', 'show_completed'].includes(e.target.configValue)) {
delete this._config[e.target.configValue];
}
} else {
this._config = {
...this._config,
[e.target.configValue]: e.target.checked !== undefined
? e.target.checked
: e.target.value,
: this.isNumeric(e.target.value) ? parseFloat(e.target.value) : e.target.value,
};
}
}
Expand All @@ -110,6 +122,7 @@ class TodoistCardEditor extends LitElement {
}

const entities = this.getEntitiesByType('sensor');
const completedCount = [...Array(16).keys()];

return html`<div class="card-config">
<paper-dropdown-menu
Expand All @@ -126,6 +139,21 @@ class TodoistCardEditor extends LitElement {
})}
</paper-listbox>
</paper-dropdown-menu>
<paper-dropdown-menu
label="Number of completed tasks shown at the end of the list (0 to disable)"
.configValue=${'show_completed'}
@value-changed=${this.valueChanged}
>
<paper-listbox
slot="dropdown-content"
.selected=${completedCount.indexOf(this._show_completed)}
>
${completedCount.map(count => {
return html`<paper-item>${count}</paper-item>`;
})}
</paper-listbox>
</paper-dropdown-menu>
<p class="option">
<ha-switch
Expand Down Expand Up @@ -154,7 +182,7 @@ class TodoistCardEditor extends LitElement {
@change=${this.valueChanged}
>
</ha-switch>
Show "close/complete" buttons
Show "close/complete" and "uncomplete" buttons
</p>
<p class="option">
Expand Down Expand Up @@ -199,6 +227,12 @@ class TodoistCardEditor extends LitElement {


class TodoistCard extends LitElement {
constructor() {
super();

this.itemsCompleted = [];
}

static get properties() {
return {
hass: Object,
Expand All @@ -225,6 +259,12 @@ class TodoistCard extends LitElement {
random(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}

getUUID() {
let date = new Date();

return this.random(1, 100) + '-' + (+date) + '-' + date.getMilliseconds();
}

itemAdd(e) {
if (e.which === 13) {
Expand All @@ -235,81 +275,109 @@ class TodoistCard extends LitElement {
let stateValue = this.hass.states[this.config.entity].state || undefined;

if (stateValue) {
let date = new Date();

let temp = this.random(1, 100) + '-' + (+date) + '-' + date.getMilliseconds();
let uuid = this.getUUID();

let commands = [{
'type': 'item_add',
'temp_id': temp,
'uuid': temp,
'temp_id': uuid,
'uuid': uuid,
'args': {
'project_id': stateValue,
'content': value,
},
}];
this.hass.callService('rest_command', 'todoist', {
commands: JSON.stringify(commands),
});

input.value = '';

let t = this;
setTimeout(function () {
t.hass.callService('homeassistant', 'update_entity', {
entity_id: t.config.entity,

this.hass
.callService('rest_command', 'todoist', {
commands: JSON.stringify(commands),
})
.then(response => {
input.value = '';

this.hass.callService('homeassistant', 'update_entity', {
entity_id: this.config.entity,
});
});
}, 1000);
}
}
}
}

itemClose(itemId) {
let date = new Date();

itemClose(item) {
let commands = [{
'type': 'item_close',
'uuid': this.random(1, 100) + '-' + (+date) + '-' + date.getMilliseconds(),
'uuid': this.getUUID(),
'args': {
'id': itemId,
'id': item.id,
},
}];

this.hass.callService('rest_command', 'todoist', {
commands: JSON.stringify(commands),
});
this.hass
.callService('rest_command', 'todoist', {
commands: JSON.stringify(commands),
})
.then(response => {
if (this.itemsCompleted.length >= this.config.show_completed) {
this.itemsCompleted.splice(0, this.itemsCompleted.length - this.config.show_completed + 1);
}
this.itemsCompleted.push(item);

this.hass.callService('homeassistant', 'update_entity', {
entity_id: this.config.entity,
});
});
}

itemUncomplete(item) {
let commands = [{
'type': 'item_uncomplete',
'uuid': this.getUUID(),
'args': {
'id': item.id,
},
}];

let t = this;
setTimeout(function () {
t.hass.callService('homeassistant', 'update_entity', {
entity_id: t.config.entity,
this.hass
.callService('rest_command', 'todoist', {
commands: JSON.stringify(commands),
})
.then(response => {
this.itemDeleteCompleted(item);

// this.hass.callService('homeassistant', 'update_entity', {
// entity_id: this.config.entity,
// });
});
}, 1000);
}

itemDelete(itemId) {
let date = new Date();

itemDelete(item) {
let commands = [{
'type': 'item_delete',
'uuid': this.random(1, 100) + '-' + (+date) + '-' + date.getMilliseconds(),
'uuid': this.getUUID(),
'args': {
'id': itemId,
'id': item.id,
},
}];

this.hass.callService('rest_command', 'todoist', {
commands: JSON.stringify(commands),
});

let t = this;
setTimeout(function () {
t.hass.callService('homeassistant', 'update_entity', {
entity_id: t.config.entity,
this.hass
.callService('rest_command', 'todoist', {
commands: JSON.stringify(commands),
})
.then(response => {
this.hass.callService('homeassistant', 'update_entity', {
entity_id: this.config.entity,
});
});
}, 1000);
}

itemDeleteCompleted(item) {
this.itemsCompleted = this.itemsCompleted.filter(v => {
return v.id != item.id;
});

this.hass.callService('homeassistant', 'update_entity', {
entity_id: this.config.entity,
});
}

render() {
Expand All @@ -332,15 +400,15 @@ class TodoistCard extends LitElement {
<div class="name">${state.attributes.friendly_name}</div>
</h1>`
: html``}
${items.length
? html`<div class="todoist-list">
${items.map(item => {
<div class="todoist-list">
${items.length
? items.map(item => {
return html`<div class="todoist-item">
${(this.config.show_item_close === undefined) || (this.config.show_item_close !== false)
? html`<ha-icon-button
icon="mdi:checkbox-marked-circle-outline"
class="todoist-item-close"
@click=${() => this.itemClose(item.id)}
@click=${() => this.itemClose(item)}
></ha-icon-button>`
: html`<ha-icon
icon="mdi:circle-medium"
Expand All @@ -350,13 +418,36 @@ class TodoistCard extends LitElement {
? html`<ha-icon-button
icon="mdi:trash-can-outline"
class="todoist-item-delete"
@click=${() => this.itemDelete(item.id)}
@click=${() => this.itemDelete(item)}
></ha-icon-button>`
: html``}
</div>`;
})}
</ul>`
: html`<div class="todoist-list-empty">No uncompleted tasks!</div>`}
})
: html`<div class="todoist-list-empty">No uncompleted tasks!</div>`}
${this.config.show_completed && this.itemsCompleted
? this.itemsCompleted.map(item => {
return html`<div class="todoist-item todoist-item-completed">
${(this.config.show_item_close === undefined) || (this.config.show_item_close !== false)
? html`<ha-icon-button
icon="mdi:plus-outline"
class="todoist-item-close"
@click=${() => this.itemUncomplete(item)}
></ha-icon-button>`
: html`<ha-icon
icon="mdi:circle-medium"
></ha-icon>`}
<div class="todoist-item-text">${item.content}</div>
${(this.config.show_item_delete === undefined) || (this.config.show_item_delete !== false)
? html`<ha-icon-button
icon="mdi:trash-can-outline"
class="todoist-item-delete"
@click=${() => this.itemDeleteCompleted(item)}
></ha-icon-button>`
: html``}
</div>`;
})
: html``}
</div>
${(this.config.show_item_add === undefined) || (this.config.show_item_add !== false)
? html`<input
id="todoist-card-item-add"
Expand Down Expand Up @@ -393,6 +484,10 @@ class TodoistCard extends LitElement {
line-height: 48px;
}
.todoist-item-completed {
color: #808080;
}
.todoist-item-text {
font-size: 16px;
white-space: nowrap;
Expand All @@ -403,11 +498,19 @@ class TodoistCard extends LitElement {
.todoist-item-close {
color: #008000;
}
.todoist-item-completed .todoist-item-close {
color: #808080;
}
.todoist-item-delete {
margin-left: auto;
color: #800000;
}
.todoist-item-completed .todoist-item-delete {
color: #808080;
}
.todoist-item-add {
width: calc(100% - 30px);
Expand Down

0 comments on commit 4d76b3f

Please sign in to comment.