Sync to Pi: alle Features die live deployed sind
Aus dem Backup und Live-Pull vom Pi (10.11.3.144): - dashboard.py: Grid-Linien nur im freien Hintergrund (nicht durch Widgets) - templates/index.html: komplett redesigned mit Sidebar + Topbar + Toast + Modal - plugins/clock.py: responsive Layout (1x1 bis 4x4) - plugins/system.py, weather.py, minimax.py: mit Threshold-Bars und Color-Variants - plugins/base.py: NEU — fetch_with_retry Helper (3x retry mit backoff) + render_error_banner für fehlgeschlagene API-Plugins (grosses rotes "!" Icon mit Plugin-Name und Fehler statt Crash) Cleanup: Helfer-Chaos (renderer.py/2/3, design_a/b/c.html, clock_classic.py, 23x clock_*.png, alte test_*.py) wurde bereits im vorherigen Commit entfernt. Co-Authored-By: Hermes <noreply@hermes.local>
This commit is contained in:
co-authored by
Hermes
parent
af9a99a379
commit
1f142f5245
@@ -0,0 +1,117 @@
|
||||
"""Clock-Plugin: Uhrzeit + Datum, responsive fuer alle Slot-Groessen.
|
||||
|
||||
Layout-Strategie pro Slot-Groesse:
|
||||
is_small (1x1 ~200x120): nur Big-Time zentriert
|
||||
is_wide (4x1/2x1): Time links gross, Datum rechts klein
|
||||
sonst (1x2/2x2/4x4): Datum oben klein, Big-Time mittig, Wochentag unten
|
||||
"""
|
||||
import os, sys
|
||||
from datetime import datetime
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
from plugins.base import Widget
|
||||
from palette import (FG, INFO, ACCENT, BLUE, OK,
|
||||
measure, fit_font, centered_text,
|
||||
is_small, is_wide, is_tall)
|
||||
|
||||
|
||||
class Widget(Widget):
|
||||
name = "clock"
|
||||
label = "Uhrzeit / Datum"
|
||||
description = "Aktuelle Uhrzeit und Datum. Responsiv fuer 1x1 bis 4x4 Slots."
|
||||
category = "info"
|
||||
|
||||
config_schema = [
|
||||
{"key": "format_24h", "label": "24-Stunden-Format", "type": "bool", "default": True},
|
||||
{"key": "show_seconds", "label": "Sekunden anzeigen", "type": "bool", "default": False},
|
||||
{"key": "show_date", "label": "Datum anzeigen", "type": "bool", "default": True},
|
||||
{"key": "show_weekday", "label": "Wochentag anzeigen", "type": "bool", "default": True},
|
||||
{"key": "accent_color", "label": "Akzentfarbe",
|
||||
"type": "select",
|
||||
"choices": ["info", "blue", "accent", "ok", "warn", "alert"],
|
||||
"default": "info",
|
||||
"help": "Farbe fuer Datum und Wochentag"},
|
||||
{"key": "weekday_color", "label": "Wochentag-Farbe",
|
||||
"type": "select",
|
||||
"choices": ["accent", "blue", "info", "ok", "warn", "alert"],
|
||||
"default": "accent"},
|
||||
]
|
||||
default_config = {
|
||||
"format_24h": True, "show_seconds": False,
|
||||
"show_date": True, "show_weekday": True,
|
||||
"accent_color": "info", "weekday_color": "accent",
|
||||
}
|
||||
|
||||
def fetch(self):
|
||||
return {}
|
||||
|
||||
def render(self, draw, fonts, x, y, w, h):
|
||||
from palette import fill_for
|
||||
now = datetime.now()
|
||||
pad = 10
|
||||
|
||||
time_str = now.strftime("%H:%M:%S" if self.cfg("show_seconds") else "%H:%M")
|
||||
date_str = now.strftime("%d %b %Y")
|
||||
day_str = now.strftime("%A").upper()
|
||||
|
||||
accent = fill_for(self.cfg("accent_color", "info"))
|
||||
weekday_c = fill_for(self.cfg("weekday_color", "accent"))
|
||||
|
||||
# === Mini-Modus: 1x1 oder sehr klein ===
|
||||
if is_small(w, h):
|
||||
font = fit_font(draw, time_str, fonts, w - 2 * pad, h - 2 * pad)
|
||||
centered_text(draw, time_str, x, y, w, h, font, FG)
|
||||
return
|
||||
|
||||
# === Wide-Strip-Modus: 4x1 oder 2x1 ===
|
||||
if is_wide(w, h):
|
||||
# Big Time links
|
||||
font_time = fit_font(draw, time_str, fonts, w // 2 - 2 * pad, h - 2 * pad)
|
||||
centered_text(draw, time_str, x, y, w // 2, h, font_time, FG)
|
||||
# Datum + Wochentag rechts
|
||||
if self.cfg("show_date"):
|
||||
font_date = fit_font(draw, date_str, fonts, w // 2 - 2 * pad, h // 2 - 4)
|
||||
centered_text(draw, date_str, x + w // 2, y, w // 2, h // 2, font_date, accent)
|
||||
if self.cfg("show_weekday"):
|
||||
font_day = fit_font(draw, day_str, fonts, w // 2 - 2 * pad, h // 2 - 4)
|
||||
centered_text(draw, day_str, x + w // 2, y + h // 2, w // 2, h // 2, font_day, weekday_c)
|
||||
return
|
||||
|
||||
# === Tall-Modus: schmal aber hoch ===
|
||||
if is_tall(w, h):
|
||||
# Vertikal: Time oben, dann Date, dann Weekday
|
||||
font_time = fit_font(draw, time_str, fonts, w - 2 * pad, int(h * 0.45))
|
||||
centered_text(draw, time_str, x, y, w, int(h * 0.45), font_time, FG)
|
||||
if self.cfg("show_date"):
|
||||
font_date = fit_font(draw, date_str, fonts, w - 2 * pad, int(h * 0.25))
|
||||
centered_text(draw, date_str, x, y + int(h * 0.45), w, int(h * 0.25), font_date, accent)
|
||||
if self.cfg("show_weekday"):
|
||||
font_day = fit_font(draw, day_str, fonts, w - 2 * pad, int(h * 0.20))
|
||||
centered_text(draw, day_str, x, y + int(h * 0.70), w, int(h * 0.20), font_day, weekday_c)
|
||||
return
|
||||
|
||||
# === Standard-Modus: 2x2 oder groesser, quadratisch oder landscape ===
|
||||
# Drei Sektionen: Date (15%) | Time (60%) | Weekday (25%)
|
||||
date_h = int(h * 0.18) if self.cfg("show_date") else 0
|
||||
weekday_h = int(h * 0.18) if self.cfg("show_weekday") else 0
|
||||
time_h = h - date_h - weekday_h
|
||||
cur_y = y
|
||||
|
||||
if self.cfg("show_date"):
|
||||
font_date = fit_font(draw, date_str, fonts, w - 2 * pad, date_h - 4)
|
||||
centered_text(draw, date_str, x, cur_y, w, date_h, font_date, accent)
|
||||
cur_y += date_h
|
||||
|
||||
time_x = x
|
||||
time_w = w
|
||||
# Wenn weekday und date beide aus: Time zentriert ueber alles
|
||||
if not (self.cfg("show_date") or self.cfg("show_weekday")):
|
||||
time_y = y
|
||||
else:
|
||||
time_y = cur_y
|
||||
font_time = fit_font(draw, time_str, fonts, time_w - 2 * pad, time_h - 4)
|
||||
centered_text(draw, time_str, time_x, time_y, time_w, time_h, font_time, FG)
|
||||
cur_y += time_h
|
||||
|
||||
if self.cfg("show_weekday"):
|
||||
font_day = fit_font(draw, day_str, fonts, w - 2 * pad, weekday_h - 4)
|
||||
centered_text(draw, day_str, x, cur_y, w, weekday_h, font_day, weekday_c)
|
||||
Reference in New Issue
Block a user