Files
Py-Backup/pyimage_ui/backup_content_frame.py
Désiré Werner Menrath 474930e6d0 feat(ui): Improve "Backup Content" view default behavior
Implements a more intuitive default view for the "Backup Content" screen based on user context.

- After a backup is completed, the "Backup Content" view will now automatically open the tab corresponding to the type of backup just performed (System or User).
- On a fresh application start, the "Backup Content" view will now always default to showing the "System" backups tab.
- This is achieved by adding state variables to the main app and modifying the navigation logic, while removing the previous behavior of saving the last-viewed tab to the config.
2025-09-09 02:54:34 +02:00

190 lines
7.8 KiB
Python

import tkinter as tk
from tkinter import ttk
import os
from shared_libs.animated_icon import AnimatedIcon
from core.pbp_app_config import Msg
from pyimage_ui.system_backup_content_frame import SystemBackupContentFrame
from pyimage_ui.user_backup_content_frame import UserBackupContentFrame
from shared_libs.logger import app_logger
from shared_libs.message import MessageDialog
class BackupContentFrame(ttk.Frame):
def __init__(self, master, backup_manager, actions, app, **kwargs):
super().__init__(master, **kwargs)
app_logger.log("BackupContentFrame: __init__ called")
self.backup_manager = backup_manager
self.actions = actions
self.app = app
self.base_backup_path = None
self.current_view_index = 0
self.viewing_encrypted = False
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
header_frame = ttk.Frame(self)
header_frame.grid(row=0, column=0, sticky=tk.NSEW)
top_nav_frame = ttk.Frame(header_frame)
top_nav_frame.pack(side=tk.LEFT)
self.nav_buttons_defs = [
(Msg.STR["system_backup_info"], lambda: self._switch_view(0)),
(Msg.STR["user_backup_info"], lambda: self._switch_view(1)),
]
self.nav_buttons = []
self.nav_progress_bars = []
for i, (text, command) in enumerate(self.nav_buttons_defs):
button_frame = ttk.Frame(top_nav_frame)
button_frame.pack(side=tk.LEFT, padx=5)
button = ttk.Button(button_frame, text=text,
command=command, style="TButton.Borderless.Round")
button.pack(side=tk.TOP)
self.nav_buttons.append(button)
progress_bar = ttk.Progressbar(
button_frame, orient="horizontal", length=50, mode="determinate", style="Small.Horizontal.TProgressbar")
progress_bar.pack_forget()
self.nav_progress_bars.append(progress_bar)
if i < len(self.nav_buttons_defs) - 1:
ttk.Separator(top_nav_frame, orient=tk.VERTICAL).pack(
side=tk.LEFT, fill=tk.Y, padx=2)
# Deletion Status UI
self.deletion_status_frame = ttk.Frame(header_frame)
self.deletion_status_frame.pack(side=tk.LEFT, padx=15)
bg_color = self.winfo_toplevel().style.lookup('TFrame', 'background')
self.deletion_animated_icon = AnimatedIcon(
self.deletion_status_frame, width=20, height=20, use_pillow=True, bg=bg_color, animation_type="blink")
self.deletion_animated_icon.pack(side=tk.LEFT, padx=5)
self.deletion_animated_icon.stop("DISABLE")
self.deletion_status_label = ttk.Label(
self.deletion_status_frame, text="", font=("Ubuntu", 10, "bold"))
self.deletion_status_label.pack(side=tk.LEFT, padx=5)
content_container = ttk.Frame(self)
content_container.grid(row=1, column=0, sticky="nsew")
content_container.grid_rowconfigure(0, weight=1)
content_container.grid_columnconfigure(0, weight=1)
self.system_backups_frame = SystemBackupContentFrame(
content_container, backup_manager, actions, parent_view=self)
self.user_backups_frame = UserBackupContentFrame(
content_container, backup_manager, actions, parent_view=self)
self.system_backups_frame.grid(row=0, column=0, sticky=tk.NSEW)
self.user_backups_frame.grid(row=0, column=0, sticky=tk.NSEW)
action_button_frame = ttk.Frame(self, padding=10)
action_button_frame.grid(row=2, column=0, sticky="ew")
self.restore_button = ttk.Button(
action_button_frame, text=Msg.STR["restore"], command=self._restore_selected, state="disabled")
self.restore_button.pack(side=tk.LEFT, padx=5)
self.delete_button = ttk.Button(
action_button_frame, text=Msg.STR["delete"], command=self._delete_selected, state="disabled")
self.delete_button.pack(side=tk.LEFT, padx=5)
self.edit_comment_button = ttk.Button(
action_button_frame, text=Msg.STR["comment"], command=self._edit_comment, state="disabled")
self.edit_comment_button.pack(side=tk.LEFT, padx=5)
self._switch_view(0)
def update_button_state(self, is_selected):
self.restore_button.config(
state="normal" if is_selected else "disabled")
self.delete_button.config(
state="normal" if is_selected else "disabled")
self.edit_comment_button.config(
state="normal" if is_selected else "disabled")
def _get_active_subframe(self):
return self.system_backups_frame if self.current_view_index == 0 else self.user_backups_frame
def _restore_selected(self):
self._get_active_subframe()._restore_selected()
def _delete_selected(self):
self._get_active_subframe()._delete_selected()
def _edit_comment(self):
self._get_active_subframe()._edit_comment()
def _switch_view(self, index):
self.current_view_index = index
self.update_nav_buttons(index)
if index == 0:
self.system_backups_frame.grid()
self.user_backups_frame.grid_remove()
else:
self.user_backups_frame.grid()
self.system_backups_frame.grid_remove()
self.update_button_state(False)
def update_nav_buttons(self, active_index):
for i, button in enumerate(self.nav_buttons):
if i == active_index:
button.configure(style="Toolbutton")
self.nav_progress_bars[i].pack(side=tk.BOTTOM, fill=tk.X)
self.nav_progress_bars[i]['value'] = 100
else:
button.configure(style="Gray.Toolbutton")
self.nav_progress_bars[i].pack_forget()
def show(self, backup_path, initial_tab_index=0):
app_logger.log(
f"BackupContentFrame: show called with path {backup_path}")
self.grid(row=2, column=0, sticky="nsew")
self.base_backup_path = backup_path
# Check if the destination is encrypted and trigger mount if necessary
is_encrypted = self.backup_manager.encryption_manager.is_encrypted(
backup_path)
self.viewing_encrypted = is_encrypted # Set this flag for remembering the view
pybackup_dir = os.path.join(backup_path, "pybackup")
if not os.path.isdir(pybackup_dir):
app_logger.log(
f"Backup path {pybackup_dir} does not exist or is not a directory.")
# Clear views if path is invalid
self.system_backups_frame.show(backup_path, [])
self.user_backups_frame.show(backup_path, [])
return
all_backups = self.backup_manager.list_all_backups(backup_path, mount_if_needed=True)
if all_backups:
system_backups, user_backups = all_backups
self.system_backups_frame.show(backup_path, system_backups)
self.user_backups_frame.show(backup_path, user_backups)
else:
# Handle case where inspection returns None (e.g. encrypted and mount_if_needed=False)
self.system_backups_frame.show(backup_path, [])
self.user_backups_frame.show(backup_path, [])
# Use the passed index to switch to the correct view
self.after(10, lambda: self._switch_view(initial_tab_index))
def hide(self):
self.grid_remove()
def show_deletion_status(self, text: str):
app_logger.log(f"Showing deletion status: {text}")
self.deletion_status_label.config(text=text)
self.deletion_animated_icon.start()
self.deletion_status_frame.pack(side=tk.LEFT, padx=15)
def hide_deletion_status(self):
app_logger.log("Hiding deletion status text.")
self.deletion_status_label.config(text="")
self.deletion_animated_icon.stop("DISABLE")