diff --git a/app.js b/app.js index 5a1f2e5..6cc5aac 100644 --- a/app.js +++ b/app.js @@ -224,9 +224,17 @@ class TeeTracker { this.charts = {}; this.currentBgImage = null; + // Tea Timer + this.timer = null; + this.timerSeconds = 180; // 3 minutes in seconds + this.timerRunning = false; + this.timerPaused = false; + this.remainingSeconds = 180; + // Initialize this.initStorage(); this.setupEventListeners(); + this.setupTimerListeners(); this.loadData().then(() => { this.renderAll(); this.initCharts(); @@ -742,6 +750,39 @@ class TeeTracker { // Nextcloud settings this.setupNextcloudListeners(); + + // Tea Timer controls + this.setupTimerListeners(); + } + + setupTimerListeners() { + // Timer control buttons + const startBtn = document.getElementById('timer-start'); + const pauseBtn = document.getElementById('timer-pause'); + const resetBtn = document.getElementById('timer-reset'); + const decreaseBtn = document.getElementById('timer-decrease'); + const increaseBtn = document.getElementById('timer-increase'); + const timerInput = document.getElementById('timer-input'); + + if (startBtn) { + startBtn.addEventListener('click', () => this.startTimer()); + } + if (pauseBtn) { + pauseBtn.addEventListener('click', () => this.pauseTimer()); + } + if (resetBtn) { + resetBtn.addEventListener('click', () => this.resetTimer()); + } + if (decreaseBtn) { + decreaseBtn.addEventListener('click', () => this.decreaseTimer()); + } + if (increaseBtn) { + increaseBtn.addEventListener('click', () => this.increaseTimer()); + } + if (timerInput) { + timerInput.addEventListener('change', (e) => this.updateTimerFromInput(e)); + timerInput.addEventListener('input', (e) => this.validateTimerInput(e)); + } } setupNextcloudListeners() { @@ -1890,6 +1931,172 @@ class TeeTracker { } } +// ============================================ +// Tea Timer Methods +// ============================================ + +TeeTracker.prototype.startTimer = function() { + if (this.timerRunning && !this.timerPaused) return; + + if (this.timerPaused) { + // Resume from paused state + this.timerPaused = false; + } else { + // Start new timer + const input = document.getElementById('timer-input'); + let minutes = parseInt(input.value) || 3; + + // Clamp to valid range + minutes = Math.max(1, Math.min(15, minutes)); + this.timerSeconds = minutes * 60; + this.remainingSeconds = this.timerSeconds; + input.value = minutes; + } + + this.timerRunning = true; + this.updateTimerButtons(); + this.updateTimerDisplay(); + + this.timer = setInterval(() => { + this.remainingSeconds--; + this.updateTimerDisplay(); + + if (this.remainingSeconds <= 0) { + this.stopTimer(); + this.showTimerNotification('⏰ Timer abgelaufen! Zeit für deinen Tee!'); + + // Play notification sound if possible + if (typeof Audio !== 'undefined') { + try { + const audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const oscillator = audioContext.createOscillator(); + const gainNode = audioContext.createGain(); + oscillator.connect(gainNode); + gainNode.connect(audioContext.destination); + oscillator.frequency.value = 800; + oscillator.type = 'sine'; + gainNode.gain.setValueAtTime(0.1, audioContext.currentTime); + oscillator.start(audioContext.currentTime); + oscillator.stop(audioContext.currentTime + 0.5); + } catch (e) { + console.log('Audio notification not supported'); + } + } + } + }, 1000); +}; + +TeeTracker.prototype.pauseTimer = function() { + if (!this.timerRunning || this.timerPaused) return; + + this.timerPaused = true; + this.timerRunning = false; + this.updateTimerButtons(); + + if (this.timer) { + clearInterval(this.timer); + this.timer = null; + } +}; + +TeeTracker.prototype.stopTimer = function() { + if (this.timer) { + clearInterval(this.timer); + this.timer = null; + } + this.timerRunning = false; + this.timerPaused = false; + this.updateTimerButtons(); +}; + +TeeTracker.prototype.resetTimer = function() { + this.stopTimer(); + const input = document.getElementById('timer-input'); + const minutes = parseInt(input.value) || 3; + this.timerSeconds = Math.max(1, Math.min(15, minutes)) * 60; + this.remainingSeconds = this.timerSeconds; + this.updateTimerDisplay(); + this.updateTimerButtons(); +}; + +TeeTracker.prototype.decreaseTimer = function() { + const input = document.getElementById('timer-input'); + let minutes = parseInt(input.value) || 3; + minutes = Math.max(1, minutes - 1); + input.value = minutes; + this.timerSeconds = minutes * 60; + this.remainingSeconds = this.timerSeconds; + this.updateTimerDisplay(); +}; + +TeeTracker.prototype.increaseTimer = function() { + const input = document.getElementById('timer-input'); + let minutes = parseInt(input.value) || 3; + minutes = Math.min(15, minutes + 1); + input.value = minutes; + this.timerSeconds = minutes * 60; + this.remainingSeconds = this.timerSeconds; + this.updateTimerDisplay(); +}; + +TeeTracker.prototype.updateTimerFromInput = function(e) { + let minutes = parseInt(e.target.value) || 3; + minutes = Math.max(1, Math.min(15, minutes)); + e.target.value = minutes; + this.timerSeconds = minutes * 60; + this.remainingSeconds = this.timerSeconds; + this.updateTimerDisplay(); +}; + +TeeTracker.prototype.validateTimerInput = function(e) { + let value = e.target.value; + // Remove non-numeric characters + value = value.replace(/\D/g, ''); + if (value === '') value = '3'; + let minutes = parseInt(value) || 3; + minutes = Math.max(1, Math.min(15, minutes)); + e.target.value = minutes; +}; + +TeeTracker.prototype.updateTimerDisplay = function() { + const display = document.getElementById('timer-display'); + if (!display) return; + + const minutes = Math.floor(this.remainingSeconds / 60); + const seconds = this.remainingSeconds % 60; + display.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; +}; + +TeeTracker.prototype.updateTimerButtons = function() { + const startBtn = document.getElementById('timer-start'); + const pauseBtn = document.getElementById('timer-pause'); + const resetBtn = document.getElementById('timer-reset'); + const decreaseBtn = document.getElementById('timer-decrease'); + const increaseBtn = document.getElementById('timer-increase'); + const timerInput = document.getElementById('timer-input'); + + if (startBtn) startBtn.disabled = this.timerRunning && !this.timerPaused; + if (pauseBtn) pauseBtn.disabled = !this.timerRunning || this.timerPaused; + if (resetBtn) resetBtn.disabled = false; + if (decreaseBtn) decreaseBtn.disabled = this.timerRunning && !this.timerPaused; + if (increaseBtn) increaseBtn.disabled = this.timerRunning && !this.timerPaused; + if (timerInput) timerInput.disabled = this.timerRunning && !this.timerPaused; +}; + +TeeTracker.prototype.showTimerNotification = function(message) { + const notification = document.getElementById('timer-notification'); + if (notification) { + notification.textContent = message; + notification.className = 'timer-notification success'; + notification.style.display = 'block'; + + // Hide after 5 seconds + setTimeout(() => { + notification.style.display = 'none'; + }, 5000); + } +}; + // Initialize the application let app; document.addEventListener('DOMContentLoaded', () => { diff --git a/index.html b/index.html index bbbcaad..e7f670b 100644 --- a/index.html +++ b/index.html @@ -43,6 +43,26 @@ + +