renema accurate to Incrementel
This commit is contained in:
@@ -264,7 +264,7 @@ class BackupManager:
|
||||
|
||||
if not latest_backup_path:
|
||||
self.logger.log(
|
||||
"No previous full backup found. Accurate incremental size cannot be estimated, returning 0.")
|
||||
"No previous full backup found. Incremental size cannot be estimated, returning 0.")
|
||||
return 0
|
||||
|
||||
command = []
|
||||
@@ -484,7 +484,7 @@ class BackupManager:
|
||||
final_user_list = []
|
||||
for source in sorted(user_backups_by_source.keys()):
|
||||
source_backups = user_backups_by_source[source]
|
||||
|
||||
|
||||
grouped_source_backups = []
|
||||
temp_group = []
|
||||
for backup in reversed(source_backups):
|
||||
@@ -500,8 +500,9 @@ class BackupManager:
|
||||
if temp_group:
|
||||
grouped_source_backups.append(temp_group)
|
||||
|
||||
grouped_source_backups.sort(key=lambda g: g[0]['datetime'], reverse=True)
|
||||
|
||||
grouped_source_backups.sort(
|
||||
key=lambda g: g[0]['datetime'], reverse=True)
|
||||
|
||||
for group in grouped_source_backups:
|
||||
final_user_list.extend(group)
|
||||
|
||||
|
@@ -265,12 +265,12 @@ class Msg:
|
||||
"backup_finished_with_warnings": _("Backup finished with warnings. See log for details."),
|
||||
"backup_failed": _("Backup failed. See log for details."),
|
||||
"backup_cancelled_by_user": _("Backup was cancelled by the user."),
|
||||
"accurate_size_cb_label": _("Accurate inkrem. size"),
|
||||
"accurate_size_info_label": _("(Calculation may take longer)"),
|
||||
"accurate_size_success": _("Accurate size calculated successfully."),
|
||||
"accurate_size_failed": _("Failed to calculate size. See log for details."),
|
||||
"incremental_size_cb_label": _("Inkrem. size"),
|
||||
"incremental_size_info_label": _("(Calculation may take longer)"),
|
||||
"incremental_size_success": _("Incremental size calculated successfully."),
|
||||
"incremental_size_failed": _("Failed to calculate size. See log for details."),
|
||||
"please_wait": _("Please wait, calculating..."),
|
||||
"accurate_calc_cancelled": _("Calculate size cancelled."),
|
||||
"incremental_calc_cancelled": _("Calculate size cancelled."),
|
||||
"add_to_exclude_list": _("Add to exclude list"),
|
||||
"exclude_dialog_text": _("Do you want to add a folder or a file?"),
|
||||
"add_folder_button": _("Folder"),
|
||||
@@ -278,6 +278,9 @@ class Msg:
|
||||
"system_excludes": _("System Excludes"),
|
||||
"manual_excludes": _("Manual Excludes"),
|
||||
"manual_excludes_info": _("Here, manually add files or folders to be excluded from the backup. Each entry should be on a new line."),
|
||||
"sudoers_info_text": _(f"To run automated backups, an administrator must create a file in /etc/sudoers.d/\n"
|
||||
f"with the following content (replace 'user' with the correct username):\n"
|
||||
f"user ALL=(ALL) NOPASSWD: /path/to/pybackup-cli.py"),
|
||||
|
||||
# Menus
|
||||
"file_menu": _("File"),
|
||||
|
42
main_app.py
42
main_app.py
@@ -115,7 +115,7 @@ class MainApplication(tk.Tk):
|
||||
self.calculation_thread = None
|
||||
self.calculation_stop_event = None
|
||||
self.source_larger_than_partition = False
|
||||
self.accurate_calculation_running = False
|
||||
self.incremental_calculation_running = False
|
||||
self.is_first_backup = False
|
||||
|
||||
self.left_canvas_animation = None
|
||||
@@ -473,16 +473,16 @@ class MainApplication(tk.Tk):
|
||||
self.time_info_frame, text="Ende: --:--:--")
|
||||
self.end_time_label.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
accurate_size_frame = ttk.Frame(self.time_info_frame)
|
||||
accurate_size_frame.pack(side=tk.LEFT, padx=20)
|
||||
incremental_size_frame = ttk.Frame(self.time_info_frame)
|
||||
incremental_size_frame.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
self.accurate_size_btn = ttk.Button(accurate_size_frame, text=Msg.STR["accurate_size_cb_label"],
|
||||
command=self.actions.on_accurate_size_calc)
|
||||
self.accurate_size_btn.pack(side=tk.LEFT, padx=5)
|
||||
self.incremental_size_btn = ttk.Button(incremental_size_frame, text=Msg.STR["incremental_size_cb_label"],
|
||||
command=self.actions.on_incremental_size_calc)
|
||||
self.incremental_size_btn.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
accurate_size_info_label = ttk.Label(
|
||||
accurate_size_frame, text=Msg.STR["accurate_size_info_label"], foreground="gray")
|
||||
accurate_size_info_label.pack(side=tk.LEFT)
|
||||
incremental_size_info_label = ttk.Label(
|
||||
incremental_size_frame, text=Msg.STR["incremental_size_info_label"], foreground="gray")
|
||||
incremental_size_info_label.pack(side=tk.LEFT)
|
||||
|
||||
checkbox_frame = ttk.Frame(self.info_checkbox_frame)
|
||||
checkbox_frame.pack(fill=tk.X, pady=5)
|
||||
@@ -530,9 +530,9 @@ class MainApplication(tk.Tk):
|
||||
progress_container, orient="horizontal", length=100, mode="determinate")
|
||||
self.task_progress.grid(row=1, column=0, sticky="ew", pady=(5, 0))
|
||||
|
||||
self.start_pause_button = ttk.Button(
|
||||
self.start_cancel_button = ttk.Button(
|
||||
self.action_frame, text=Msg.STR["start"], command=self.actions.toggle_start_cancel, state="disabled")
|
||||
self.start_pause_button.grid(row=0, column=2, rowspan=2, padx=5)
|
||||
self.start_cancel_button.grid(row=0, column=2, rowspan=2, padx=5)
|
||||
|
||||
def on_closing(self):
|
||||
self.config_manager.set_setting(
|
||||
@@ -597,9 +597,9 @@ class MainApplication(tk.Tk):
|
||||
button_text, folder_size, mode_when_started = message
|
||||
|
||||
if mode_when_started != self.mode:
|
||||
if calc_type == 'accurate_incremental':
|
||||
if calc_type == 'incremental_incremental':
|
||||
self.actions._set_ui_state(True)
|
||||
self.accurate_calculation_running = False
|
||||
self.incremental_calculation_running = False
|
||||
self.animated_icon.stop("DISABLE")
|
||||
else:
|
||||
current_folder_name = self.left_canvas_data.get(
|
||||
@@ -639,7 +639,7 @@ class MainApplication(tk.Tk):
|
||||
|
||||
self.drawing.update_target_projection()
|
||||
|
||||
if calc_type == 'accurate_incremental':
|
||||
if calc_type == 'incremental_incremental':
|
||||
self.source_size_bytes = folder_size
|
||||
self.drawing.update_target_projection()
|
||||
self.animated_icon.stop("DISABLE")
|
||||
@@ -647,16 +647,16 @@ class MainApplication(tk.Tk):
|
||||
self.task_progress.config(
|
||||
mode="determinate", value=0)
|
||||
self.actions._set_ui_state(True)
|
||||
self.accurate_calculation_running = False
|
||||
self.start_pause_button.config(
|
||||
self.incremental_calculation_running = False
|
||||
self.start_cancel_button.config(
|
||||
text=Msg.STR["start"])
|
||||
if status == 'success':
|
||||
self.info_label.config(
|
||||
text=Msg.STR["accurate_size_success"], foreground="#0078d7")
|
||||
text=Msg.STR["incremental_size_success"], foreground="#0078d7")
|
||||
self.current_file_label.config(text="")
|
||||
else:
|
||||
self.info_label.config(
|
||||
text=Msg.STR["accurate_size_failed"], foreground="#D32F2F")
|
||||
text=Msg.STR["incremental_size_failed"], foreground="#D32F2F")
|
||||
self.current_file_label.config(text="")
|
||||
|
||||
elif isinstance(message, tuple) and len(message) == 2:
|
||||
@@ -679,7 +679,7 @@ class MainApplication(tk.Tk):
|
||||
else:
|
||||
self.task_progress.stop()
|
||||
elif message_type == 'cancel_button_state':
|
||||
self.start_pause_button.config(state=value)
|
||||
self.start_cancel_button.config(state=value)
|
||||
elif message_type == 'current_path':
|
||||
self.current_backup_path = value
|
||||
app_logger.log(f"Set current backup path to: {value}")
|
||||
@@ -692,7 +692,7 @@ class MainApplication(tk.Tk):
|
||||
self.destination_path, initial_tab_index=active_tab_index)
|
||||
elif message_type == 'error':
|
||||
self.animated_icon.stop("DISABLE")
|
||||
self.start_pause_button["text"] = "Start"
|
||||
self.start_cancel_button["text"] = "Start"
|
||||
self.backup_is_running = False
|
||||
elif message_type == 'completion':
|
||||
status_info = value
|
||||
@@ -721,7 +721,7 @@ class MainApplication(tk.Tk):
|
||||
pass
|
||||
|
||||
self.animated_icon.stop("DISABLE")
|
||||
self.start_pause_button["text"] = "Start"
|
||||
self.start_cancel_button["text"] = "Start"
|
||||
self.task_progress["value"] = 0
|
||||
self.current_file_label.config(text="")
|
||||
|
||||
|
@@ -74,7 +74,7 @@ class Actions:
|
||||
self.app.compressed_cb.config(state="normal")
|
||||
self.app.encrypted_cb.config(state="normal")
|
||||
self.app.test_run_cb.config(state="normal")
|
||||
self.app.accurate_size_btn.config(state="normal")
|
||||
self.app.incremental_size_btn.config(state="normal")
|
||||
|
||||
# Apply specific logic based on current states
|
||||
if self.app.compressed_var.get():
|
||||
@@ -85,8 +85,8 @@ class Actions:
|
||||
# If compressed, cannot be encrypted
|
||||
self.app.encrypted_var.set(False)
|
||||
self.app.encrypted_cb.config(state="disabled")
|
||||
# Accurate size not applicable for compressed
|
||||
self.app.accurate_size_btn.config(state="disabled")
|
||||
# Incremental size not applicable for compressed
|
||||
self.app.incremental_size_btn.config(state="disabled")
|
||||
elif self.app.encrypted_var.get():
|
||||
# If encrypted, cannot be compressed
|
||||
self.app.compressed_var.set(False)
|
||||
@@ -113,16 +113,16 @@ class Actions:
|
||||
def handle_encryption_change(self):
|
||||
self._refresh_backup_options_ui()
|
||||
|
||||
def on_accurate_size_calc(self):
|
||||
def on_incremental_size_calc(self):
|
||||
|
||||
if self.app.calculation_thread and self.app.calculation_thread.is_alive():
|
||||
self.app.calculation_stop_event.set()
|
||||
app_logger.log("Stopping previous size calculation.")
|
||||
|
||||
app_logger.log("Accurate incremental size calculation requested.")
|
||||
self.app.accurate_calculation_running = True
|
||||
app_logger.log("Incremental size calculation requested.")
|
||||
self.app.incremental_calculation_running = True
|
||||
self._set_ui_state(False, keep_cancel_enabled=True)
|
||||
self.app.start_pause_button.config(text=Msg.STR["cancel_backup"])
|
||||
self.app.start_cancel_button.config(text=Msg.STR["cancel_backup"])
|
||||
|
||||
self.app.drawing.reset_projection_canvases()
|
||||
|
||||
@@ -142,9 +142,9 @@ class Actions:
|
||||
|
||||
if not folder_path or not button_text:
|
||||
app_logger.log(
|
||||
"Cannot start accurate calculation, source folder info missing.")
|
||||
"Cannot start incremental calculation, source folder info missing.")
|
||||
self._set_ui_state(True)
|
||||
self.app.accurate_calculation_running = False
|
||||
self.app.incremental_calculation_running = False
|
||||
self.app.animated_icon.stop("DISABLE")
|
||||
return
|
||||
|
||||
@@ -180,9 +180,9 @@ class Actions:
|
||||
app_logger.log(f"Error during threaded_incremental_calc: {e}")
|
||||
status = 'failure'
|
||||
finally:
|
||||
if self.app.accurate_calculation_running:
|
||||
if self.app.incremental_calculation_running:
|
||||
self.app.queue.put(
|
||||
(button_text, size, self.app.mode, 'accurate_incremental', status))
|
||||
(button_text, size, self.app.mode, 'incremental_incremental', status))
|
||||
|
||||
self.app.calculation_thread = threading.Thread(
|
||||
target=threaded_incremental_calc)
|
||||
@@ -190,9 +190,9 @@ class Actions:
|
||||
self.app.calculation_thread.start()
|
||||
|
||||
def on_sidebar_button_click(self, button_text):
|
||||
if self.app.backup_is_running or self.app.accurate_calculation_running:
|
||||
if self.app.backup_is_running or self.app.incremental_calculation_running:
|
||||
app_logger.log(
|
||||
"Action blocked: Backup or accurate calculation is in progress.")
|
||||
"Action blocked: Backup or incremental calculation is in progress.")
|
||||
return
|
||||
|
||||
self.app.drawing.reset_projection_canvases()
|
||||
@@ -214,7 +214,7 @@ class Actions:
|
||||
if not folder_path or not folder_path.exists():
|
||||
print(
|
||||
f"Folder not found for {canonical_key} (Path: {folder_path})")
|
||||
self.app.start_pause_button.config(state="disabled")
|
||||
self.app.start_cancel_button.config(state="disabled")
|
||||
return
|
||||
|
||||
if self.app.mode == 'restore':
|
||||
@@ -245,7 +245,7 @@ class Actions:
|
||||
self.app._update_sync_mode_display()
|
||||
|
||||
def _start_left_canvas_calculation(self, button_text, folder_path, icon_name, extra_info):
|
||||
self.app.start_pause_button.config(state="disabled")
|
||||
self.app.start_cancel_button.config(state="disabled")
|
||||
if self.app.mode == 'backup' and not self.app.destination_path:
|
||||
self.app.left_canvas_data.update({
|
||||
'icon': icon_name,
|
||||
@@ -386,7 +386,7 @@ class Actions:
|
||||
self.app.config_manager.set_setting(
|
||||
"restore_source_path", path)
|
||||
self.app.drawing.calculate_restore_folder_size()
|
||||
self.app.start_pause_button.config(state="normal")
|
||||
self.app.start_cancel_button.config(state="normal")
|
||||
|
||||
except FileNotFoundError:
|
||||
with message_box_animation(self.app.animated_icon):
|
||||
@@ -416,7 +416,7 @@ class Actions:
|
||||
settings_frame.load_and_display_excludes()
|
||||
settings_frame._load_hidden_files()
|
||||
self.app.destination_path = None
|
||||
self.app.start_pause_button.config(state="disabled")
|
||||
self.app.start_cancel_button.config(state="disabled")
|
||||
|
||||
self.app.backup_left_canvas_data.clear()
|
||||
self.app.backup_right_canvas_data.clear()
|
||||
@@ -499,17 +499,17 @@ class Actions:
|
||||
self.app.test_run_cb,
|
||||
self.app.bypass_security_cb
|
||||
]
|
||||
self.app.accurate_size_btn.config(state="disabled")
|
||||
self.app.incremental_size_btn.config(state="disabled")
|
||||
for cb in checkboxes:
|
||||
cb.config(state="disabled")
|
||||
|
||||
if keep_cancel_enabled:
|
||||
self.app.start_pause_button.config(state="normal")
|
||||
self.app.start_cancel_button.config(state="normal")
|
||||
|
||||
def toggle_start_cancel(self):
|
||||
if self.app.accurate_calculation_running:
|
||||
app_logger.log("Accurate size calculation cancelled by user.")
|
||||
self.app.accurate_calculation_running = False
|
||||
if self.app.incremental_calculation_running:
|
||||
app_logger.log("Incremental size calculation cancelled by user.")
|
||||
self.app.incremental_calculation_running = False
|
||||
|
||||
self.app.animated_icon.stop("DISABLE")
|
||||
if self.app.left_canvas_animation:
|
||||
@@ -520,8 +520,8 @@ class Actions:
|
||||
self.app.task_progress.stop()
|
||||
self.app.task_progress.config(mode="determinate", value=0)
|
||||
self.app.info_label.config(
|
||||
text=Msg.STR["accurate_calc_cancelled"], foreground="#E8740C")
|
||||
self.app.start_pause_button.config(text=Msg.STR["start"])
|
||||
text=Msg.STR["incremental_calc_cancelled"], foreground="#E8740C")
|
||||
self.app.start_cancel_button.config(text=Msg.STR["start"])
|
||||
self._set_ui_state(True)
|
||||
return
|
||||
|
||||
@@ -571,11 +571,11 @@ class Actions:
|
||||
self.app.current_backup_path = None
|
||||
|
||||
self.app.backup_is_running = False
|
||||
self.app.start_pause_button["text"] = Msg.STR["start"]
|
||||
self.app.start_cancel_button["text"] = Msg.STR["start"]
|
||||
self._set_ui_state(True)
|
||||
|
||||
else:
|
||||
if self.app.start_pause_button['state'] == 'disabled':
|
||||
if self.app.start_cancel_button['state'] == 'disabled':
|
||||
return
|
||||
|
||||
self.app.backup_is_running = True
|
||||
@@ -588,7 +588,7 @@ class Actions:
|
||||
self.app.info_label.config(text="Backup wird vorbereitet...")
|
||||
self.app._update_duration()
|
||||
|
||||
self.app.start_pause_button["text"] = Msg.STR["cancel_backup"]
|
||||
self.app.start_cancel_button["text"] = Msg.STR["cancel_backup"]
|
||||
self.app.update_idletasks()
|
||||
|
||||
self._set_ui_state(False, allow_log_and_backup_toggle=True)
|
||||
@@ -603,7 +603,7 @@ class Actions:
|
||||
app_logger.log(
|
||||
"No source folder selected, aborting backup.")
|
||||
self.app.backup_is_running = False
|
||||
self.app.start_pause_button["text"] = Msg.STR["start"]
|
||||
self.app.start_cancel_button["text"] = Msg.STR["start"]
|
||||
self._set_ui_state(True)
|
||||
return
|
||||
|
||||
@@ -668,7 +668,7 @@ class Actions:
|
||||
MessageDialog(message_type="error",
|
||||
title=Msg.STR["error"], text=Msg.STR["err_no_dest_folder"])
|
||||
self.app.backup_is_running = False
|
||||
self.app.start_pause_button["text"] = Msg.STR["start"]
|
||||
self.app.start_cancel_button["text"] = Msg.STR["start"]
|
||||
self._set_ui_state(True)
|
||||
return
|
||||
|
||||
|
@@ -172,9 +172,7 @@ class AdvancedSettingsFrame(ttk.Frame):
|
||||
self.keyfile_settings_frame, textvariable=self.key_file_status_var, foreground="gray")
|
||||
key_file_status_label.grid(row=0, column=1, padx=5, pady=5, sticky="w")
|
||||
|
||||
sudoers_info_text = (f"To run automated backups, an administrator must create a file in /etc/sudoers.d/\n"
|
||||
f"with the following content (replace 'punix' with the correct username):\n"
|
||||
f"punix ALL=(ALL) NOPASSWD: /path/to/pybackup-cli.py")
|
||||
sudoers_info_text = Msg.STR["sudoers_info_text"]
|
||||
sudoers_info_label = ttk.Label(
|
||||
self.keyfile_settings_frame, text=sudoers_info_text, justify="left")
|
||||
|
||||
|
@@ -166,7 +166,7 @@ class Drawing:
|
||||
if self.app.right_calculation_thread and self.app.right_calculation_thread.is_alive():
|
||||
self.app.right_calculation_stop_event.set()
|
||||
|
||||
self.app.start_pause_button.config(state="disabled")
|
||||
self.app.start_cancel_button.config(state="disabled")
|
||||
path_to_calculate = self.app.right_canvas_data.get('path_display')
|
||||
if path_to_calculate and os.path.isdir(path_to_calculate):
|
||||
self.app.right_canvas_data['calculating'] = True
|
||||
@@ -213,7 +213,7 @@ class Drawing:
|
||||
self.redraw_right_canvas_restore()
|
||||
|
||||
if not self.app.left_canvas_data.get('calculating', False):
|
||||
self.app.start_pause_button.config(state="normal")
|
||||
self.app.start_cancel_button.config(state="normal")
|
||||
|
||||
if not stop_event.is_set():
|
||||
self.app.after(0, update_ui)
|
||||
@@ -240,9 +240,10 @@ class Drawing:
|
||||
required_space *= 2 # Double the space for compression process
|
||||
|
||||
projected_total_used = self.app.destination_used_bytes + required_space
|
||||
|
||||
|
||||
if self.app.destination_total_bytes > 0:
|
||||
projected_total_percentage = projected_total_used / self.app.destination_total_bytes
|
||||
projected_total_percentage = projected_total_used / \
|
||||
self.app.destination_total_bytes
|
||||
else:
|
||||
projected_total_percentage = 0
|
||||
|
||||
@@ -251,35 +252,42 @@ class Drawing:
|
||||
|
||||
# First, check for critical space issues
|
||||
if projected_total_used > self.app.destination_total_bytes or projected_total_percentage >= 0.95:
|
||||
self.app.start_pause_button.config(state="disabled")
|
||||
canvas.create_rectangle(0, 0, canvas_width, canvas.winfo_height(), fill="#D32F2F", outline="") # Red bar
|
||||
self.app.start_cancel_button.config(state="disabled")
|
||||
canvas.create_rectangle(0, 0, canvas_width, canvas.winfo_height(
|
||||
), fill="#D32F2F", outline="") # Red bar
|
||||
info_messages.append(Msg.STR["warning_not_enough_space"])
|
||||
|
||||
|
||||
elif projected_total_percentage >= 0.90:
|
||||
self.app.start_pause_button.config(state="normal")
|
||||
canvas.create_rectangle(0, 0, canvas_width, canvas.winfo_height(), fill="#E8740C", outline="") # Orange bar
|
||||
self.app.start_cancel_button.config(state="normal")
|
||||
canvas.create_rectangle(0, 0, canvas_width, canvas.winfo_height(
|
||||
), fill="#E8740C", outline="") # Orange bar
|
||||
info_messages.append(Msg.STR["warning_space_over_90_percent"])
|
||||
|
||||
|
||||
else:
|
||||
# Only enable the button if the source is not larger than the partition itself
|
||||
if not self.app.source_larger_than_partition:
|
||||
self.app.start_pause_button.config(state="normal")
|
||||
self.app.start_cancel_button.config(state="normal")
|
||||
else:
|
||||
self.app.start_pause_button.config(state="disabled")
|
||||
self.app.start_cancel_button.config(state="disabled")
|
||||
|
||||
used_percentage = self.app.destination_used_bytes / self.app.destination_total_bytes
|
||||
used_percentage = self.app.destination_used_bytes / \
|
||||
self.app.destination_total_bytes
|
||||
used_width = canvas_width * used_percentage
|
||||
canvas.create_rectangle(0, 0, used_width, canvas.winfo_height(), fill="#0078d7", outline="")
|
||||
canvas.create_rectangle(
|
||||
0, 0, used_width, canvas.winfo_height(), fill="#0078d7", outline="")
|
||||
|
||||
# Draw the projected part only if there is space
|
||||
projected_percentage = self.app.source_size_bytes / self.app.destination_total_bytes
|
||||
projected_percentage = self.app.source_size_bytes / \
|
||||
self.app.destination_total_bytes
|
||||
projected_width = canvas_width * projected_percentage
|
||||
canvas.create_rectangle(used_width, 0, used_width + projected_width, canvas.winfo_height(), fill="#50E6FF", outline="")
|
||||
canvas.create_rectangle(used_width, 0, used_width + projected_width,
|
||||
canvas.winfo_height(), fill="#50E6FF", outline="")
|
||||
|
||||
# Add other informational messages if no critical warnings are present
|
||||
if not info_messages:
|
||||
if self.app.source_larger_than_partition:
|
||||
info_messages.append(Msg.STR["warning_source_larger_than_partition"])
|
||||
info_messages.append(
|
||||
Msg.STR["warning_source_larger_than_partition"])
|
||||
elif self.app.is_first_backup:
|
||||
info_messages.append(Msg.STR["ready_for_first_backup"])
|
||||
elif self.app.mode == "backup":
|
||||
@@ -287,7 +295,8 @@ class Drawing:
|
||||
else:
|
||||
info_messages.append(Msg.STR["restore_mode_info"])
|
||||
|
||||
self.app.info_label.config(text="\n".join(info_messages), font=info_font)
|
||||
self.app.info_label.config(
|
||||
text="\n".join(info_messages), font=info_font)
|
||||
|
||||
self.app.target_size_label.config(
|
||||
text=f"{projected_total_used / (1024**3):.2f} GB / {self.app.destination_total_bytes / (1024**3):.2f} GB")
|
||||
|
Reference in New Issue
Block a user