Files
ClaudeProjectManager-main/gui/settings_dialog.py
Claude Project Manager ec92da8a64 Initial commit
2025-07-07 22:11:38 +02:00

314 Zeilen
11 KiB
Python

"""
Settings Dialog for the application
Allows users to configure various settings including view modes
"""
import customtkinter as ctk
from gui.styles import COLORS, FONTS
from utils.logger import logger
import json
from pathlib import Path
class SettingsDialog(ctk.CTkToplevel):
def __init__(self, parent, sidebar_view):
super().__init__(parent)
self.sidebar_view = sidebar_view
self.settings_file = Path.home() / ".claude_project_manager" / "ui_settings.json"
# Window setup
self.title("Einstellungen")
self.geometry("450x400")
self.resizable(False, False)
# Make modal
self.transient(parent)
self.grab_set()
# Load current settings
self.settings = self.load_settings()
# Setup UI
self.setup_ui()
# Center window
self.center_window()
# Focus
self.focus()
def setup_ui(self):
"""Setup the settings UI"""
# Main container
main_frame = ctk.CTkFrame(self, fg_color=COLORS['bg_primary'])
main_frame.pack(fill="both", expand=True, padx=20, pady=20)
# Title
title_label = ctk.CTkLabel(
main_frame,
text="⚙️ Einstellungen",
font=FONTS['subtitle'],
text_color=COLORS['text_primary']
)
title_label.pack(pady=(0, 20))
# Activity Server Section
activity_section = ctk.CTkFrame(main_frame, fg_color=COLORS['bg_secondary'])
activity_section.pack(fill="x", pady=(0, 15))
activity_header = ctk.CTkLabel(
activity_section,
text="👥 Team-Aktivität Server",
font=FONTS['body'],
text_color=COLORS['text_primary']
)
activity_header.pack(anchor="w", padx=15, pady=(10, 5))
# Server URL
url_label = ctk.CTkLabel(
activity_section,
text="Server URL:",
font=FONTS['small'],
text_color=COLORS['text_secondary']
)
url_label.pack(anchor="w", padx=30, pady=(5, 0))
self.server_url_var = ctk.StringVar(value=self.settings.get("activity_server_url", "http://91.99.192.14:3001"))
self.server_url_entry = ctk.CTkEntry(
activity_section,
textvariable=self.server_url_var,
width=300,
fg_color=COLORS['bg_primary']
)
self.server_url_entry.pack(padx=30, pady=(0, 5))
# API Key
api_label = ctk.CTkLabel(
activity_section,
text="API Key:",
font=FONTS['small'],
text_color=COLORS['text_secondary']
)
api_label.pack(anchor="w", padx=30, pady=(5, 0))
self.api_key_var = ctk.StringVar(value=self.settings.get("activity_api_key", ""))
self.api_key_entry = ctk.CTkEntry(
activity_section,
textvariable=self.api_key_var,
width=300,
fg_color=COLORS['bg_primary'],
show="*"
)
self.api_key_entry.pack(padx=30, pady=(0, 5))
# User Name
user_label = ctk.CTkLabel(
activity_section,
text="Benutzername:",
font=FONTS['small'],
text_color=COLORS['text_secondary']
)
user_label.pack(anchor="w", padx=30, pady=(5, 0))
self.user_name_var = ctk.StringVar(value=self.settings.get("activity_user_name", ""))
self.user_name_entry = ctk.CTkEntry(
activity_section,
textvariable=self.user_name_var,
width=300,
fg_color=COLORS['bg_primary']
)
self.user_name_entry.pack(padx=30, pady=(0, 5))
# Test connection button
test_btn = ctk.CTkButton(
activity_section,
text="Verbindung testen",
command=self.test_activity_connection,
fg_color=COLORS['bg_tile'],
hover_color=COLORS['bg_tile_hover'],
text_color=COLORS['text_primary'],
width=150
)
test_btn.pack(pady=(5, 10))
# Status label
self.connection_status_label = ctk.CTkLabel(
activity_section,
text="",
font=FONTS['small'],
text_color=COLORS['text_secondary']
)
self.connection_status_label.pack(pady=(0, 10))
# Buttons
button_frame = ctk.CTkFrame(main_frame, fg_color="transparent")
button_frame.pack(side="bottom", fill="x", pady=(20, 0))
# Apply button
apply_btn = ctk.CTkButton(
button_frame,
text="Anwenden",
command=self.apply_settings,
fg_color=COLORS['accent_primary'],
hover_color=COLORS['accent_hover'],
width=100
)
apply_btn.pack(side="right", padx=(5, 0))
# Cancel button
cancel_btn = ctk.CTkButton(
button_frame,
text="Abbrechen",
command=self.destroy,
fg_color=COLORS['bg_tile'],
hover_color=COLORS['bg_tile_hover'],
text_color=COLORS['text_primary'],
width=100
)
cancel_btn.pack(side="right")
def load_settings(self):
"""Load settings from file"""
try:
if self.settings_file.exists():
with open(self.settings_file, 'r') as f:
return json.load(f)
except Exception as e:
logger.error(f"Failed to load UI settings: {e}")
return {} # No settings currently
def save_settings(self):
"""Save settings to file"""
try:
self.settings_file.parent.mkdir(parents=True, exist_ok=True)
with open(self.settings_file, 'w') as f:
json.dump(self.settings, f, indent=2)
logger.info(f"Saved UI settings: {self.settings}")
except Exception as e:
logger.error(f"Failed to save UI settings: {e}")
def apply_settings(self):
"""Apply the selected settings"""
import uuid
from services.activity_sync import activity_service
# Get values
server_url = self.server_url_var.get().strip()
api_key = self.api_key_var.get().strip()
user_name = self.user_name_var.get().strip()
# Update settings
self.settings["activity_server_url"] = server_url
self.settings["activity_api_key"] = api_key
self.settings["activity_user_name"] = user_name
self.save_settings()
# Update activity service
activity_service.server_url = server_url
activity_service.api_key = api_key
activity_service.user_name = user_name
activity_service.user_id = self.settings.get("activity_user_id", str(uuid.uuid4()))
# Save user ID if newly generated
if "activity_user_id" not in self.settings:
self.settings["activity_user_id"] = activity_service.user_id
self.save_settings()
# Save activity settings
activity_service.save_settings()
# Reconnect if settings changed
if activity_service.connected:
activity_service.disconnect()
if activity_service.is_configured():
activity_service.connect()
logger.info("Activity server settings applied")
# Close dialog
self.destroy()
def test_activity_connection(self):
"""Test connection to activity server"""
import requests
from tkinter import messagebox
server_url = self.server_url_var.get().strip()
api_key = self.api_key_var.get().strip()
if not server_url:
self.connection_status_label.configure(
text="⚠️ Bitte Server URL eingeben",
text_color=COLORS['accent_warning']
)
return
self.connection_status_label.configure(
text="🔄 Teste Verbindung...",
text_color=COLORS['text_secondary']
)
self.update()
try:
# Try to connect to the server
response = requests.get(
f"{server_url}/health",
timeout=5,
headers={"Authorization": f"Bearer {api_key}"} if api_key else {}
)
if response.status_code == 200:
self.connection_status_label.configure(
text="✅ Verbindung erfolgreich!",
text_color=COLORS['accent_success']
)
logger.info(f"Activity server connection successful: {server_url}")
else:
self.connection_status_label.configure(
text=f"❌ Server antwortet mit Status {response.status_code}",
text_color=COLORS['accent_error']
)
logger.warning(f"Activity server returned status {response.status_code}")
except requests.exceptions.ConnectionError:
self.connection_status_label.configure(
text="❌ Server nicht erreichbar",
text_color=COLORS['accent_error']
)
logger.error(f"Activity server not reachable: {server_url}")
except requests.exceptions.Timeout:
self.connection_status_label.configure(
text="❌ Verbindung Timeout",
text_color=COLORS['accent_error']
)
logger.error(f"Activity server connection timeout: {server_url}")
except Exception as e:
self.connection_status_label.configure(
text=f"❌ Fehler: {str(e)}",
text_color=COLORS['accent_error']
)
logger.error(f"Activity server connection error: {e}")
def center_window(self):
"""Center the dialog on parent window"""
self.update_idletasks()
# Get parent window position
parent = self.master
parent_x = parent.winfo_x()
parent_y = parent.winfo_y()
parent_width = parent.winfo_width()
parent_height = parent.winfo_height()
# Get dialog size
dialog_width = self.winfo_width()
dialog_height = self.winfo_height()
# Calculate position
x = parent_x + (parent_width - dialog_width) // 2
y = parent_y + (parent_height - dialog_height) // 2
self.geometry(f"+{x}+{y}")