add settings for animation select

This commit is contained in:
2025-08-24 17:51:54 +02:00
parent 3528f5c7d3
commit d227e2f47c
9 changed files with 62 additions and 48 deletions

View File

@@ -195,6 +195,9 @@ class Msg:
"backup_mode_info": _("Backup Mode: You can start a backup here."),
"restore_mode_info": _("Restore Mode: You can start a restore here."),
"advanced_settings_title": _("Advanced Settings"),
"animation_settings_title": _("Animation Settings"),
"backup_animation_label": _("Backup/Restore Animation:"),
"calc_animation_label": _("Size Calculation Animation:"),
"advanced_settings_warning": _("WARNING: Changing these settings is recommended for experienced users only. Incorrect configurations can lead to an unreliable backup.\n\nThe backup destination is always excluded for security reasons and cannot be changed here."),
"exclude_system_folders": _("Exclude system folders"),
"in_backup": _("In Backup"),

View File

@@ -309,8 +309,11 @@ class MainApplication(tk.Tk):
# Explicitly get the theme's background color for the canvas
bg_color = self.style.lookup('TFrame', 'background')
# Get the animation type from settings, with a default
animation_type = self.config_manager.get_setting("backup_animation_type", "counter_arc")
self.animated_icon = AnimatedIcon(
self.action_frame, width=20, height=20, use_pillow=True, bg=bg_color)
self.action_frame, width=20, height=20, use_pillow=True, bg=bg_color, animation_type=animation_type)
self.animated_icon.pack(side=tk.LEFT, padx=5)
self.animated_icon.stop("DISABLE")

View File

@@ -78,10 +78,13 @@ class Actions:
}
self.app.drawing.redraw_left_canvas()
# Get the animation type from settings, with a default
animation_type = self.app.config_manager.get_setting("calculation_animation_type", "double_arc")
if self.app.calculating_animation:
self.app.calculating_animation.destroy()
self.app.calculating_animation = AnimatedIcon(
self.app.left_canvas, width=20, height=20, animation_type="counter_arc", use_pillow=True)
self.app.left_canvas, width=20, height=20, animation_type=animation_type, use_pillow=True)
self.app.calculating_animation.start()
self.app.drawing.redraw_left_canvas()

View File

