Optionally trash data on uninstall

This commit is contained in:
Heliguy
2024-08-26 22:16:11 -04:00
parent f507f048b5
commit 98b624c6fc
7 changed files with 96 additions and 28 deletions

View File

@@ -12,6 +12,7 @@ class SidebarButton(Gtk.ToggleButton):
# Connections
main_split.connect("notify::show-sidebar", lambda *_: self.set_active(main_split.get_show_sidebar()))
# main_split.connect("notify::collapsed", lambda *_: self.set_visible(main_split.get_collapsed()))
self.connect("toggled", lambda *_: main_split.set_show_sidebar(self.get_active()))
# Apply

View File

@@ -9,6 +9,7 @@ blueprints = custom_target('blueprints',
'main_window/window.blp',
'packages_page/packages_page.blp',
'packages_page/filters_page.blp',
'packages_page/uninstall_dialog.blp',
'properties_page/properties_page.blp',
'user_data_page/data_box.blp',
'user_data_page/user_data_page.blp',
@@ -67,10 +68,11 @@ warehouse_sources = [
'__init__.py',
'main.py',
'host_info.py',
'packages_page/app_row.py',
'gtk/error_toast.py',
'gtk/sidebar_button.py',
'main_window/window.py',
'packages_page/app_row.py',
'packages_page/uninstall_dialog.py',
'packages_page/packages_page.py',
'packages_page/filters_page.py',
'properties_page/properties_page.py',

View File

@@ -5,7 +5,8 @@ from .error_toast import ErrorToast
from .properties_page import PropertiesPage
from .filters_page import FiltersPage
from .sidebar_button import SidebarButton
import subprocess
from .uninstall_dialog import UninstallDialog
import subprocess, os
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/packages_page/packages_page.ui")
class PackagesPage(Adw.BreakpointBin):
@@ -150,6 +151,7 @@ class PackagesPage(Adw.BreakpointBin):
def generate_list(self, *args):
self.packages_list_box.remove_all()
self.selected_rows.clear()
GLib.idle_add(lambda *_: self.filters_page.generate_filters())
self.copy_button.set_sensitive(False)
self.uninstall_button.set_sensitive(False)
@@ -226,15 +228,21 @@ class PackagesPage(Adw.BreakpointBin):
self.packages_toast_overlay.add_toast(ErrorToast(_("Could not copy {}").format(feedback), str(e)).toast)
def selection_uninstall(self, *args):
def on_response(alert_dialog, response):
if response != "continue":
return
def on_response(should_trash):
GLib.idle_add(lambda *_: self.set_status(self.uninstalling))
error = [None]
def thread(*args):
cmd = ['flatpak-spawn', '--host', 'flatpak', 'uninstall', '-y']
to_trash = []
for row in self.selected_rows:
cmd.append(row.package.info["ref"])
if should_trash and os.path.exists(row.package.data_path):
to_trash.append(row.package.data_path)
try:
subprocess.run(cmd, check=True, capture_output=True)
if should_trash:
subprocess.run(['gio', 'trash'] + to_trash, check=True, capture_output=True)
except subprocess.CalledProcessError as cpe:
error[0] = cpe
except Exception as e:
@@ -249,21 +257,12 @@ class PackagesPage(Adw.BreakpointBin):
GLib.idle_add(lambda *__: self.packages_toast_overlay.add_toast(Adw.Toast(title=_("Uninstalled Packages"))))
Gio.Task.new(None, None, callback).run_in_thread(thread)
cmd = ['flatpak-spawn', '--host', 'flatpak', 'uninstall', '-y']
for row in self.selected_rows:
cmd.append(row.package.info["ref"])
dialog = Adw.AlertDialog(heading=_("Uninstall Packages?"), body=_("It will not be possible to use these packages after removal"))
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("continue", _("Uninstall"))
dialog.set_response_appearance("continue", Adw.ResponseAppearance.DESTRUCTIVE)
dialog.connect("response", on_response)
dialog = UninstallDialog(on_response)
dialog.present(self.main_window)
def start_loading(self):
self.packages_navpage.set_title(_("Packages"))
self.selected_rows.clear()
self.select_button.set_active(False)
self.set_status(self.loading_packages)

View File

@@ -0,0 +1,32 @@
using Gtk 4.0;
using Adw 1;
template $UninstallDialog : Adw.AlertDialog {
// responses [
// cancel: _("Cancel"),
// continue: _("Uninstall") destructive,
// ]
extra-child:
Adw.PreferencesGroup group {
Adw.ActionRow {
title: _("Keep");
subtitle: _("Allows restoring app settings and content");
activatable-widget: keep;
[prefix]
CheckButton keep {
active: true;
}
}
Adw.ActionRow {
title: _("Trash");
subtitle: _("Send data to the trash");
activatable-widget: trash;
[prefix]
CheckButton trash {
group: keep;
}
}
}
;
}

View File

@@ -0,0 +1,32 @@
from gi.repository import Adw, Gtk, GLib, Gio, Pango
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/packages_page/uninstall_dialog.ui")
class UninstallDialog(Adw.AlertDialog):
__gtype_name__ = "UninstallDialog"
gtc = Gtk.Template.Child
group = gtc()
trash = gtc()
def on_response(self, dialog, response):
if response != "continue":
return
self.continue_callback(self.trash.get_active())
def __init__(self, continue_callback, package_name=None, **kwargs):
super().__init__(**kwargs)
if package_name:
self.set_heading(GLib.markup_escape_text(_("Uninstall {}").format(package_name)))
self.set_body(GLib.markup_escape_text(_("It will not be possible to use {} after removal").format(package_name)))
else:
self.set_heading(GLib.markup_escape_text(_("Uninstall Packages?")))
self.set_body(GLib.markup_escape_text(_("It will not be possible to use these packages after removal")))
self.continue_callback = continue_callback
self.add_response("cancel", _("Cancel"))
self.add_response("continue", _("Uninstall"))
self.set_response_appearance("continue", Adw.ResponseAppearance.DESTRUCTIVE)
self.connect("response", self.on_response)
self.group.set_title(GLib.markup_escape_text(_("App Settings & Content")))

View File

@@ -2,6 +2,7 @@ from gi.repository import Adw, Gtk,GLib#, Gio, Pango
from .error_toast import ErrorToast
from .host_info import HostInfo
from .change_version_page import ChangeVersionPage
from .uninstall_dialog import UninstallDialog
import subprocess, os
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/properties_page/properties_page.ui")
@@ -204,11 +205,18 @@ class PropertiesPage(Adw.NavigationPage):
self.package.set_pin(state, callback)
def uninstall_handler(self, *args):
def on_choice(_, response):
if response != 'continue':
return
def on_choice(should_trash):
self.packages_page.set_status(self.packages_page.uninstalling)
self.package.uninstall(callback)
if should_trash:
try:
self.package.trash_data()
self.set_properties(self.package, refresh=True)
self.toast_overlay.add_toast(Adw.Toast.new("Trashed User Data"))
except subprocess.CalledProcessError as cpe:
self.toast_overlay.add_toast(ErrorToast(_("Could not trash data"), cpe.stderr).toast)
except Exception as e:
self.toast_overlay.add_toast(ErrorToast(_("Could not trash data"), str(e)).toast)
def callback(*args):
if fail := self.package.failed_uninstall:
@@ -220,14 +228,7 @@ class PropertiesPage(Adw.NavigationPage):
self.packages_page.packages_toast_overlay.add_toast(Adw.Toast(title=_("Uninstalled {}").format(self.package.info["name"])))
# name = self.package.info["name"]
dialog = Adw.AlertDialog(
heading=_("Uninstall {}?").format(name := self.package.info["name"]),
body=_("It will not be possible to use {} after removal.").format(name),
)
dialog.add_response('cancel', _("Cancel"))
dialog.add_response('continue', _("Uninstall"))
dialog.connect("response", on_choice)
dialog.set_response_appearance('continue', Adw.ResponseAppearance.DESTRUCTIVE)
dialog = UninstallDialog(on_choice)
dialog.present(self.main_window)
def runtime_row_handler(self, *args):

View File

@@ -7,6 +7,7 @@
<file preprocess="xml-stripblanks">main_window/window.ui</file>
<file preprocess="xml-stripblanks">packages_page/packages_page.ui</file>
<file preprocess="xml-stripblanks">packages_page/filters_page.ui</file>
<file preprocess="xml-stripblanks">packages_page/uninstall_dialog.ui</file>
<file preprocess="xml-stripblanks">properties_page/properties_page.ui</file>
<file preprocess="xml-stripblanks">change_version_page/change_version_page.ui</file>
<file preprocess="xml-stripblanks">user_data_page/data_box.ui</file>