149 |
150 |
337 |
340 | Turn on
347 | Turn off
352 | Toggle
357 |
358 |
${
359 | this.entityState == "idle" ? "Set timer" : "Cancel timer"
360 | }
361 |
362 | `;
363 | }
364 |
365 | _handleTouchStart(event) {
366 | event.preventDefault();
367 | const touch = event.touches[0];
368 | this.startY = touch.clientY;
369 | this.lastMoveDeltaY = 0;
370 | }
371 |
372 | _handleTouchMove(event) {
373 | event.preventDefault();
374 |
375 | if (this.entityState == "idle") {
376 | const touch = event.changedTouches[0];
377 | const endY = touch.clientY;
378 | const deltaY = this.startY - endY;
379 | let scrollDirectionUpward;
380 |
381 | if (deltaY > 0) {
382 | scrollDirectionUpward = true;
383 | } else if (deltaY < 0) {
384 | scrollDirectionUpward = false;
385 | }
386 |
387 | if (Math.abs(deltaY) - this.lastMoveDeltaY >= 20) {
388 | this.swipeColumn(scrollDirectionUpward, event.currentTarget.id);
389 | this.lastMoveDeltaY = Math.abs(deltaY);
390 | }
391 | }
392 | }
393 |
394 | _startIntervalUpdater() {
395 | this.timerUpdateInterval = window.setInterval(() => {
396 | this._updateRemaningTime(
397 | this._hass.states[this.entity].attributes.finishing_at
398 | );
399 | }, 500);
400 | }
401 |
402 | _stopIntervalUpdater() {
403 | window.clearInterval(this.timerUpdateInterval);
404 | window.timerUpdateInterval = null;
405 | }
406 |
407 | connectedCallback() {
408 | super.connectedCallback();
409 |
410 | if (this.entityState == "set") {
411 | this._startIntervalUpdater();
412 | }
413 | }
414 |
415 | disconnectedCallback() {
416 | super.disconnectedCallback();
417 | window.clearInterval(this.timerUpdateInterval);
418 | }
419 |
420 | _updateRemaningTime(finishingAt) {
421 | const finishingTime = new Date(finishingAt);
422 | const remainingMs = finishingTime - new Date();
423 | const remainingH = Math.floor(remainingMs / (1000 * 60 * 60));
424 | const remainingM = Math.floor(remainingMs / (1000 * 60));
425 | const remainingS = Math.floor(remainingMs / 1000);
426 | const remainingTime = [
427 | remainingH,
428 | remainingM - remainingH * 60,
429 | remainingS - remainingM * 60,
430 | ];
431 |
432 | if (this.entityState == "idle") {
433 | this._stopIntervalUpdater();
434 | this.hoursColumnMoveIndex = 0;
435 | this.minutesColumnMoveIndex = 0;
436 | this.secondsColumnMoveIndex = 0;
437 |
438 | this._moveTimerColumn(this.hoursColumnMoveIndex, "hours-column");
439 | this._moveTimerColumn(this.minutesColumnMoveIndex, "minutes-column");
440 | this._moveTimerColumn(this.secondsColumnMoveIndex, "seconds-column");
441 | this.requestUpdate();
442 | return null;
443 | }
444 |
445 | this.hoursColumnMoveIndex = remainingTime[0];
446 | this.minutesColumnMoveIndex = remainingTime[1];
447 | this.secondsColumnMoveIndex = remainingTime[2];
448 |
449 | this._moveTimerColumn(this.hoursColumnMoveIndex, "hours-column");
450 | this._moveTimerColumn(this.minutesColumnMoveIndex, "minutes-column");
451 | this._moveTimerColumn(this.secondsColumnMoveIndex, "seconds-column");
452 | }
453 |
454 | _handleScroll(event) {
455 | if (this.entityState == "idle") {
456 | const columnWrapper = event.currentTarget;
457 | const columnWrapperId = columnWrapper.id;
458 | let indexChange;
459 |
460 | event.preventDefault();
461 |
462 | if (event.deltaY > 0) {
463 | indexChange = 1;
464 | } else if (event.deltaY < 0) {
465 | indexChange = -1;
466 | }
467 |
468 | let newIndex;
469 | switch (columnWrapperId) {
470 | case "hours-column":
471 | newIndex = this.hoursColumnMoveIndex + indexChange;
472 |
473 | if (newIndex < this.hoursMaxMoveIndex && newIndex >= 0) {
474 | this.hoursColumnMoveIndex = newIndex;
475 | this._moveTimerColumn(this.hoursColumnMoveIndex, columnWrapperId);
476 | }
477 | break;
478 | case "minutes-column":
479 | newIndex = this.minutesColumnMoveIndex + indexChange;
480 | if (newIndex < this.minutesMaxMoveIndex && newIndex >= 0) {
481 | this.minutesColumnMoveIndex = newIndex;
482 | this._moveTimerColumn(this.minutesColumnMoveIndex, columnWrapperId);
483 | }
484 | break;
485 | case "seconds-column":
486 | newIndex = this.secondsColumnMoveIndex + indexChange;
487 | if (newIndex < this.secondsMaxMoveIndex && newIndex >= 0) {
488 | this.secondsColumnMoveIndex = newIndex;
489 | this._moveTimerColumn(this.secondsColumnMoveIndex, columnWrapperId);
490 | }
491 | break;
492 | }
493 | }
494 | }
495 |
496 | swipeColumn(upwardDirection, columnWrapperId) {
497 | let indexChange;
498 | let newIndex;
499 |
500 | if (upwardDirection) {
501 | indexChange = 1;
502 | } else if (!upwardDirection) {
503 | indexChange = -1;
504 | }
505 |
506 | switch (columnWrapperId) {
507 | case "hours-column":
508 | newIndex = this.hoursColumnMoveIndex + indexChange;
509 | if (newIndex < this.hoursMaxMoveIndex && newIndex >= 0) {
510 | this.hoursColumnMoveIndex = newIndex;
511 | this._moveTimerColumn(this.hoursColumnMoveIndex, columnWrapperId);
512 | }
513 | break;
514 | case "minutes-column":
515 | newIndex = this.minutesColumnMoveIndex + indexChange;
516 | if (newIndex < this.minutesMaxMoveIndex && newIndex >= 0) {
517 | this.minutesColumnMoveIndex = newIndex;
518 | this._moveTimerColumn(this.minutesColumnMoveIndex, columnWrapperId);
519 | }
520 | break;
521 | case "seconds-column":
522 | newIndex = this.secondsColumnMoveIndex + indexChange;
523 | if (newIndex < this.secondsMaxMoveIndex && newIndex >= 0) {
524 | this.secondsColumnMoveIndex = newIndex;
525 | this._moveTimerColumn(this.secondsColumnMoveIndex, columnWrapperId);
526 | }
527 | break;
528 | }
529 | }
530 |
531 | _moveTimerColumn(columnMoveIndex, columnWrapperId) {
532 | const columnWrapper = this.shadowRoot.querySelector(
533 | `#${columnWrapperId} .timer-digit-column`
534 | );
535 | columnWrapper.style.transform = `translateY(-${columnMoveIndex * 55}px)`;
536 | }
537 |
538 | _setTimerAction(clickEvent) {
539 | if (this.entityState == "idle") {
540 | this.renderRoot.querySelectorAll(".timer-action").forEach((button) => {
541 | button.classList.remove("timer-action-active");
542 | });
543 | const button = clickEvent.currentTarget;
544 | button.classList.add("timer-action-active");
545 | this.timerAction = button.innerHTML;
546 | }
547 | }
548 |
549 | _submitAction(clickEvent) {
550 | if (this.entityState == "idle") {
551 | this._hass.callService("switch_timer", "set_timer", {
552 | entity_id: this.entity,
553 | action: this.timerAction,
554 | duration: `${String(this.hoursColumnMoveIndex).padStart(
555 | 2,
556 | "0"
557 | )}:${String(this.minutesColumnMoveIndex).padStart(2, "0")}:${String(
558 | this.secondsColumnMoveIndex
559 | ).padStart(2, "0")}`,
560 | });
561 |
562 | setTimeout(() => {
563 | this.requestUpdate();
564 | this._startIntervalUpdater();
565 | }, 200);
566 | setTimeout(() => {
567 | this._hass.callService("browser_mod", "close_popup", {
568 | target: "this",
569 | });
570 | }, 1500);
571 | } else if (this.entityState == "set") {
572 | this._stopIntervalUpdater();
573 | this._hass.callService("switch_timer", "cancel_timer", {
574 | entity_id: this.entity,
575 | });
576 |
577 | this.hoursColumnMoveIndex = 0;
578 | this.minutesColumnMoveIndex = 0;
579 | this.secondsColumnMoveIndex = 0;
580 | this._moveTimerColumn(this.hoursColumnMoveIndex, "hours-column");
581 | this._moveTimerColumn(this.minutesColumnMoveIndex, "minutes-column");
582 | this._moveTimerColumn(this.secondsColumnMoveIndex, "seconds-column");
583 | setTimeout(() => {
584 | this.requestUpdate();
585 | }, 200);
586 | }
587 | }
588 | setConfig(config) {
589 | if (!config.entity) {
590 | throw new Error("No timer entity supplied");
591 | } else if (!config.entity.startsWith("switch_timer.")) {
592 | throw new Error(
593 | "The supplied entity is not a valid 'switch_timer' entity"
594 | );
595 | }
596 | this.entity = config.entity;
597 | }
598 |
599 | getCardSize() {
600 | return 3;
601 | }
602 | }
603 | customElements.define("set-timer-popup-card", SetTimerCard);
604 |
--------------------------------------------------------------------------------