@@ -7,17 +7,16 @@ import fnmatch
from app_config import AppConfig, Msg
class AdvancedSettingsFrame(tk.Toplevel):
def __init__(self, master, **kwargs):
def __init__(self, master, config_manager, app_instance, **kwargs):
super().__init__(master, **kwargs)
self.title(Msg.STR["advanced_settings_title"])
self.geometry("800x600")
self.app_config = AppConfig()
self.config_manager = config_manager
self.app_instance = app_instance
# --- Warning Label ---
warning_label = ttk.Label(self, text=Msg.STR["advanced_settings_warning"], wraplength=780, justify="center")
warning_label.pack(pady=10)
warning_label.pack(pady=10, fill=tk.X, padx=10)
# --- Treeview for system folder exclusion ---
self.tree_frame = ttk.LabelFrame(self, text=Msg.STR["exclude_system_folders"], padding=10)
@@ -33,6 +32,24 @@ class AdvancedSettingsFrame(tk.Toplevel):
self.tree.bind("<Button-1>", self._toggle_include_status)
# --- Animation Settings ---
animation_frame = ttk.LabelFrame(self, text="Animationseinstellungen", padding=10)
animation_frame.pack(fill=tk.X, padx=10, pady=5)
animation_types = ["counter_arc", "double_arc", "line", "blink"]
ttk.Label(animation_frame, text=Msg.STR["backup_animation_label"]).grid(row=0, column=0, sticky="w", pady=2)
self.backup_anim_var = tk.StringVar()
self.backup_anim_combo = ttk.Combobox(animation_frame, textvariable=self.backup_anim_var, values=animation_types, state="readonly")
self.backup_anim_combo.grid(row=0, column=1, sticky="ew", padx=5)
ttk.Label(animation_frame, text=Msg.STR["calc_animation_label"]).grid(row=1, column=0, sticky="w", pady=2)
self.calc_anim_var = tk.StringVar()
self.calc_anim_combo = ttk.Combobox(animation_frame, textvariable=self.calc_anim_var, values=animation_types, state="readonly")
self.calc_anim_combo.grid(row=1, column=1, sticky="ew", padx=5)
animation_frame.columnconfigure(1, weight=1)
# --- Action Buttons ---
button_frame = ttk.Frame(self)
button_frame.pack(pady=10)
@@ -41,9 +58,15 @@ class AdvancedSettingsFrame(tk.Toplevel):
ttk.Button(button_frame, text=Msg.STR["cancel"], command=self.destroy).pack(side=tk.LEFT, padx=5)
self._load_system_folders()
self._load_animation_settings()
def _load_animation_settings(self):
backup_anim = self.config_manager.get_setting("backup_animation_type", "counter_arc")
calc_anim = self.config_manager.get_setting("calculation_animation_type", "double_arc")
self.backup_anim_var.set(backup_anim)
self.calc_anim_var.set(calc_anim)
def _load_system_folders(self):
# Clear existing items
for i in self.tree.get_children():
self.tree.delete(i)
@@ -52,66 +75,50 @@ class AdvancedSettingsFrame(tk.Toplevel):
"/tmp", "/dev", "/run", "/mnt", "/proc", "/media", "/cdrom", "/var",
"/sbin.usr-is-merged", "/bin.usr-is-merged", "/lib.usr-is-merged", "/boot"
]
# Add patterns from standard exclude content
always_exclude.extend(AppConfig.STANDARD_EXCLUDE_CONTENT.splitlines())
# Load user exclude patterns
_, user_patterns = self._load_exclude_patterns()
items_to_display = {}
items_to_display = {} # Use a dictionary to avoid duplicates and easily manage items
# Add root directories
root_dir = Path("/")
for item in root_dir.iterdir():
if item.is_dir():
item_path_str = str(item.absolute())
if item_path_str in always_exclude or f"{item_path_str}/*" in always_exclude:
continue # Skip always excluded items
continue
is_user_excluded = f"{item_path_str}/*" in user_patterns
included_text = Msg.STR["no"] if is_user_excluded else Msg.STR["yes"]
items_to_display[item_path_str] = (included_text, item.name, item_path_str)
# Explicitly add or update the backup destination's root
app_instance = self.master.master.master # Assuming master is SettingsFrame, master.master is content_frame, master.master.master is MainApplication
if app_instance.destination_path:
backup_root_path = Path(f"/{app_instance.destination_path.strip('/').split('/')[0]}")
if self.app_instance and self.app_instance.destination_path:
backup_root_path = Path(f"/{self.app_instance.destination_path.strip('/').split('/')[0]}")
backup_root_path_str = str(backup_root_path.absolute())
# Set the backup destination to be always excluded
items_to_display[backup_root_path_str] = (Msg.STR["no"], backup_root_path.name, backup_root_path_str)
# Insert items into the treeview
for item_path_str in sorted(items_to_display.keys()):
tags = ()
if app_instance.destination_path and item_path_str == str(Path(f"/{app_instance.destination_path.strip('/').split('/')[0]}").absolute()):
tags = ("backup_dest_exclude",) # Add tag for backup destination
if self.app_instance and self.app_instance.destination_path and item_path_str == str(Path(f"/{self.app_instance.destination_path.strip('/').split('/')[0]}").absolute()):
tags = ("backup_dest_exclude",)
self.tree.insert("", "end", values=items_to_display[item_path_str], tags=tags)
def _toggle_include_status(self, event):
item_id = self.tree.identify_row(event.y)
if not item_id:
return
# Check if the item is the backup destination exclude
if "backup_dest_exclude" in self.tree.item(item_id, "tags"):
return # Do nothing if it's the backup destination exclude
return
current_values = self.tree.item(item_id, 'values')
current_status = current_values[0]
new_status = Msg.STR["yes"] if current_status == Msg.STR["no"] else Msg.STR["no"]
new_status = Msg.STR["yes"] if current_values[0] == Msg.STR["no"] else Msg.STR["no"]
self.tree.item(item_id, values=(new_status, current_values[1], current_values[2]))
def _apply_changes(self):
# Get all paths displayed in the tree
self.config_manager.set_setting("backup_animation_type", self.backup_anim_var.get())
self.config_manager.set_setting("calculation_animation_type", self.calc_anim_var.get())
tree_paths = set()
for item_id in self.tree.get_children():
values = self.tree.item(item_id, 'values')
tree_paths.add(values[2])
# Get the new excludes from the tree
new_excludes = []
for item_id in self.tree.get_children():
values = self.tree.item(item_id, 'values')
@@ -122,27 +129,21 @@ class AdvancedSettingsFrame(tk.Toplevel):
else:
new_excludes.append(path)
# Load existing patterns
existing_patterns = []
if AppConfig.USER_EXCLUDE_LIST_PATH.exists():
with open(AppConfig.USER_EXCLUDE_LIST_PATH, 'r') as f:
existing_patterns = [line.strip() for line in f if line.strip() and not line.startswith('#')]
# Preserve patterns that are not managed by this view
preserved_patterns = []
for pattern in existing_patterns:
# A bit tricky to match pattern to tree_paths, this is a simplification
# This assumes patterns are in the form of /path/* or /path
clean_pattern = pattern.replace('/*', '')
if clean_pattern not in tree_paths:
preserved_patterns.append(pattern)
# Combine preserved patterns with new excludes from this view
final_excludes = list(set(preserved_patterns + new_excludes))
# Handle backup destination separately to ensure it's always excluded
if self.master.master.master.destination_path:
backup_root_to_exclude = f"/{self.master.master.master.destination_path.strip('/').split('/')[0]}/*"
if self.app_instance and self.app_instance.destination_path:
backup_root_to_exclude = f"/{self.app_instance.destination_path.strip('/').split('/')[0]}/*"
if backup_root_to_exclude not in final_excludes:
final_excludes.append(backup_root_to_exclude)
@@ -152,10 +153,10 @@ class AdvancedSettingsFrame(tk.Toplevel):
self.destroy()
# Trigger recalculation
current_source = self.master.master.master.left_canvas_data.get('folder')
if current_source:
self.master.master.master.actions.on_sidebar_button_click(current_source)
if self.app_instance:
current_source = self.app_instance.left_canvas_data.get('folder')
if current_source:
self.app_instance.actions.on_sidebar_button_click(current_source)
def _load_exclude_patterns(self):
generated_patterns = []

View File

@@ -205,7 +205,11 @@ class SettingsFrame(ttk.Frame):
self.master.master.master.actions.on_sidebar_button_click(current_source)
def _open_advanced_settings(self):
advanced_settings_window = AdvancedSettingsFrame(self.master)
advanced_settings_window = AdvancedSettingsFrame(
self.master,
config_manager=self.master.master.master.config_manager,
app_instance=self.master.master.master
)
advanced_settings_window.grab_set()
def _toggle_hidden_files_view(self):