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.
190 lines
7.8 KiB
Python
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")
|