Files
aza/AzA march 2026 - Kopie (5)/aza_whatsapp.py

358 lines
13 KiB
Python
Raw Normal View History

2026-03-25 13:42:48 +01:00
# -*- coding: utf-8 -*-
"""
AzA WhatsApp - WhatsApp Integration für Arztpraxis
"""
import os
import sys
import json
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
from datetime import datetime
# Konfigurationsdatei
CONFIG_FILENAME = "aza_whatsapp_config.json"
def _config_path():
return os.path.join(os.path.dirname(os.path.abspath(__file__)), CONFIG_FILENAME)
def load_whatsapp_config():
"""Lädt WhatsApp Konfiguration."""
try:
path = _config_path()
if os.path.isfile(path):
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except Exception:
pass
return {}
def save_whatsapp_config(data):
"""Speichert WhatsApp Konfiguration."""
try:
path = _config_path()
with open(path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
except Exception:
pass
def _load_font_sizes():
try:
p = os.path.join(os.path.dirname(os.path.abspath(__file__)), "aza_font_sizes.json")
if os.path.isfile(p):
with open(p, "r", encoding="utf-8") as f:
return json.load(f)
except Exception:
pass
return {}
def _save_font_size(key, size):
try:
d = _load_font_sizes()
d[key] = size
p = os.path.join(os.path.dirname(os.path.abspath(__file__)), "aza_font_sizes.json")
with open(p, "w", encoding="utf-8") as f:
json.dump(d, f, indent=2, ensure_ascii=False)
except Exception:
pass
def add_text_font_size_control(parent_frame, text_widget, initial_size=10, label="Aa", bg_color="#F5FCFF", save_key=None):
"""▲▼-Pfeile für Textfeld-Schriftgröße (520pt), unauffällig im Hintergrund."""
if save_key:
saved = _load_font_sizes().get(save_key)
if saved is not None:
initial_size = int(saved)
_size = [max(5, min(20, initial_size))]
_fg = "#8AAFC0"
_fg_hover = "#1a4d6d"
cf = tk.Frame(parent_frame, bg=bg_color, highlightthickness=0, bd=0)
cf.pack(side="right", padx=4)
tk.Label(cf, text=label, font=("Segoe UI", 8), bg=bg_color, fg=_fg).pack(side="left", padx=(0, 1))
size_lbl = tk.Label(cf, text=str(_size[0]), font=("Segoe UI", 8), bg=bg_color, fg=_fg, width=2, anchor="center")
size_lbl.pack(side="left")
def _apply(ns):
ns = max(5, min(20, ns))
_size[0] = ns
size_lbl.configure(text=str(ns))
text_widget.configure(font=("Segoe UI", ns))
if save_key:
_save_font_size(save_key, ns)
text_widget.configure(font=("Segoe UI", _size[0]))
btn_up = tk.Label(cf, text="\u25B2", font=("Segoe UI", 7), bg=bg_color, fg=_fg, cursor="hand2", bd=0, highlightthickness=0)
btn_up.pack(side="left", padx=(2, 0))
btn_down = tk.Label(cf, text="\u25BC", font=("Segoe UI", 7), bg=bg_color, fg=_fg, cursor="hand2", bd=0, highlightthickness=0)
btn_down.pack(side="left")
btn_up.bind("<Button-1>", lambda e: _apply(_size[0] + 1))
btn_down.bind("<Button-1>", lambda e: _apply(_size[0] - 1))
for w in (btn_up, btn_down):
w.bind("<Enter>", lambda e, ww=w: ww.configure(fg=_fg_hover))
w.bind("<Leave>", lambda e, ww=w: ww.configure(fg=_fg))
return _size
class WhatsAppApp:
def __init__(self, root):
self.root = root
self.root.title("AzA WhatsApp")
self.root.geometry("1000x600")
self.root.minsize(800, 500)
# Farben (WhatsApp-ähnlich)
self.bg_dark = "#075E54" # WhatsApp Dunkelgrün
self.bg_medium = "#128C7E" # WhatsApp Mittelgrün
self.bg_light = "#DCF8C6" # WhatsApp Hellgrün (eigene Nachricht)
self.bg_white = "#FFFFFF"
self.bg_chat = "#ECE5DD" # WhatsApp Chat-Hintergrund
self.fg_dark = "#2C3E50"
self.fg_light = "#FFFFFF"
self.root.configure(bg=self.bg_dark)
# Dummy-Daten
self.contacts = [
{"name": "Dr. Müller", "phone": "+41 79 123 45 67", "last_msg": "Termin bestätigt"},
{"name": "Patient Hans", "phone": "+41 78 234 56 78", "last_msg": "Vielen Dank!"},
{"name": "Apotheke Linden", "phone": "+41 44 123 45 67", "last_msg": "Rezept bereit"},
]
self.current_contact = None
self.messages = []
# Gespeicherte Geometrie laden
config = load_whatsapp_config()
saved_geom = config.get("geometry", "")
if saved_geom:
try:
self.root.geometry(saved_geom)
except:
pass
self.root.protocol("WM_DELETE_WINDOW", self._on_close)
self._build_ui()
def _on_close(self):
"""Speichert Geometrie beim Schließen."""
config = load_whatsapp_config()
config["geometry"] = self.root.geometry()
save_whatsapp_config(config)
self.root.destroy()
def _build_ui(self):
"""Baut die Benutzeroberfläche."""
# Toolbar
self._create_toolbar()
# Hauptbereich: 2 Spalten (Kontakte, Chat)
main_paned = ttk.PanedWindow(self.root, orient="horizontal")
main_paned.pack(fill="both", expand=True)
# Linke Spalte: Kontaktliste
left_frame = tk.Frame(main_paned, bg="#FFFFFF", width=300)
main_paned.add(left_frame, weight=1)
# Rechte Spalte: Chat
right_frame = tk.Frame(main_paned, bg=self.bg_chat)
main_paned.add(right_frame, weight=3)
self._create_contact_list(left_frame)
self._create_chat_area(right_frame)
# Statusleiste
self.status_var = tk.StringVar(value="Bereit")
status_bar = tk.Label(
self.root, textvariable=self.status_var,
bg=self.bg_dark, fg=self.fg_light,
font=("Segoe UI", 9), anchor="w", padx=10
)
status_bar.pack(side="bottom", fill="x")
def _create_toolbar(self):
"""Erstellt die Toolbar."""
toolbar = tk.Frame(self.root, bg=self.bg_dark, height=50)
toolbar.pack(side="top", fill="x")
toolbar.pack_propagate(False)
tk.Label(
toolbar, text="💬 WhatsApp", bg=self.bg_dark, fg=self.fg_light,
font=("Segoe UI", 14, "bold")
).pack(side="left", padx=20, pady=10)
btn_frame = tk.Frame(toolbar, bg=self.bg_dark)
btn_frame.pack(side="right", padx=20, pady=10)
self._create_toolbar_button(btn_frame, " Neuer Chat", self._new_chat).pack(side="left", padx=2)
self._create_toolbar_button(btn_frame, "🔍 Suchen", self._search_contacts).pack(side="left", padx=2)
def _create_toolbar_button(self, parent, text, command):
"""Erstellt einen Toolbar-Button."""
btn = tk.Button(
parent, text=text, command=command,
bg=self.bg_medium, fg=self.fg_light,
font=("Segoe UI", 10), relief="flat",
padx=12, pady=6, cursor="hand2"
)
def on_enter(e):
btn.configure(bg="#0E7A6E")
def on_leave(e):
btn.configure(bg=self.bg_medium)
btn.bind("<Enter>", on_enter)
btn.bind("<Leave>", on_leave)
return btn
def _create_contact_list(self, parent):
"""Erstellt die Kontaktliste."""
tk.Label(
parent, text="Chats", bg="#FFFFFF", fg=self.fg_dark,
font=("Segoe UI", 12, "bold"), anchor="w", padx=10
).pack(fill="x", pady=(10, 5))
# Listbox für Kontakte
list_frame = tk.Frame(parent, bg="#FFFFFF")
list_frame.pack(fill="both", expand=True, padx=5, pady=5)
scrollbar = tk.Scrollbar(list_frame)
scrollbar.pack(side="right", fill="y")
self.contact_listbox = tk.Listbox(
list_frame, font=("Segoe UI", 10),
relief="flat", bd=0, highlightthickness=0,
yscrollcommand=scrollbar.set, selectmode="single"
)
self.contact_listbox.pack(side="left", fill="both", expand=True)
scrollbar.config(command=self.contact_listbox.yview)
# Kontakte einfügen
for contact in self.contacts:
display = f"{contact['name']}\n{contact['last_msg']}"
self.contact_listbox.insert("end", display)
self.contact_listbox.insert("end", "") # Trenner
self.contact_listbox.bind("<<ListboxSelect>>", self._on_contact_select)
def _create_chat_area(self, parent):
"""Erstellt den Chat-Bereich."""
# Header
header_frame = tk.Frame(parent, bg="#EDEDED", height=60)
header_frame.pack(fill="x")
header_frame.pack_propagate(False)
self.chat_header_label = tk.Label(
header_frame, text="Wählen Sie einen Chat aus",
bg="#EDEDED", fg=self.fg_dark,
font=("Segoe UI", 12, "bold"), anchor="w", padx=15
)
self.chat_header_label.pack(fill="both", expand=True)
# Chat-Verlauf
chat_scroll_frame = tk.Frame(parent, bg=self.bg_chat)
chat_scroll_frame.pack(fill="both", expand=True, padx=10, pady=10)
chat_header = tk.Frame(chat_scroll_frame, bg=self.bg_chat)
chat_header.pack(fill="x", anchor="w")
self.chat_display = scrolledtext.ScrolledText(
chat_scroll_frame, wrap="word", font=("Segoe UI", 10),
relief="flat", bd=0, bg=self.bg_chat, state="disabled"
)
self.chat_display.pack(fill="both", expand=True)
add_text_font_size_control(chat_header, self.chat_display, initial_size=10, bg_color=self.bg_chat, save_key="whatsapp_chat")
# Eingabe-Bereich
input_frame = tk.Frame(parent, bg="#F0F0F0", height=60)
input_frame.pack(fill="x", padx=10, pady=(0, 10))
input_frame.pack_propagate(False)
self.message_entry = tk.Entry(
input_frame, font=("Segoe UI", 11),
relief="solid", bd=1
)
self.message_entry.pack(side="left", fill="both", expand=True, padx=(5, 5), pady=10)
self.message_entry.bind("<Return>", lambda e: self._send_message())
send_btn = tk.Button(
input_frame, text="📤", command=self._send_message,
bg=self.bg_medium, fg=self.fg_light,
font=("Segoe UI", 14), relief="flat",
width=3, cursor="hand2"
)
send_btn.pack(side="right", padx=(0, 5), pady=10)
def _on_contact_select(self, event):
"""Wird aufgerufen, wenn ein Kontakt ausgewählt wird."""
selection = self.contact_listbox.curselection()
if not selection:
return
idx = selection[0] // 2
if idx < len(self.contacts):
self.current_contact = self.contacts[idx]
self.chat_header_label.config(text=self.current_contact["name"])
self._load_messages()
def _load_messages(self):
"""Lädt Nachrichten für den aktuellen Kontakt."""
# Dummy-Nachrichten
self.messages = [
{"from": "me", "text": "Hallo, wie geht es Ihnen?", "time": "10:30"},
{"from": "them", "text": "Danke, gut! Ich hätte gerne einen Termin.", "time": "10:32"},
{"from": "me", "text": "Gerne, wann passt es Ihnen?", "time": "10:35"},
]
self.chat_display.configure(state="normal")
self.chat_display.delete("1.0", "end")
for msg in self.messages:
if msg["from"] == "me":
self.chat_display.insert("end", f"[{msg['time']}] Sie: {msg['text']}\n\n")
else:
self.chat_display.insert("end", f"[{msg['time']}] {self.current_contact['name']}: {msg['text']}\n\n")
self.chat_display.configure(state="disabled")
self.chat_display.see("end")
def _send_message(self):
"""Sendet eine Nachricht."""
if not self.current_contact:
messagebox.showinfo("Hinweis", "Bitte wählen Sie zuerst einen Chat aus.")
return
text = self.message_entry.get().strip()
if not text:
return
# Nachricht hinzufügen
now = datetime.now().strftime("%H:%M")
self.messages.append({"from": "me", "text": text, "time": now})
self.chat_display.configure(state="normal")
self.chat_display.insert("end", f"[{now}] Sie: {text}\n\n")
self.chat_display.configure(state="disabled")
self.chat_display.see("end")
self.message_entry.delete(0, "end")
self.status_var.set("Nachricht gesendet.")
def _new_chat(self):
"""Startet einen neuen Chat."""
messagebox.showinfo("Neuer Chat", "Neue Chat-Funktion wird in einer zukünftigen Version implementiert.")
def _search_contacts(self):
"""Durchsucht Kontakte."""
messagebox.showinfo("Suchen", "Suchfunktion wird in einer zukünftigen Version implementiert.")
def main():
root = tk.Tk()
app = WhatsAppApp(root)
root.mainloop()
if __name__ == "__main__":
main()