Fix Aktivitätenstatus
Dieser Commit ist enthalten in:
@ -2966,10 +2966,16 @@ class MainWindow:
|
||||
def update_activity_status(self):
|
||||
"""Periodic update of activity status"""
|
||||
from services.activity_sync import activity_service
|
||||
from utils.logger import logger
|
||||
|
||||
logger.debug("Periodic activity status update triggered")
|
||||
|
||||
if activity_service.connected:
|
||||
# Update display with current activities
|
||||
logger.debug(f"Updating activity display with {len(activity_service.activities)} activities")
|
||||
self.update_activity_display(activity_service.activities)
|
||||
else:
|
||||
logger.debug("Activity service not connected, skipping update")
|
||||
|
||||
# Schedule next update
|
||||
self.root.after(5000, self.update_activity_status) # Update every 5 seconds
|
||||
|
||||
@ -25,7 +25,9 @@ class ProjectTile(ctk.CTkFrame):
|
||||
width=TILE_SIZE['width'],
|
||||
height=TILE_SIZE['height'],
|
||||
fg_color=COLORS['bg_vps'] if is_vps else COLORS['bg_tile'],
|
||||
corner_radius=10
|
||||
corner_radius=10,
|
||||
border_width=3,
|
||||
border_color=COLORS['bg_vps'] if is_vps else COLORS['bg_tile']
|
||||
)
|
||||
|
||||
self.project = project
|
||||
@ -38,6 +40,9 @@ class ProjectTile(ctk.CTkFrame):
|
||||
self.is_vps = is_vps
|
||||
self.is_running = is_running
|
||||
self.is_selected = False
|
||||
self.activity_animation_id = None
|
||||
self.activity_pulse_value = 0
|
||||
self.has_team_activity = False
|
||||
|
||||
self.grid_propagate(False)
|
||||
self.setup_ui()
|
||||
@ -582,39 +587,52 @@ pause
|
||||
|
||||
def _start_activity(self):
|
||||
"""Start activity for this project"""
|
||||
# Use main_window reference if available
|
||||
if hasattr(self, 'main_window') and self.main_window:
|
||||
self.main_window.start_activity(self.project)
|
||||
return
|
||||
|
||||
# Otherwise try to find in widget hierarchy
|
||||
widget = self
|
||||
while widget:
|
||||
if hasattr(widget, 'start_activity'):
|
||||
widget.start_activity(self.project)
|
||||
return
|
||||
widget = widget.master if hasattr(widget, 'master') else None
|
||||
from services.activity_sync import activity_service
|
||||
|
||||
# If not found, log error
|
||||
logger.error("Could not find start_activity method in widget hierarchy")
|
||||
logger.info(f"Starting activity for project: {self.project.name}")
|
||||
|
||||
# Update UI optimistically immediately
|
||||
self.update_activity_status(True, activity_service.user_name, True)
|
||||
|
||||
success = activity_service.start_activity(
|
||||
self.project.name,
|
||||
self.project.path,
|
||||
self.project.description if hasattr(self.project, 'description') else ""
|
||||
)
|
||||
|
||||
logger.info(f"Activity start result for {self.project.name}: success={success}")
|
||||
|
||||
if not success:
|
||||
# Revert on failure
|
||||
logger.error(f"Failed to start activity for {self.project.name}, reverting UI")
|
||||
self.update_activity_status(False)
|
||||
from tkinter import messagebox
|
||||
messagebox.showerror(
|
||||
"Fehler",
|
||||
"Aktivität konnte nicht gestartet werden."
|
||||
)
|
||||
|
||||
def _stop_activity(self):
|
||||
"""Stop current activity"""
|
||||
# Use main_window reference if available
|
||||
if hasattr(self, 'main_window') and self.main_window:
|
||||
self.main_window.stop_activity()
|
||||
return
|
||||
|
||||
# Otherwise try to find in widget hierarchy
|
||||
widget = self
|
||||
while widget:
|
||||
if hasattr(widget, 'stop_activity'):
|
||||
widget.stop_activity()
|
||||
return
|
||||
widget = widget.master if hasattr(widget, 'master') else None
|
||||
from services.activity_sync import activity_service
|
||||
|
||||
# If not found, log error
|
||||
logger.error("Could not find stop_activity method in widget hierarchy")
|
||||
logger.info(f"Stopping activity for project: {self.project.name}")
|
||||
|
||||
# Update UI optimistically immediately
|
||||
self.update_activity_status(False)
|
||||
|
||||
success = activity_service.stop_activity()
|
||||
|
||||
logger.info(f"Activity stop result: success={success}")
|
||||
|
||||
if not success:
|
||||
# Revert on failure - check if we're still the active project
|
||||
current = activity_service.get_current_activity()
|
||||
if current and current.get('projectName') == self.project.name:
|
||||
logger.error(f"Failed to stop activity for {self.project.name}, reverting UI")
|
||||
self.update_activity_status(True, activity_service.user_name, True)
|
||||
else:
|
||||
logger.error(f"Failed to stop activity, but no current activity found")
|
||||
|
||||
def _toggle_activity(self):
|
||||
"""Toggle activity for this project"""
|
||||
@ -653,7 +671,17 @@ pause
|
||||
|
||||
def update_activity_status(self, is_active: bool = False, user_name: str = None, is_own_activity: bool = False):
|
||||
"""Update activity indicator on tile"""
|
||||
logger.debug(f"update_activity_status called for {self.project.name}: is_active={is_active}, user_name={user_name}, is_own_activity={is_own_activity}")
|
||||
|
||||
if is_active:
|
||||
# Start border animation for team activity
|
||||
if not is_own_activity:
|
||||
self.has_team_activity = True
|
||||
self._start_activity_animation()
|
||||
else:
|
||||
self.has_team_activity = False
|
||||
self._stop_activity_animation()
|
||||
|
||||
# Show indicator with appropriate color
|
||||
if is_own_activity:
|
||||
# Green for own activity
|
||||
@ -680,6 +708,10 @@ pause
|
||||
# Hide indicator
|
||||
self.activity_indicator.pack_forget()
|
||||
|
||||
# Stop border animation
|
||||
self.has_team_activity = False
|
||||
self._stop_activity_animation()
|
||||
|
||||
# Update activity button if exists
|
||||
if hasattr(self, 'activity_button'):
|
||||
self.activity_button.configure(text="▶")
|
||||
@ -725,7 +757,16 @@ pause
|
||||
"""Check if this project has active users"""
|
||||
from services.activity_sync import activity_service
|
||||
|
||||
# Get all activities for this project
|
||||
logger.debug(f"check_activity called for project: {self.project.name}")
|
||||
|
||||
# First check if this is our own current activity
|
||||
current_activity = activity_service.get_current_activity()
|
||||
is_own_current = (current_activity and
|
||||
current_activity.get('projectName') == self.project.name)
|
||||
|
||||
logger.debug(f"Current activity check - is_own_current: {is_own_current}, current_activity: {current_activity}")
|
||||
|
||||
# Get all activities for this project from server
|
||||
active_users = []
|
||||
is_own_activity = False
|
||||
has_other_users = False
|
||||
@ -740,13 +781,76 @@ pause
|
||||
else:
|
||||
has_other_users = True
|
||||
|
||||
logger.debug(f"Server activities - active_users: {active_users}, is_own_activity: {is_own_activity}, has_other_users: {has_other_users}")
|
||||
|
||||
# If we have a local current activity, ensure it's included
|
||||
if is_own_current:
|
||||
is_own_activity = True
|
||||
if activity_service.user_name not in active_users:
|
||||
active_users.append(activity_service.user_name)
|
||||
logger.debug(f"Added local user to active_users: {activity_service.user_name}")
|
||||
|
||||
if active_users:
|
||||
# Show indicator with all active users
|
||||
user_text = ", ".join(active_users)
|
||||
# If both own and others are active, show as others (orange) to indicate collaboration
|
||||
self.update_activity_status(True, user_text, is_own_activity and not has_other_users)
|
||||
final_is_own = is_own_activity and not has_other_users
|
||||
logger.info(f"Updating activity status for {self.project.name}: active=True, users={user_text}, is_own={final_is_own}")
|
||||
self.update_activity_status(True, user_text, final_is_own)
|
||||
else:
|
||||
logger.info(f"Updating activity status for {self.project.name}: active=False")
|
||||
self.update_activity_status(False)
|
||||
|
||||
def _start_activity_animation(self):
|
||||
"""Start animated border for team activity"""
|
||||
if self.activity_animation_id:
|
||||
return # Animation already running
|
||||
|
||||
def animate():
|
||||
if not self.has_team_activity:
|
||||
self.activity_animation_id = None
|
||||
return
|
||||
|
||||
# Calculate pulsing color
|
||||
self.activity_pulse_value = (self.activity_pulse_value + 5) % 100
|
||||
pulse = abs(50 - self.activity_pulse_value) / 50 # 0 to 1 pulsing
|
||||
|
||||
# Interpolate between orange and a brighter orange
|
||||
base_color = COLORS['accent_warning'] # Orange
|
||||
bright_factor = 0.3 + (0.7 * pulse) # Pulse between 0.3 and 1.0 brightness
|
||||
|
||||
# Create pulsing border color
|
||||
if base_color.startswith('#'):
|
||||
# Convert hex to RGB, apply brightness, convert back
|
||||
r = int(base_color[1:3], 16)
|
||||
g = int(base_color[3:5], 16)
|
||||
b = int(base_color[5:7], 16)
|
||||
|
||||
# Apply brightness
|
||||
r = min(255, int(r + (255 - r) * (1 - bright_factor)))
|
||||
g = min(255, int(g + (255 - g) * (1 - bright_factor)))
|
||||
b = min(255, int(b + (255 - b) * (1 - bright_factor)))
|
||||
|
||||
pulse_color = f"#{r:02x}{g:02x}{b:02x}"
|
||||
else:
|
||||
pulse_color = base_color
|
||||
|
||||
self.configure(border_color=pulse_color)
|
||||
|
||||
# Continue animation
|
||||
self.activity_animation_id = self.after(50, animate)
|
||||
|
||||
animate()
|
||||
|
||||
def _stop_activity_animation(self):
|
||||
"""Stop animated border"""
|
||||
if self.activity_animation_id:
|
||||
self.after_cancel(self.activity_animation_id)
|
||||
self.activity_animation_id = None
|
||||
|
||||
# Reset border to default
|
||||
default_color = COLORS['bg_vps'] if self.is_vps else COLORS['bg_tile']
|
||||
self.configure(border_color=default_color)
|
||||
|
||||
class AddProjectTile(ctk.CTkFrame):
|
||||
"""Special tile for adding new projects"""
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren