# -*- 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 (5–20pt), 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("", lambda e: _apply(_size[0] + 1)) btn_down.bind("", lambda e: _apply(_size[0] - 1)) for w in (btn_up, btn_down): w.bind("", lambda e, ww=w: ww.configure(fg=_fg_hover)) w.bind("", 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("", on_enter) btn.bind("", 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("<>", 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("", 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()