diff --git a/data/io.github.vikdevelop.SaveDesktop.metainfo.xml.in b/data/io.github.vikdevelop.SaveDesktop.metainfo.xml.in index e289d0f0..e47bd08a 100644 --- a/data/io.github.vikdevelop.SaveDesktop.metainfo.xml.in +++ b/data/io.github.vikdevelop.SaveDesktop.metainfo.xml.in @@ -66,6 +66,16 @@ + + https://github.com/vikdevelop/SaveDesktop/releases/tag/4.0 + +
    +
  • Added support for Niri WM and LXQt DE
  • +
  • Added a status window for showing the progress of Flatpak apps installation after configuration import
  • +
  • Updated the GNOME runtime and 7-Zip to the latest versions
  • +
+
+
https://github.com/vikdevelop/SaveDesktop/releases/tag/4.0 diff --git a/io.github.vikdevelop.SaveDesktop.json b/io.github.vikdevelop.SaveDesktop.json index b8fd8c19..14b2e014 100644 --- a/io.github.vikdevelop.SaveDesktop.json +++ b/io.github.vikdevelop.SaveDesktop.json @@ -47,8 +47,8 @@ { "type" : "git", "url" : "https://github.com/ip7z/7zip.git", - "tag" : "26.01", - "commit" : "8c63d71ff886bda90c86db28466287f977374237" + "tag" : "26.02", + "commit" : "f9d78aff31a5f2521ae7ddbdc97c4a8855808959" } ], "x-checker-data" : { diff --git a/meson.build b/meson.build index 09256d99..f1a9e076 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('savedesktop', - version: '4.0', + version: '4.1', meson_version: '>= 1.0.0', default_options: [ 'warning_level=2', 'werror=false', ], ) diff --git a/po/savedesktop.pot b/po/savedesktop.pot index c761ecc8..0caa6e7d 100644 --- a/po/savedesktop.pot +++ b/po/savedesktop.pot @@ -108,6 +108,62 @@ msgstr "" msgid "Keep existing Flatpak apps and data" msgstr "" +#: src/gui/flatpaks_installer_window.py +msgid "Installing your Flatpak apps..." +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "You can continue using your computer; everything runs in the background. Once the installation of your Flatpak apps and, if applicable, your user data is complete, a message will appear here and you’ll also see a system notification. You can also show the progress below." +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "Installation queue is empty. Nothing new to install." +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "Copying the Flatpak's user data to ~/.var/app" +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "✔ Copied Flatpak's user data" +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "Cleaning up orphaned user data..." +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "All useless apps and orphaned data have been removed" +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "Installing {count} new apps" +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "{app} is already available in the system." +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "↓ Installing {app} ({current}/{total})" +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "✔ Finished installing {app}" +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "✔ All operations have been completed successfully." +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "Your apps have been installed!" +msgstr "" + +#: src/gui/flatpaks_installer_window.py +msgid "This window will be closed automatically in 2 minutes." +msgstr "" + #: src/gui/templates/shortcuts_window.ui:50 #: src/gui/more_options_dialog.py msgid "More options" diff --git a/src/core/de_config.py b/src/core/de_config.py index 46d3ec43..b7db6e32 100644 --- a/src/core/de_config.py +++ b/src/core/de_config.py @@ -105,7 +105,7 @@ def create_flatpak_autostart(): "[Desktop Entry]\n" "Name=SaveDesktop (Flatpak Apps installer)\n" "Type=Application\n" - f"Exec=python3 {CACHE}/workspace/flatpaks_installer.py\n" + f"Exec=sh -c \"flatpak run io.github.vikdevelop.SaveDesktop --show-flatpaks-installer & python3 -u {CACHE}/workspace/flatpaks_installer.py > {CACHE}/workspace/log.pipe 2>&1\"" ) print("[OK] Created Flatpak autostart") @@ -296,8 +296,7 @@ def __init__(self): print("Saving KDE Plasma configuration...") os.makedirs("DE/xdg-config", exist_ok=True) os.makedirs("DE/xdg-data", exist_ok=True) - os.system(f"cp -R {home}/.config/[k]* ./DE/xdg-config/") - os.system(f"cp -R {home}/.local/share/[k]* ./DE/xdg-data/") + self.save_kde_config_data_dirs() for src, dst in KDE_DIRS_SAVE: if os.path.isfile(src): safe_copy(src, os.path.join("DE", dst)) @@ -316,6 +315,36 @@ def save_dconf(self): os.system("dconf dump / > ./General/dconf-settings.ini") print("[OK] Saved dconf") + def save_kde_config_data_dirs(self): + # Target dirs + target_base_dir = "./DE" + mapping = [ + (f"{self.home}/.config", Path(target_base_dir) / "xdg-config"), + (f"{self.home}/.local/share", Path(target_base_dir) / "xdg-data"), + ] + + for src_dir, dst_path in mapping: + # Creating destination dir + dst_path.mkdir(parents=True, exist_ok=True) + + # Find folders begining with 'k' or 'K' + for path_str in glob.glob(f"{src_dir}/[kK]*"): + src_path = Path(path_str) + + # Ignore kdeconnect + if src_path.name.lower() == "kdeconnect": + continue + + target = dst_path / src_path.name + + # Copying folders and files + if src_path.is_dir(): + if target.exists(): + shutil.rmtree(target) + shutil.copytree(src_path, target) + else: + shutil.copy2(src_path, target) + # ------------------------ # Import pipeline # ------------------------ diff --git a/src/core/flatpaks_installer.py b/src/core/flatpaks_installer.py index 190f3e9e..4919d963 100644 --- a/src/core/flatpaks_installer.py +++ b/src/core/flatpaks_installer.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import os, subprocess, shutil, json +import os, subprocess, shutil, json, time from pathlib import Path CACHE_FLATPAK = f"{Path.home()}/.var/app/io.github.vikdevelop.SaveDesktop/cache/tmp/workspace" @@ -24,8 +24,7 @@ if dest_dir: os.chdir(dest_dir) - # Check Flatpak user preferences - with open(f"flatpak-prefs.json") as fl: + with open("flatpak-prefs.json") as fl: j = json.load(fl) copy_data = j["copy-data"] @@ -33,100 +32,104 @@ disabled_flatpaks = j["disabled-flatpaks"] keep_flatpaks = j["keep-flatpaks"] - # Restore Flatpak user data archive - if copy_data: - print("[DEBUG] Copying the Flatpak's user data to ~/.var/app") - if os.path.exists(f"app"): - print("Copying the Flatpak apps' user data to the ~/.var/app directory (backward compatibility mode)") - os.system(f"cp -au ./app/ ~/.var/") - - archive_file = "Flatpak_Apps/flatpak-apps-data.tgz" if os.path.exists("Flatpak_Apps/flatpak-apps-data.tgz") else "flatpak-apps-data.tgz" - - if os.path.exists(archive_file): - tar_cmd = ["tar", "-xzvf", archive_file, "-C", f"{Path.home()}/.var"] - for d_app in disabled_flatpaks: - tar_cmd.extend([f"--exclude={d_app}", f"--exclude=app/{d_app}"]) - subprocess.run(tar_cmd) - - # Load Flatpaks from bash scripts + # pre-calculation (math only, no actions) + desired_flatpaks = {} if install_flatpaks: - print("[DEBUG] Scanning the Bash scripts...") - if os.path.exists("Flatpak_Apps"): - installed_flatpaks_files = ['Flatpak_Apps/installed_flatpaks.sh', 'Flatpak_Apps/installed_user_flatpaks.sh'] - else: - installed_flatpaks_files = ['installed_flatpaks.sh', 'installed_user_flatpaks.sh'] - - desired_flatpaks = {} - for file in installed_flatpaks_files: + files_to_check = ['Flatpak_Apps/installed_flatpaks.sh', 'Flatpak_Apps/installed_user_flatpaks.sh'] if os.path.exists("Flatpak_Apps") else ['installed_flatpaks.sh', 'installed_user_flatpaks.sh'] + for file in files_to_check: if os.path.exists(file): - print(f"[DEBUG] Reading: {file}") with open(file, 'r') as f: - for line in f: + for line in f.readlines(): if 'flatpak' in line and 'install' in line: parts = line.split() - - app_id = None - for part in parts: - if "." in part and not part.startswith("-"): - app_id = part - break - - if not app_id: - continue - - if app_id in disabled_flatpaks: - print(f"[SKIP] Disabled app: {app_id}") - continue - - method = "--user" if "--user" in parts else "--system" - desired_flatpaks[app_id] = method - print(f"[DEBUG] Added to the installation queue: {app_id} ({method})") - - if not desired_flatpaks: - print("[DEBUG] The installation queue is empty. It couldn't find any valid Flatpaks to install.") - - # Get currently installed Flatpaks - system_flatpak_dir = '/var/lib/flatpak/app' - user_flatpak_dir = os.path.expanduser('~/.local/share/flatpak/app') - installed_apps = {} - for directory, method in [(system_flatpak_dir, '--system'), (user_flatpak_dir, '--user')]: - if os.path.exists(directory): - for app in os.listdir(directory): - if os.path.isdir(os.path.join(directory, app)): - installed_apps[app] = method - - for app, method in desired_flatpaks.items(): - if app not in installed_apps: - print(f"[INSTALL] Installing {app} ({method})") - if method == '--user': - os.system("flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo") - subprocess.run(['flatpak', 'install', method, 'flathub', app, '-y']) - else: - print(f"[INFO] {app} is available in the system.") - - # Remove Flatpaks, which are not in the list (only if it's allowed by the user) + app_id = next((p for p in parts if "." in p and not p.startswith("-")), None) + if app_id and app_id not in disabled_flatpaks: + desired_flatpaks[app_id] = "--user" if "--user" in parts else "--system" + + installed_apps = {} + for directory, method in [('/var/lib/flatpak/app', '--system'), (os.path.expanduser('~/.local/share/flatpak/app'), '--user')]: + if os.path.exists(directory): + for app in os.listdir(directory): + if os.path.isdir(os.path.join(directory, app)): + installed_apps[app] = method + + apps_to_install = {app: method for app, method in desired_flatpaks.items() if app not in installed_apps} + apps_to_remove = {app: method for app, method in installed_apps.items() if app not in desired_flatpaks} if not keep_flatpaks else {} + + # Calculate exact total steps + total_steps = 0 + if copy_data: total_steps += 1 + if install_flatpaks: total_steps += len(apps_to_install) if not keep_flatpaks: - for app, method in installed_apps.items(): - if app not in desired_flatpaks: - print(f"[REMOVE] {method.title()} Flatpak: {app}") + total_steps += len(apps_to_remove) + total_steps += 1 # one extra step for orphaned dir cleanup + + current_step = 0 + + def report_progress(): + """Helper to print the hidden progress tag for the GTK UI""" + global current_step + current_step += 1 + print(f"[PROGRESS] {current_step}/{total_steps}", flush=True) + + if total_steps == 0: + print("There's no need to install any new apps, since they're all available on your system.", flush=True) + else: + # phase 2: execution + + # Restore Data + if copy_data: + print("[COPY] Copying the Flatpak's user data to ~/.var/app", flush=True) + if os.path.exists("app"): + os.system("cp -au ./app/ ~/.var/") + archive_file = "Flatpak_Apps/flatpak-apps-data.tgz" if os.path.exists("Flatpak_Apps/flatpak-apps-data.tgz") else "flatpak-apps-data.tgz" + if os.path.exists(archive_file): + tar_cmd = ["tar", "-xzf", archive_file, "-C", f"{Path.home()}/.var"] + for d_app in disabled_flatpaks: + tar_cmd.extend([f"--exclude={d_app}", f"--exclude=app/{d_app}"]) + subprocess.run(tar_cmd) + print("✔ Copied Flatpak's user data", flush=True) + report_progress() # sends update to UI + + # Install Apps + if install_flatpaks: + for app in desired_flatpaks: + if app in installed_apps: + print(f"[INFO] {app} is already available in the system.", flush=True) + + if apps_to_install: + print(f"Installing {len(apps_to_install)} new apps", flush=True) + for i, (app, method) in enumerate(apps_to_install.items(), start=1): + print(f"↓ Installing {app} ({i}/{len(apps_to_install)})", flush=True) + if method == '--user': + os.system("flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo") + subprocess.run(['flatpak', 'install', method, 'flathub', app, '-y']) + print(f"✔ Finished installing {app}", flush=True) + report_progress() # sends update to UI + + # Remove Apps and Cleanup + if not keep_flatpaks: + for app, method in apps_to_remove.items(): + print(f"[REMOVE] {method.title()} Flatpak: {app}", flush=True) subprocess.run(['flatpak', 'uninstall', method, app, '--delete-data', '-y']) + report_progress() # <--- SEND UPDATE TO UI - # Remove orphaned ~/.var/app directories - user_var_app = Path.home() / ".var/app" - if user_var_app.exists(): - for app_dir in user_var_app.iterdir(): - if app_dir.is_dir() and app_dir.name not in desired_flatpaks: - print(f"[REMOVE] Orphaned Flatpak user data: {app_dir.name}") - shutil.rmtree(app_dir) + print("[REMOVE] Cleaning up orphaned user data...", flush=True) + user_var_app = Path.home() / ".var/app" + if user_var_app.exists(): + for app_dir in user_var_app.iterdir(): + if app_dir.is_dir() and app_dir.name not in desired_flatpaks: + print(f" -> Deleted: {app_dir.name}", flush=True) + shutil.rmtree(app_dir) + print("[OK] All useless apps and orphaned data have been removed", flush=True) + report_progress() # <--- SEND UPDATE TO UI + + print("✔ All operations have been completed successfully.", flush=True) else: - print("Nothing to do.") + print("There's no need to install any new apps, since they're all available on your system.", flush=True) # Remove the autostart file after finishing the operations autostart_file = f"{Path.home()}/.config/autostart/io.github.vikdevelop.SaveDesktop.Flatpak.desktop" if os.path.exists(autostart_file): os.remove(autostart_file) - -# Remove the cache dir after finishing the operations -if os.path.exists(CACHE_FLATPAK): - shutil.rmtree(CACHE_FLATPAK) diff --git a/src/globals.py b/src/globals.py index 1d0dbda9..4228833d 100644 --- a/src/globals.py +++ b/src/globals.py @@ -83,6 +83,8 @@ def get_app_environment(): "MATE": {"de_name": "MATE", "dirs": [(f"{home}/.config/caja", "caja")]}, "Deepin": {"de_name": "Deepin", "dirs": [(f"{home}/.config/deepin", "deepin"), (f"{home}/.local/share/deepin", "deepin-data")]}, "Hyprland": {"de_name": "Hyprland", "dirs": [(f"{home}/.config/hypr", "hypr")]}, + "LXQt": {"de_name": "LXQt", "dirs": [(f"{home}/.config/lxqt", "lxqt")]}, + "niri": {"de_name": "Niri", "dirs": [(f"{home}/.config/niri", "niri")]}, "KDE": {"de_name": "KDE Plasma"}, } diff --git a/src/gui/flatpaks_installer_window.py b/src/gui/flatpaks_installer_window.py new file mode 100644 index 00000000..60493494 --- /dev/null +++ b/src/gui/flatpaks_installer_window.py @@ -0,0 +1,247 @@ +import sys, gi, threading, time, shutil, os, re +gi.require_version('Gtk', '4.0') +gi.require_version('Adw', '1') +from gi.repository import Gtk, Adw, Gio, GLib +from savedesktop.globals import * + +class FlatpaksWindow(Adw.ApplicationWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.win_title = f'{_("Installing your Flatpak apps...")} | Save Desktop' + self.set_title(self.win_title) + + # header bar and toolbarview + self.headerbar = Adw.HeaderBar.new() + self.toolbarview = Adw.ToolbarView.new() + self.toolbarview.add_top_bar(self.headerbar) + self.set_content(self.toolbarview) + + self.headerbar.pack_start(Gtk.Image.new_from_icon_name("io.github.vikdevelop.SaveDesktop-symbolic")) + + self.set_size_request(360, 600) + + # primary layout + self.scrolled = Gtk.ScrolledWindow() + self.scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) + self.scrolled.set_vexpand(True) + self.scrolled.set_hexpand(True) + self.toolbarview.set_content(self.scrolled) + + self.winBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) + self.winBox.set_valign(Gtk.Align.FILL) + self.winBox.set_halign(Gtk.Align.FILL) + self.winBox.set_vexpand(True) + self.winBox.set_hexpand(True) + self.scrolled.set_child(self.winBox) + + # Status page + self.status_page = Adw.StatusPage.new() + self.status_page.set_description(_("You can continue using your computer; everything runs in the background. Once the installation of your Flatpak apps and, if applicable, your user data is complete, a message will appear here and you’ll also see a system notification. You can also show the progress below.")) + self.winBox.append(self.status_page) + + self.progress_bar = Gtk.ProgressBar() + # Add some margins so it doesn't touch the edges of the window + self.progress_bar.set_margin_start(20) + self.progress_bar.set_margin_end(20) + self.progress_bar.set_margin_bottom(10) + # Set initial state to 0% + self.progress_bar.set_fraction(0.0) + self.winBox.append(self.progress_bar) + + # Create TextView for logging + self.text_view = Gtk.TextView() + self.text_view.set_editable(False) + self.text_view.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) + + # Wrapper ScrolledWindow for the logs + self.log_scroller = Gtk.ScrolledWindow() + self.log_scroller.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) + + self.log_scroller.set_min_content_height(100) + self.log_scroller.set_hexpand(True) + self.log_scroller.set_vexpand(True) + + # Put the TextView inside this new ScrolledWindow + self.log_scroller.set_child(self.text_view) + + # Append the ScrolledWindow to the main UI box + self.winBox.append(self.log_scroller) + + thread = threading.Thread(target=self.read_pipe_background, daemon=True) + thread.start() + + def read_pipe_background(self): + log_path = os.path.expanduser(f"{CACHE}/workspace/log.pipe") + print(f"[THREAD] Looking for log file at: {log_path}") + + # Wait patiently until the logic script actually creates the file + while not os.path.exists(log_path): + print(f"[THREAD] Still waiting for {log_path} to exist...") + time.sleep(0.5) + + print("[THREAD] File found! Opening it now...") + + # Open the regular file ONCE and read it continuously + try: + with open(log_path, 'r') as log_file: + while True: + line = log_file.readline() + + if not line: + if not os.path.exists(log_path): + print("[THREAD] File was deleted. Killing thread cleanly.") + break + + time.sleep(0.1) + continue + + GLib.idle_add(self.add_text_to_ui, line) + + if "✔ All operations have been completed successfully." in line: + print("[THREAD] Success string found. Stopping background read.") + break + + except Exception as e: + print(f"[THREAD] FATAL ERROR: {e}") + + def add_text_to_ui(self, text): + print(f"DEBUG INCOMING: {text.strip()}") + buffer = self.text_view.get_buffer() + end_iter = buffer.get_end_iter() + + # Full completion + if "✔ All operations have been completed successfully." in text or "There's no need to install any new apps, since they're all available on your system." in text: + self.progress_bar.set_fraction(1.0) + self.send_completion_notification() + cleanup_thread = threading.Thread(target=self.cache_cleanup) + cleanup_thread.start() + + # Pulse effect for ANY active operation + if any(keyword in text for keyword in ["↓ Installing", "[COPY]", "[REMOVE]"]): + self.progress_bar.pulse() + + # Unified hidden progress tracker + match = re.search(r"\[PROGRESS\] (\d+)/(\d+)", text) + if match: + try: + current_step = int(match.group(1)) + total_steps = int(match.group(2)) + if total_steps > 0: + fraction = current_step / total_steps + self.progress_bar.set_fraction(fraction) + except ValueError: + pass + + return False + + translated_text = self.translate_log_line(text) + + + buffer.insert(end_iter, translated_text) + + new_end_iter = buffer.get_end_iter() + mark = buffer.create_mark(None, new_end_iter, False) + self.text_view.scroll_to_mark(mark, 0.0, True, 0.0, 1.0) + buffer.delete_mark(mark) + + return False + + def translate_log_line(self, original_text): + # Remove whitespace/newlines for easier exact matching + text = original_text.strip() + + if text == "✔ All operations have been completed successfully.": + return _("✔ All operations have been completed successfully.") + "\n" + + elif text == "Installation queue is empty. Nothing new to install.": + return _("Installation queue is empty. Nothing new to install.") + "\n" + + elif text == "[COPY] Copying the Flatpak's user data to ~/.var/app": + return _("Copying the Flatpak's user data to ~/.var/app") + "[COPY]\n" + + elif text == "✔ Copied Flatpak's user data": + return _("✔ Copied Flatpak's user data") + "\n" + + elif text == "[REMOVE] Cleaning up orphaned user data...": + return _("Cleaning up orphaned user data...") + "[REMOVE]\n" + + elif text == "[OK] All useless apps and orphaned data have been removed": + return _("All useless apps and orphaned data have been removed") + "[OK]\n" + + match_installing = re.search(r"↓ Installing (.*) \((\d+)/(\d+)\)", text) + if match_installing: + app = match_installing.group(1) + current = match_installing.group(2) + total = match_installing.group(3) + return _("↓ Installing {app} ({current}/{total})").format( + app=app, current=current, total=total + ) + "\n" + + match_finished = re.search(r"✔ Finished installing (.*)", text) + if match_finished: + app = match_finished.group(1) + return _("✔ Finished installing {app}").format(app=app) + "\n" + + match_new_apps = re.search(r"Installing (\d+) new apps", text) + if match_new_apps: + count = match_new_apps.group(1) + return _("Installing {count} new apps").format(count=count) + "\n" + + # 4. Matches: "[INFO] com.example.App is already available in the system." + match_info = re.search(r"\[INFO\] (.*) is already available in the system\.", text) + if match_info: + app = match_info.group(1) + return _("{app} is already available in the system.").format(app=app) + "[INFO]\n" + + # If no translation matches, just return the original English text + return original_text + + def send_completion_notification(self): + # Create the notification object with a title + notification = Gio.Notification.new(_("Your apps have been installed!")) + + # Optional: Set a system icon (or use your app's specific icon name) + icon = Gio.ThemedIcon.new("object-select-symbolic") + notification.set_icon(icon) + + # Get the application instance and send the notification + # The string "install-complete" is just a unique ID for this specific notification + app = self.get_application() + if app: + app.send_notification("install-complete", notification) + + def cache_cleanup(self): + if os.path.exists(f"{CACHE}/workspace"): + shutil.rmtree(f"{CACHE}/workspace") + + GLib.idle_add(self.start_auto_close_timer) + + def start_auto_close_timer(self): + # 300 seconds = 2 minutes + # GLib.timeout_add_seconds will wait in the background and then execute 'self.close_app' + GLib.timeout_add_seconds(120, self.close_app) + + self.set_title(_("Your apps have been installed!")) + self.status_page.set_icon_name("done") + self.status_page.set_description(_("This window will be closed automatically in 2 minutes.")) + + return False # tells idle_add to only run this setup once + + def close_app(self): + # This is triggered when the 2 minutes are up. + # Safely closes the current GTK window. + self.close() + + return False # tells the timeout timer not to repeat itself + +class FlatpaksInstallerApp(Adw.Application): + def __init__(self, **kwargs): + super().__init__(**kwargs, flags=Gio.ApplicationFlags.FLAGS_NONE, + application_id="io.github.vikdevelop.SaveDesktop") + self.connect('activate', self.on_activate) + + # Show the app window + def on_activate(self, app): + self.win = FlatpaksWindow(application=app) + self.win.present() diff --git a/src/gui/meson.build b/src/gui/meson.build index d1ad5d2c..b0f5c647 100644 --- a/src/gui/meson.build +++ b/src/gui/meson.build @@ -5,7 +5,8 @@ gui_sources = [ '__init__.py', 'custom_dirs_dialog.py', 'flatpak_apps_dialog.py', 'more_options_dialog.py', - 'synchronization_dialogs.py', + 'synchronization_dialogs.py', + 'flatpaks_installer_window.py', ] install_data(gui_sources, install_dir: moduledir / 'gui') diff --git a/src/savedesktop.in b/src/savedesktop.in index ad67a011..bd987900 100755 --- a/src/savedesktop.in +++ b/src/savedesktop.in @@ -53,6 +53,7 @@ parser.add_argument("--save-without-archive", type=str, help="Save the configura parser.add_argument("--sync", "--periodic-sync", action="store_true", help="Start periodic synchronization") parser.add_argument("--sync-now", action="store_true", help="Sync the configuration immediately") parser.add_argument("--import-config", help="Import a configuration from a file (*.sd.zip or *.sd.tar.gz) or folder", type=str, dest="CFG_ARCHIVE_PATH") +parser.add_argument("--show-flatpaks-installer", action="store_true", help="Show a status window about Flatpak apps' installation progress") cmd = parser.parse_args() # Import these modules before starting periodic saving or synchronization @@ -85,6 +86,13 @@ elif cmd.CFG_ARCHIVE_PATH: # import a configuration from a file, or folder raise ValueError(f"Encrypted archives are not supported in this mode") Unpack(dir_path) # archive.py +elif cmd.show_flatpaks_installer: + try: + from savedesktop.gui.flatpaks_installer_window import FlatpaksInstallerApp + app = FlatpaksInstallerApp() + app.run([]) + except FileNotFoundError: + print("File CACHE/workspace/flatpak-prefs.json doesn't exist, so it's impossible to open the window.") else: # show the app window resource = Gio.Resource.load(os.path.join(pkgdatadir, 'savedesktop.gresource')) resource._register()