diff --git a/app.py b/app.py index 999f0e0..04a7915 100644 --- a/app.py +++ b/app.py @@ -197,14 +197,15 @@ def index(): current_lesson_title = "Unbekannte Lektion" if lessons and progress.current_text_index < len(lessons): lesson = lessons[progress.current_text_index] - current_lesson_title = lesson.get('description', f"Lektion {progress.current_text_index + 1}") + current_lesson_title = lesson.get('title', f"Lektion {progress.current_text_index + 1}") return render_template('index.html', current_text=current_text, current_position=progress.current_position, last_text=progress.last_text, lessons=lessons, - current_lesson_title=current_lesson_title) + current_lesson_title=current_lesson_title, + current_lesson_index=progress.current_text_index) except Exception as e: print(f"Fehler in index(): {e}") @@ -362,10 +363,10 @@ def calculate_statistics(user_input, current_text, elapsed_time): # Berechne Metriken basierend auf echter Zeit if total_chars > 0 and elapsed_time > 0: - # Zeichen pro Sekunde + # Zeichen pro Sekunde (auf eine Nachkommastelle gerundet) chars_per_second = total_chars / elapsed_time - # Wörter pro Minute (Annahme: 1 Wort = 5 Zeichen) - words_per_minute = (total_chars / 5) / (elapsed_time / 60) + # Wörter pro Minute gemäß Formel: (Gesamtzahl der korrekt getippten Zeichen/5)/((Zeit in Sekunden)/60) + words_per_minute = (correct_chars / 5) / (elapsed_time / 60) # Durchschnittliche Zeit pro Zeichen duration_per_char = elapsed_time / total_chars else: @@ -382,9 +383,9 @@ def calculate_statistics(user_input, current_text, elapsed_time): 'incorrect_chars': incorrect_chars, 'total_chars': total_chars, 'error_rate': round(error_rate, 1), - 'typing_speed': round(chars_per_second, 2), + 'typing_speed': round(chars_per_second, 1), # Auf eine Nachkommastelle 'duration_per_char': round(duration_per_char, 3), - 'words_per_minute': round(words_per_minute, 2), + 'words_per_minute': round(words_per_minute, 2), # Auf zwei Nachkommastellen 'accuracy': round(accuracy, 2) } @@ -414,7 +415,7 @@ def next_text(): # Bestimme den Titel der neuen Lektion new_lesson = lessons[progress.current_text_index] - lesson_title = new_lesson.get('description', f"Lektion {progress.current_text_index + 1}") + lesson_title = new_lesson.get('title', f"Lektion {progress.current_text_index + 1}") return jsonify({ 'text': new_lesson['text'], @@ -452,7 +453,7 @@ def set_lesson(): # Bestimme den Titel der neuen Lektion new_lesson = lessons[lesson_index] - lesson_title = new_lesson.get('description', f"Lektion {lesson_index + 1}") + lesson_title = new_lesson.get('title', f"Lektion {lesson_index + 1}") return jsonify({ 'text': new_lesson['text'], @@ -480,4 +481,4 @@ if __name__ == '__main__': print(f"Debug-Info verfügbar unter: http://127.0.0.1:5000/debug") print("=" * 50) - app.run(debug=True) + app.run(debug=True, host='0.0.0.0', port=5000) diff --git a/static/css/style.css b/static/css/style.css index 3160402..15b998c 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -1,6 +1,104 @@ body { background-color: #f8f9fa; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + transition: background-color 0.3s, color 0.3s; +} + +/* Dark Theme Styles */ +[data-bs-theme="dark"] { + --bs-body-bg: #121212; + --bs-body-color: #e0e0e0; + --bs-light: #1e1e1e; + --bs-dark: #f8f9fa; +} + +[data-bs-theme="dark"] body { + background-color: #121212; + color: #e0e0e0; +} + +[data-bs-theme="dark"] .bg-light { + background-color: #1e1e1e !important; +} + +[data-bs-theme="dark"] .card { + background-color: #1e1e1e; + color: #e0e0e0; + border-color: #333; +} + +[data-bs-theme="dark"] .card-header { + background-color: #0d6efd !important; + color: white; +} + +[data-bs-theme="dark"] .list-group-item { + background-color: #1e1e1e; + color: #e0e0e0; + border-color: #333; +} + +/* Light Mode für Text- und Eingabefelder */ +#target-text, +#user-input { + background-color: white; + color: #000; + border-color: #dee2e6; +} + +/* Dark Mode für Text- und Eingabefelder */ +[data-bs-theme="dark"] #target-text, +[data-bs-theme="dark"] #user-input { + background-color: #2d2d2d; + color: #e0e0e0; + border-color: #444; +} + +/* Verbesserte Lesbarkeit für Hervorhebungen im Dark-Mode */ +[data-bs-theme="dark"] .highlight-correct { + color: #4ade80; /* Helleres Grün für besseren Kontrast */ + font-weight: bold; +} + +[data-bs-theme="dark"] .highlight-incorrect { + color: #f87171; /* Helleres Rot für besseren Kontrast */ +} + +[data-bs-theme="dark"] .highlight-space, +[data-bs-theme="dark"] .highlight-tab, +[data-bs-theme="dark"] .highlight-newline { + color: #a0a0a0; /* Hellgrau für Sonderzeichen */ +} + +[data-bs-theme="dark"] .form-control { + background-color: #2d2d2d; + color: #e0e0e0; + border-color: #444; +} + +[data-bs-theme="dark"] .form-control:focus { + background-color: #2d2d2d; + color: #e0e0e0; + border-color: #0d6efd; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} + +[data-bs-theme="dark"] .lesson-link:hover { + background-color: #333; +} + +[data-bs-theme="dark"] .progress { + background-color: #2d2d2d; +} + +[data-bs-theme="dark"] .btn-outline-secondary { + color: #e0e0e0; + border-color: #6c757d; +} + +[data-bs-theme="dark"] .btn-outline-secondary:hover { + background-color: #6c757d; + color: #fff; } .card { @@ -113,3 +211,41 @@ body { font-size: 1rem; } } +/* Theme-Toggle-Button */ +#theme-toggle { + display: flex; + align-items: center; + justify-content: center; +} + +/* Zusätzliche Stile für die aktive Lektion */ +.lesson-link:hover { + background-color: #e9ecef; + border-radius: 3px; +} + +/* Stile für Lektionsnummern */ +.lesson-link { + display: flex; + align-items: center; + justify-content: center; + width: 100%; +} + +/* Helle Hintergrundfarbe für den Success-Button */ +.btn-success { + background-color: #90EE90 !important; + border-color: #90EE90 !important; + color: #006400 !important; +} + +[data-bs-theme="dark"] .btn-success { + background-color: #90EE90 !important; + border-color: #90EE90 !important; + color: #006400 !important; +} + +.bg-success { + background-color: #90EE90 !important; + color: #006400 !important; +} diff --git a/static/js/script.js b/static/js/script.js index 4a39e01..4be86bf 100644 --- a/static/js/script.js +++ b/static/js/script.js @@ -1,4 +1,36 @@ +// Theme Management +function initializeTheme() { + const savedTheme = localStorage.getItem('theme') || 'light'; + document.body.setAttribute('data-bs-theme', savedTheme); + updateThemeButton(savedTheme); +} + +function toggleTheme() { + const currentTheme = document.body.getAttribute('data-bs-theme'); + const newTheme = currentTheme === 'light' ? 'dark' : 'light'; + document.body.setAttribute('data-bs-theme', newTheme); + localStorage.setItem('theme', newTheme); + updateThemeButton(newTheme); +} + +function updateThemeButton(theme) { + const button = document.getElementById('theme-toggle'); + if (theme === 'dark') { + button.innerHTML = ''; + button.classList.remove('btn-outline-light'); + button.classList.add('btn-outline-warning'); + } else { + button.innerHTML = ''; + button.classList.remove('btn-outline-warning'); + button.classList.add('btn-outline-light'); + } +} + document.addEventListener('DOMContentLoaded', function() { + // Theme initialisieren + initializeTheme(); + document.getElementById('theme-toggle').addEventListener('click', toggleTheme); + const userInput = document.getElementById('user-input'); const targetText = document.getElementById('target-text'); const nextBtn = document.getElementById('next-btn'); @@ -28,14 +60,11 @@ document.addEventListener('DOMContentLoaded', function() { userInput.addEventListener('keydown', function(event) { if (!startTime && event.key.length === 1) { // Nur Buchstaben, Zahlen, etc. startTime = new Date(); - // Starte Timer für Echtzeit-Update - if (timerInterval) clearInterval(timerInterval); - timerInterval = setInterval(updateTimer, 100); } }); - // Aktualisiere die Statistik bei Eingabe - userInput.addEventListener('input', function() { + // Aktualisiere die Statistik bei jedem Tastendruck + userInput.addEventListener('keyup', function() { const userValue = this.value; const currentLine = lines[currentLineIndex]; updateStatistics(userValue, currentLine); @@ -49,11 +78,6 @@ document.addEventListener('DOMContentLoaded', function() { updateStatistics('', lines[currentLineIndex]); } else { // Lektion beendet - Statistik speichern - if (timerInterval) { - clearInterval(timerInterval); - timerInterval = null; - } - // Hier könnten wir die Statistik an den Server senden alert('Lektion beendet!'); // Setze zurück für nächste Lektion? // Oder automatisch zur nächsten Lektion? @@ -61,15 +85,20 @@ document.addEventListener('DOMContentLoaded', function() { } }); - // Timer für Echtzeit-Update der Statistik - function updateTimer() { - if (startTime) { - const userValue = userInput.value; - const currentLine = lines[currentLineIndex]; - updateStatistics(userValue, currentLine); - } + // Funktion zum Aktualisieren der Lektionsmarkierung + function updateLessonHighlight(lessonIndex) { + document.querySelectorAll('.lesson-link').forEach(link => { + const index = parseInt(link.getAttribute('data-lesson-index')); + if (index === lessonIndex) { + link.classList.add('fw-bold', 'text-danger'); + link.classList.remove('text-primary'); + } else { + link.classList.remove('fw-bold', 'text-danger'); + link.classList.add('text-primary'); + } + }); } - + // Event-Listener für Lektions-Links document.querySelectorAll('.lesson-link').forEach(link => { link.addEventListener('click', function() { @@ -103,6 +132,8 @@ document.addEventListener('DOMContentLoaded', function() { userInput.value = ''; userInput.focus(); updateStatistics('', lines[currentLineIndex]); + // Aktualisiere die Markierung der aktuellen Lektion + updateLessonHighlight(lessonIndex); } }) .catch(error => console.error('Fehler:', error)); @@ -135,6 +166,8 @@ document.addEventListener('DOMContentLoaded', function() { userInput.value = ''; userInput.focus(); // Fokus zurück auf Eingabefeld updateStatistics('', lines[currentLineIndex]); + // Aktualisiere die Markierung der aktuellen Lektion + updateLessonHighlight(data.index); }) .catch(error => console.error('Fehler:', error)); }); @@ -158,14 +191,14 @@ document.addEventListener('DOMContentLoaded', function() { // Statistik aktualisieren function updateStatistics(userInput, currentText) { - // Berechne verstrichene Zeit + // Berechne verstrichene Zeit nur wenn der Benutzer tippt let elapsedTime = 0; if (startTime) { const now = new Date(); elapsedTime = (now - startTime) / 1000; // in Sekunden } - // Sende Daten an den Server + // Sende Daten an den Server nur wenn der Benutzer tippt oder klickt fetch('/update_progress', { method: 'POST', headers: { diff --git a/templates/index.html b/templates/index.html index 79ad7d1..28d94ea 100644 --- a/templates/index.html +++ b/templates/index.html @@ -7,19 +7,40 @@ -
+