mirror of
https://github.com/morgan9e/warehouse
synced 2026-04-14 00:04:08 +09:00
Format code with Black
This commit is contained in:
@@ -10,8 +10,8 @@ from .snapshots_window import SnapshotsWindow
|
||||
from .filter_window import FilterWindow
|
||||
from .common import myUtils
|
||||
|
||||
class AppRow(Adw.ActionRow):
|
||||
|
||||
class AppRow(Adw.ActionRow):
|
||||
def set_selectable(self, is_selectable):
|
||||
self.tickbox.set_active(False)
|
||||
self.tickbox.set_visible(is_selectable)
|
||||
@@ -61,13 +61,38 @@ class AppRow(Adw.ActionRow):
|
||||
if len(current_flatpak[13]) == 0:
|
||||
self.is_runtime = True
|
||||
|
||||
info_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, valign=Gtk.Align.CENTER, halign=Gtk.Align.CENTER, hexpand=True, vexpand=True, spacing=6)
|
||||
info_box = Gtk.Box(
|
||||
orientation=Gtk.Orientation.VERTICAL,
|
||||
valign=Gtk.Align.CENTER,
|
||||
halign=Gtk.Align.CENTER,
|
||||
hexpand=True,
|
||||
vexpand=True,
|
||||
spacing=6,
|
||||
)
|
||||
|
||||
# justify=Gtk.Justification.RIGHT
|
||||
self.mask_label = Gtk.Label(label=_("Updates Disabled"), visible=False, hexpand=True, wrap=True, valign=Gtk.Align.CENTER, tooltip_text=_("{} is masked and will not be updated").format(self.app_name))
|
||||
self.mask_label = Gtk.Label(
|
||||
label=_("Updates Disabled"),
|
||||
visible=False,
|
||||
hexpand=True,
|
||||
wrap=True,
|
||||
valign=Gtk.Align.CENTER,
|
||||
tooltip_text=_("{} is masked and will not be updated").format(
|
||||
self.app_name
|
||||
),
|
||||
)
|
||||
self.mask_label.add_css_class("warning")
|
||||
|
||||
self.eol_app_label = Gtk.Label(label=_("App EOL"), visible=False, hexpand=True, wrap=True, valign=Gtk.Align.CENTER, tooltip_text=_("{} has reached its End of Life and will not receive any security updates").format(self.app_name))
|
||||
self.eol_app_label = Gtk.Label(
|
||||
label=_("App EOL"),
|
||||
visible=False,
|
||||
hexpand=True,
|
||||
wrap=True,
|
||||
valign=Gtk.Align.CENTER,
|
||||
tooltip_text=_(
|
||||
"{} has reached its End of Life and will not receive any security updates"
|
||||
).format(self.app_name),
|
||||
)
|
||||
self.eol_app_label.add_css_class("error")
|
||||
info_box.append(self.eol_app_label)
|
||||
if "eol" in parent_window.host_flatpaks[index][12]:
|
||||
@@ -75,7 +100,16 @@ class AppRow(Adw.ActionRow):
|
||||
# justify=Gtk.Justification.RIGHT
|
||||
self.eol_app_label.set_visible(True)
|
||||
|
||||
self.eol_runtime_label = Gtk.Label(label=_("Runtime EOL"), visible=False, hexpand=True, wrap=True, valign=Gtk.Align.CENTER, tooltip_text=_("{}'s runtime has reached its End of Life and will not receive any security updates").format(self.app_name))
|
||||
self.eol_runtime_label = Gtk.Label(
|
||||
label=_("Runtime EOL"),
|
||||
visible=False,
|
||||
hexpand=True,
|
||||
wrap=True,
|
||||
valign=Gtk.Align.CENTER,
|
||||
tooltip_text=_(
|
||||
"{}'s runtime has reached its End of Life and will not receive any security updates"
|
||||
).format(self.app_name),
|
||||
)
|
||||
self.eol_runtime_label.add_css_class("error")
|
||||
info_box.append(self.eol_runtime_label)
|
||||
if current_flatpak[13] in parent_window.eol_list:
|
||||
@@ -85,92 +119,188 @@ class AppRow(Adw.ActionRow):
|
||||
|
||||
info_pop = Gtk.Popover()
|
||||
info_pop.set_child(info_box)
|
||||
self.info_button = Gtk.MenuButton(visible=False, valign=Gtk.Align.CENTER, popover=info_pop, icon_name="software-update-urgent-symbolic")
|
||||
self.info_button = Gtk.MenuButton(
|
||||
visible=False,
|
||||
valign=Gtk.Align.CENTER,
|
||||
popover=info_pop,
|
||||
icon_name="software-update-urgent-symbolic",
|
||||
)
|
||||
self.info_button.add_css_class("flat")
|
||||
|
||||
info_box.append(self.mask_label)
|
||||
self.add_suffix(self.info_button)
|
||||
|
||||
properties_button = Gtk.Button(icon_name="info-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("View Properties"))
|
||||
properties_button = Gtk.Button(
|
||||
icon_name="info-symbolic",
|
||||
valign=Gtk.Align.CENTER,
|
||||
tooltip_text=_("View Properties"),
|
||||
)
|
||||
properties_button.add_css_class("flat")
|
||||
properties_button.connect("clicked", lambda *_: PropertiesWindow(index, host_flatpaks, parent_window))
|
||||
properties_button.connect(
|
||||
"clicked", lambda *_: PropertiesWindow(index, host_flatpaks, parent_window)
|
||||
)
|
||||
self.add_suffix(properties_button)
|
||||
|
||||
self.tickbox = Gtk.CheckButton(visible=False) # visible=self.in_batch_mode
|
||||
|
||||
self.tickbox = Gtk.CheckButton(visible=False) # visible=self.in_batch_mode
|
||||
self.tickbox.add_css_class("selection-mode")
|
||||
self.tickbox.connect("toggled", parent_window.rowSelectHandler)
|
||||
self.add_suffix(self.tickbox)
|
||||
self.set_activatable_widget(self.tickbox)
|
||||
self.set_activatable(False)
|
||||
|
||||
self.row_menu = Gtk.MenuButton(icon_name="view-more-symbolic", valign=Gtk.Align.CENTER) # visible=not self.in_batch_mode
|
||||
self.row_menu = Gtk.MenuButton(
|
||||
icon_name="view-more-symbolic", valign=Gtk.Align.CENTER
|
||||
) # visible=not self.in_batch_mode
|
||||
self.row_menu.add_css_class("flat")
|
||||
row_menu_model = Gio.Menu()
|
||||
copy_menu_model = Gio.Menu()
|
||||
advanced_menu_model = Gio.Menu()
|
||||
self.add_suffix(self.row_menu)
|
||||
|
||||
parent_window.create_action(("copy-name" + str(index)), lambda *_, name=self.app_name, toast=_("Copied name"): parent_window.copyItem(name, toast))
|
||||
copy_menu_model.append_item(Gio.MenuItem.new(_("Copy Name"), f"win.copy-name{index}"))
|
||||
parent_window.create_action(
|
||||
("copy-name" + str(index)),
|
||||
lambda *_, name=self.app_name, toast=_(
|
||||
"Copied name"
|
||||
): parent_window.copyItem(name, toast),
|
||||
)
|
||||
copy_menu_model.append_item(
|
||||
Gio.MenuItem.new(_("Copy Name"), f"win.copy-name{index}")
|
||||
)
|
||||
|
||||
parent_window.create_action(("copy-id" + str(index)), lambda *_, id=self.app_id, toast=_("Copied ID"): parent_window.copyItem(id, toast))
|
||||
copy_menu_model.append_item(Gio.MenuItem.new(_("Copy ID"), f"win.copy-id{index}"))
|
||||
parent_window.create_action(
|
||||
("copy-id" + str(index)),
|
||||
lambda *_, id=self.app_id, toast=_("Copied ID"): parent_window.copyItem(
|
||||
id, toast
|
||||
),
|
||||
)
|
||||
copy_menu_model.append_item(
|
||||
Gio.MenuItem.new(_("Copy ID"), f"win.copy-id{index}")
|
||||
)
|
||||
|
||||
parent_window.create_action(("copy-ref" + str(index)), lambda *_, ref=self.app_ref, toast=_("Copied ref"): parent_window.copyItem(ref, toast))
|
||||
copy_menu_model.append_item(Gio.MenuItem.new(_("Copy Ref"), f"win.copy-ref{index}"))
|
||||
parent_window.create_action(
|
||||
("copy-ref" + str(index)),
|
||||
lambda *_, ref=self.app_ref, toast=_("Copied ref"): parent_window.copyItem(
|
||||
ref, toast
|
||||
),
|
||||
)
|
||||
copy_menu_model.append_item(
|
||||
Gio.MenuItem.new(_("Copy Ref"), f"win.copy-ref{index}")
|
||||
)
|
||||
|
||||
parent_window.create_action(("copy-command" + str(index)), lambda *_, ref=self.app_ref, toast=_("Copied launch command"): parent_window.copyItem(f"flatpak run {ref}", toast))
|
||||
copy_menu_model.append_item(Gio.MenuItem.new(_("Copy Launch Command"), f"win.copy-command{index}"))
|
||||
parent_window.create_action(
|
||||
("copy-command" + str(index)),
|
||||
lambda *_, ref=self.app_ref, toast=_(
|
||||
"Copied launch command"
|
||||
): parent_window.copyItem(f"flatpak run {ref}", toast),
|
||||
)
|
||||
copy_menu_model.append_item(
|
||||
Gio.MenuItem.new(_("Copy Launch Command"), f"win.copy-command{index}")
|
||||
)
|
||||
|
||||
row_menu_model.append_submenu(_("Copy"), copy_menu_model)
|
||||
|
||||
if "runtime" not in parent_window.host_flatpaks[index][12]:
|
||||
parent_window.create_action(("run" + str(index)), lambda *_a, ref=self.app_ref, name=self.app_name: parent_window.runAppThread(ref, _("Opened {}").format(name)))
|
||||
parent_window.create_action(
|
||||
("run" + str(index)),
|
||||
lambda *_a, ref=self.app_ref, name=self.app_name: parent_window.runAppThread(
|
||||
ref, _("Opened {}").format(name)
|
||||
),
|
||||
)
|
||||
run_item = Gio.MenuItem.new(_("Open"), f"win.run{index}")
|
||||
row_menu_model.append_item(run_item)
|
||||
|
||||
parent_window.create_action(("uninstall" + str(index)), lambda *_: parent_window.uninstallButtonHandler(self, self.app_name, self.app_ref, self.app_id))
|
||||
parent_window.create_action(
|
||||
("uninstall" + str(index)),
|
||||
lambda *_: parent_window.uninstallButtonHandler(
|
||||
self, self.app_name, self.app_ref, self.app_id
|
||||
),
|
||||
)
|
||||
uninstall_item = Gio.MenuItem.new(_("Uninstall"), f"win.uninstall{index}")
|
||||
row_menu_model.append_item(uninstall_item)
|
||||
|
||||
data_menu_model = Gio.Menu()
|
||||
|
||||
parent_window.create_action(("open-data" + str(index)), lambda *_, path=(parent_window.user_data_path + self.app_id): parent_window.openDataFolder(path))
|
||||
open_data_item = Gio.MenuItem.new(_("Open User Data Folder"), f"win.open-data{index}")
|
||||
open_data_item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled"))
|
||||
parent_window.create_action(
|
||||
("open-data" + str(index)),
|
||||
lambda *_, path=(
|
||||
parent_window.user_data_path + self.app_id
|
||||
): parent_window.openDataFolder(path),
|
||||
)
|
||||
open_data_item = Gio.MenuItem.new(
|
||||
_("Open User Data Folder"), f"win.open-data{index}"
|
||||
)
|
||||
open_data_item.set_attribute_value(
|
||||
"hidden-when", GLib.Variant.new_string("action-disabled")
|
||||
)
|
||||
data_menu_model.append_item(open_data_item)
|
||||
|
||||
parent_window.create_action(("trash" + str(index)), lambda *_, name=self.app_name, id=self.app_id, index=index: parent_window.trashData(name, id, index))
|
||||
parent_window.create_action(
|
||||
("trash" + str(index)),
|
||||
lambda *_, name=self.app_name, id=self.app_id, index=index: parent_window.trashData(
|
||||
name, id, index
|
||||
),
|
||||
)
|
||||
trash_item = Gio.MenuItem.new(_("Trash User Data"), f"win.trash{index}")
|
||||
trash_item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled"))
|
||||
trash_item.set_attribute_value(
|
||||
"hidden-when", GLib.Variant.new_string("action-disabled")
|
||||
)
|
||||
data_menu_model.append_item(trash_item)
|
||||
|
||||
row_menu_model.append_section(None, data_menu_model)
|
||||
|
||||
|
||||
if not os.path.exists(parent_window.user_data_path + self.app_id):
|
||||
parent_window.lookup_action(f"open-data{self.index}").set_enabled(False)
|
||||
parent_window.lookup_action(f"trash{self.index}").set_enabled(False)
|
||||
|
||||
parent_window.create_action(("mask" + str(index)), lambda *_, id=self.app_id, type=self.install_type, index=index: parent_window.maskFlatpak(self))
|
||||
parent_window.create_action(
|
||||
("mask" + str(index)),
|
||||
lambda *_, id=self.app_id, type=self.install_type, index=index: parent_window.maskFlatpak(
|
||||
self
|
||||
),
|
||||
)
|
||||
mask_item = Gio.MenuItem.new(_("Disable Updates"), f"win.mask{index}")
|
||||
mask_item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled"))
|
||||
mask_item.set_attribute_value(
|
||||
"hidden-when", GLib.Variant.new_string("action-disabled")
|
||||
)
|
||||
advanced_menu_model.append_item(mask_item)
|
||||
|
||||
parent_window.create_action(("unmask" + str(index)), lambda *_, id=self.app_id, type=self.install_type, index=index: parent_window.maskFlatpak(self))
|
||||
parent_window.create_action(
|
||||
("unmask" + str(index)),
|
||||
lambda *_, id=self.app_id, type=self.install_type, index=index: parent_window.maskFlatpak(
|
||||
self
|
||||
),
|
||||
)
|
||||
unmask_item = Gio.MenuItem.new(_("Enable Updates"), f"win.unmask{index}")
|
||||
unmask_item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled"))
|
||||
unmask_item.set_attribute_value(
|
||||
"hidden-when", GLib.Variant.new_string("action-disabled")
|
||||
)
|
||||
advanced_menu_model.append_item(unmask_item)
|
||||
|
||||
if "runtime" not in parent_window.host_flatpaks[index][12]:
|
||||
parent_window.create_action(("snapshot" + str(index)), lambda *_, row=current_flatpak: SnapshotsWindow(parent_window, row).present())
|
||||
snapshot_item = Gio.MenuItem.new(_("Manage Snapshots"), f"win.snapshot{index}")
|
||||
parent_window.create_action(
|
||||
("snapshot" + str(index)),
|
||||
lambda *_, row=current_flatpak: SnapshotsWindow(
|
||||
parent_window, row
|
||||
).present(),
|
||||
)
|
||||
snapshot_item = Gio.MenuItem.new(
|
||||
_("Manage Snapshots"), f"win.snapshot{index}"
|
||||
)
|
||||
advanced_menu_model.append_item(snapshot_item)
|
||||
|
||||
parent_window.create_action(("downgrade" + str(index)), lambda *_, row=current_flatpak, index=index: DowngradeWindow(parent_window, row, index))
|
||||
parent_window.create_action(
|
||||
("downgrade" + str(index)),
|
||||
lambda *_, row=current_flatpak, index=index: DowngradeWindow(
|
||||
parent_window, row, index
|
||||
),
|
||||
)
|
||||
downgrade_item = Gio.MenuItem.new(_("Downgrade"), f"win.downgrade{index}")
|
||||
advanced_menu_model.append_item(downgrade_item)
|
||||
|
||||
if self.app_id in parent_window.system_mask_list or self.app_id in parent_window.user_mask_list:
|
||||
if (
|
||||
self.app_id in parent_window.system_mask_list
|
||||
or self.app_id in parent_window.user_mask_list
|
||||
):
|
||||
self.mask_label.set_visible(True)
|
||||
parent_window.lookup_action(f"mask{index}").set_enabled(False)
|
||||
else:
|
||||
|
||||
232
src/common.py
232
src/common.py
@@ -1,9 +1,10 @@
|
||||
from gi.repository import GLib, Gtk, Adw, Gio #, Gdk
|
||||
from gi.repository import GLib, Gtk, Adw, Gio # , Gdk
|
||||
import os
|
||||
import subprocess
|
||||
import pathlib
|
||||
import time
|
||||
|
||||
|
||||
class myUtils:
|
||||
def __init__(self, window, **kwargs):
|
||||
self.parent_window = window
|
||||
@@ -11,15 +12,20 @@ class myUtils:
|
||||
self.user_data_path = self.host_home + "/.var/app/"
|
||||
self.install_success = True
|
||||
self.uninstall_success = True
|
||||
self.new_env = dict( os.environ )
|
||||
self.new_env['LC_ALL'] = 'C'
|
||||
|
||||
self.new_env = dict(os.environ)
|
||||
self.new_env["LC_ALL"] = "C"
|
||||
|
||||
def trashFolder(self, path):
|
||||
if not os.path.exists(path):
|
||||
print("error in common.trashFolder: path does not exists. path =", path)
|
||||
return 1
|
||||
try:
|
||||
subprocess.run(["gio", "trash", path], capture_output=False, check=True, env=self.new_env)
|
||||
subprocess.run(
|
||||
["gio", "trash", path],
|
||||
capture_output=False,
|
||||
check=True,
|
||||
env=self.new_env,
|
||||
)
|
||||
return 0
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("error in common.trashFolder: CalledProcessError:", e)
|
||||
@@ -68,10 +74,18 @@ class myUtils:
|
||||
def findAppIcon(self, app_id):
|
||||
icon_theme = Gtk.IconTheme.new()
|
||||
icon_theme.add_search_path("/var/lib/flatpak/exports/share/icons/")
|
||||
icon_theme.add_search_path(self.host_home + "/.local/share/flatpak/exports/share/icons")
|
||||
|
||||
icon_theme.add_search_path(
|
||||
self.host_home + "/.local/share/flatpak/exports/share/icons"
|
||||
)
|
||||
|
||||
try:
|
||||
icon_path = (icon_theme.lookup_icon(app_id, None, 512, 1, self.parent_window.get_direction(), 0).get_file().get_path())
|
||||
icon_path = (
|
||||
icon_theme.lookup_icon(
|
||||
app_id, None, 512, 1, self.parent_window.get_direction(), 0
|
||||
)
|
||||
.get_file()
|
||||
.get_path()
|
||||
)
|
||||
except GLib.GError:
|
||||
icon_path = None
|
||||
if icon_path:
|
||||
@@ -85,7 +99,12 @@ class myUtils:
|
||||
|
||||
def getHostUpdates(self):
|
||||
list = []
|
||||
output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "update"], capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
["flatpak-spawn", "--host", "flatpak", "update"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.new_env,
|
||||
).stdout
|
||||
lines = output.strip().split("\n")
|
||||
columns = lines[0].split("\t")
|
||||
data = [columns]
|
||||
@@ -94,20 +113,37 @@ class myUtils:
|
||||
data.append(row)
|
||||
|
||||
for i in range(len(data)):
|
||||
if data[i][0].find('.') == 2:
|
||||
if data[i][0].find(".") == 2:
|
||||
list.append(data[i][2])
|
||||
|
||||
return(list)
|
||||
|
||||
return list
|
||||
|
||||
def getHostPins(self):
|
||||
output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "pin"], capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
["flatpak-spawn", "--host", "flatpak", "pin"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.new_env,
|
||||
).stdout
|
||||
data = output.strip().split("\n")
|
||||
for i in range(len(data)):
|
||||
data[i] = data[i].strip()
|
||||
return data
|
||||
|
||||
def getHostRemotes(self):
|
||||
output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "remotes", "--columns=all", "--show-disabled"], capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
[
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"remotes",
|
||||
"--columns=all",
|
||||
"--show-disabled",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.new_env,
|
||||
).stdout
|
||||
lines = output.strip().split("\n")
|
||||
columns = lines[0].split("\t")
|
||||
data = [columns]
|
||||
@@ -117,7 +153,12 @@ class myUtils:
|
||||
return data
|
||||
|
||||
def getHostFlatpaks(self):
|
||||
output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"], capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.new_env,
|
||||
).stdout
|
||||
lines = output.strip().split("\n")
|
||||
columns = lines[0].split("\t")
|
||||
data = [columns]
|
||||
@@ -125,7 +166,12 @@ class myUtils:
|
||||
row = line.split("\t")
|
||||
data.append(row)
|
||||
|
||||
output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "list", "--columns=runtime"], capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
["flatpak-spawn", "--host", "flatpak", "list", "--columns=runtime"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.new_env,
|
||||
).stdout
|
||||
lines = output.split("\n")
|
||||
for i in range(len(data)):
|
||||
data[i].append(lines[i])
|
||||
@@ -142,39 +188,65 @@ class myUtils:
|
||||
dependent_runtimes.append(current[13])
|
||||
except:
|
||||
print("Could not get dependent runtime")
|
||||
return(dependent_runtimes)
|
||||
return dependent_runtimes
|
||||
|
||||
def getHostMasks(self, user_or_system):
|
||||
output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "mask", f"--{user_or_system}"], capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
["flatpak-spawn", "--host", "flatpak", "mask", f"--{user_or_system}"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.new_env,
|
||||
).stdout
|
||||
lines = output.strip().split("\n")
|
||||
for i in range(len(lines)):
|
||||
lines[i] = lines[i].strip()
|
||||
return(lines)
|
||||
return lines
|
||||
|
||||
def maskFlatpak(self, app_id, user_or_system, remove=False):
|
||||
command = ["flatpak-spawn", "--host", "flatpak", "mask", f"--{user_or_system}", app_id]
|
||||
command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"mask",
|
||||
f"--{user_or_system}",
|
||||
app_id,
|
||||
]
|
||||
if remove:
|
||||
command.append("--remove")
|
||||
response = ""
|
||||
try:
|
||||
response = subprocess.run(command, capture_output=True, text=True, env=self.new_env)
|
||||
response = subprocess.run(
|
||||
command, capture_output=True, text=True, env=self.new_env
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error setting mask for {app_id}:\n", e)
|
||||
return(1)
|
||||
return 1
|
||||
if len(response.stderr) > 0:
|
||||
return(1)
|
||||
return(0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def downgradeFlatpak(self, ref, commit, install_type="system"):
|
||||
command = ['flatpak-spawn', '--host', 'pkexec', 'flatpak', 'update', ref, f"--commit={commit}", f"--{install_type}", '-y']
|
||||
command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"pkexec",
|
||||
"flatpak",
|
||||
"update",
|
||||
ref,
|
||||
f"--commit={commit}",
|
||||
f"--{install_type}",
|
||||
"-y",
|
||||
]
|
||||
try:
|
||||
response = subprocess.run(command, capture_output=True, text=True, env=self.new_env).stderr
|
||||
response = subprocess.run(
|
||||
command, capture_output=True, text=True, env=self.new_env
|
||||
).stderr
|
||||
except subprocess.CalledProcessError as e:
|
||||
if "note that" in response.lower():
|
||||
return(0)
|
||||
return 0
|
||||
print(f"Error setting mask for {app_id}:\n", e)
|
||||
return(1)
|
||||
return(0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def uninstallFlatpak(self, ref_arr, type_arr, should_trash, progress_bar=None):
|
||||
self.uninstall_success = True
|
||||
@@ -193,23 +265,40 @@ class myUtils:
|
||||
# apps array guide: [app_ref, app_id, user_or_system_install]
|
||||
|
||||
for i in range(len(apps)):
|
||||
command = ['flatpak-spawn', '--host', 'flatpak', 'remove', '-y', f"--{apps[i][2]}", apps[i][0]]
|
||||
command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"remove",
|
||||
"-y",
|
||||
f"--{apps[i][2]}",
|
||||
apps[i][0],
|
||||
]
|
||||
try:
|
||||
subprocess.run(command, capture_output=False, check=True, env=self.new_env)
|
||||
subprocess.run(
|
||||
command, capture_output=False, check=True, env=self.new_env
|
||||
)
|
||||
if progress_bar:
|
||||
GLib.idle_add(progress_bar.set_visible, True)
|
||||
GLib.idle_add(progress_bar.set_fraction, (i + 1.0) / len(ref_arr))
|
||||
except subprocess.CalledProcessError:
|
||||
fails.append(apps[i])
|
||||
|
||||
if len(fails) > 0: # Run this only if there is 1 or more non uninstalled apps
|
||||
pk_command = ['flatpak-spawn', '--host', 'pkexec', 'flatpak', 'remove', '-y', '--system']
|
||||
if len(fails) > 0: # Run this only if there is 1 or more non uninstalled apps
|
||||
pk_command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"pkexec",
|
||||
"flatpak",
|
||||
"remove",
|
||||
"-y",
|
||||
"--system",
|
||||
]
|
||||
print("second uninstall process")
|
||||
for i in range(len(fails)):
|
||||
|
||||
if fails[i][2] == "user":
|
||||
self.uninstall_success = False
|
||||
continue # Skip if app is a user install app
|
||||
continue # Skip if app is a user install app
|
||||
|
||||
pk_command.append(fails[i][0])
|
||||
try:
|
||||
@@ -217,7 +306,9 @@ class myUtils:
|
||||
if progress_bar:
|
||||
GLib.idle_add(progress_bar.set_visible, True)
|
||||
GLib.idle_add(progress_bar.set_fraction, 0.9)
|
||||
subprocess.run(pk_command, capture_output=False, check=True, env=self.new_env)
|
||||
subprocess.run(
|
||||
pk_command, capture_output=False, check=True, env=self.new_env
|
||||
)
|
||||
except subprocess.CalledProcessError:
|
||||
self.uninstall_success = False
|
||||
|
||||
@@ -242,29 +333,42 @@ class myUtils:
|
||||
fails = []
|
||||
|
||||
for i in range(len(app_arr)):
|
||||
command = ['flatpak-spawn', '--host', 'flatpak', 'install']
|
||||
command = ["flatpak-spawn", "--host", "flatpak", "install"]
|
||||
if remote != None:
|
||||
command.append(remote)
|
||||
command.append(f"--{user_or_system}")
|
||||
command.append('-y')
|
||||
command.append("-y")
|
||||
command.append(app_arr[i])
|
||||
try:
|
||||
subprocess.run(command, capture_output=False, check=True, env=self.new_env)
|
||||
subprocess.run(
|
||||
command, capture_output=False, check=True, env=self.new_env
|
||||
)
|
||||
if progress_bar:
|
||||
GLib.idle_add(progress_bar.set_visible, True)
|
||||
GLib.idle_add(progress_bar.set_fraction, (i + 1.0) / len(app_arr))
|
||||
except subprocess.CalledProcessError:
|
||||
fails.append(app_arr[i])
|
||||
|
||||
|
||||
if (len(fails) > 0) and (user_or_system == "system"):
|
||||
pk_command = ['flatpak-spawn', '--host', 'pkexec', 'flatpak', 'install', remote, f"--{user_or_system}", '-y']
|
||||
pk_command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"pkexec",
|
||||
"flatpak",
|
||||
"install",
|
||||
remote,
|
||||
f"--{user_or_system}",
|
||||
"-y",
|
||||
]
|
||||
for i in range(len(fails)):
|
||||
pk_command.append(fails[i])
|
||||
try:
|
||||
if progress_bar:
|
||||
GLib.idle_add(progress_bar.set_visible, True)
|
||||
GLib.idle_add(progress_bar.set_fraction, 0.9)
|
||||
subprocess.run(pk_command, capture_output=False, check=True, env=self.new_env)
|
||||
subprocess.run(
|
||||
pk_command, capture_output=False, check=True, env=self.new_env
|
||||
)
|
||||
except subprocess.CalledProcessError:
|
||||
self.install_success = False
|
||||
|
||||
@@ -279,7 +383,12 @@ class myUtils:
|
||||
self.run_app_error = False
|
||||
self.run_app_error_message = ""
|
||||
try:
|
||||
subprocess.run(['flatpak-spawn', '--host', 'flatpak', 'run', ref], check=True, env=self.new_env, start_new_session=True)
|
||||
subprocess.run(
|
||||
["flatpak-spawn", "--host", "flatpak", "run", ref],
|
||||
check=True,
|
||||
env=self.new_env,
|
||||
start_new_session=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.run_app_error_message = str(e)
|
||||
self.run_app_error = True
|
||||
@@ -292,9 +401,20 @@ class myUtils:
|
||||
if "system" in type_arr:
|
||||
return "system"
|
||||
|
||||
def snapshotApps(self, epoch, app_snapshot_path_arr, app_version_arr, app_user_data_arr, progress_bar=None):
|
||||
if not (len(app_snapshot_path_arr) == len(app_version_arr) == len(app_user_data_arr)):
|
||||
print("error in common.snapshotApp: the lengths of app_snapshot_path_arr, app_version_arr, and app_user_data_arr do not match.")
|
||||
def snapshotApps(
|
||||
self,
|
||||
epoch,
|
||||
app_snapshot_path_arr,
|
||||
app_version_arr,
|
||||
app_user_data_arr,
|
||||
progress_bar=None,
|
||||
):
|
||||
if not (
|
||||
len(app_snapshot_path_arr) == len(app_version_arr) == len(app_user_data_arr)
|
||||
):
|
||||
print(
|
||||
"error in common.snapshotApp: the lengths of app_snapshot_path_arr, app_version_arr, and app_user_data_arr do not match."
|
||||
)
|
||||
return 1
|
||||
|
||||
fails = []
|
||||
@@ -303,7 +423,14 @@ class myUtils:
|
||||
snapshot_path = app_snapshot_path_arr[i]
|
||||
version = app_version_arr[i]
|
||||
user_data = app_user_data_arr[i]
|
||||
command = ['tar', 'cafv', f"{snapshot_path}{epoch}_{version}.tar.zst", "-C", f"{user_data}", "."]
|
||||
command = [
|
||||
"tar",
|
||||
"cafv",
|
||||
f"{snapshot_path}{epoch}_{version}.tar.zst",
|
||||
"-C",
|
||||
f"{user_data}",
|
||||
".",
|
||||
]
|
||||
|
||||
try:
|
||||
if not os.path.exists(snapshot_path):
|
||||
@@ -312,13 +439,18 @@ class myUtils:
|
||||
subprocess.run(command, check=True, env=self.new_env)
|
||||
if progress_bar:
|
||||
GLib.idle_add(progress_bar.set_visible, True)
|
||||
GLib.idle_add(progress_bar.set_fraction, (i + 1.0) / len(app_snapshot_path_arr))
|
||||
GLib.idle_add(
|
||||
progress_bar.set_fraction,
|
||||
(i + 1.0) / len(app_snapshot_path_arr),
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("error in common.snapshotApp:", e)
|
||||
fails.append(user_data)
|
||||
|
||||
if(int(time.time()) == epoch): # Wait 1s if the snapshot is made too quickly, to prevent overriding a snapshot file
|
||||
subprocess.run(['sleep', '1s'])
|
||||
if (
|
||||
int(time.time()) == epoch
|
||||
): # Wait 1s if the snapshot is made too quickly, to prevent overriding a snapshot file
|
||||
subprocess.run(["sleep", "1s"])
|
||||
|
||||
if progress_bar:
|
||||
GLib.idle_add(progress_bar.set_visible, False)
|
||||
|
||||
@@ -4,12 +4,13 @@ import subprocess
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/downgrade.ui")
|
||||
class DowngradeWindow(Adw.Window):
|
||||
__gtype_name__ = "DowngradeWindow"
|
||||
|
||||
new_env = dict( os.environ )
|
||||
new_env['LC_ALL'] = 'C'
|
||||
|
||||
new_env = dict(os.environ)
|
||||
new_env["LC_ALL"] = "C"
|
||||
|
||||
cancel_button = Gtk.Template.Child()
|
||||
apply_button = Gtk.Template.Child()
|
||||
@@ -34,14 +35,28 @@ class DowngradeWindow(Adw.Window):
|
||||
self.commit_to_use = self.versions[index][0]
|
||||
|
||||
def getCommits(self):
|
||||
output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "remote-info", "--log", self.remote, self.app_ref, f"--{self.install_type}"], capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
[
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"remote-info",
|
||||
"--log",
|
||||
self.remote,
|
||||
self.app_ref,
|
||||
f"--{self.install_type}",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.new_env,
|
||||
).stdout
|
||||
lines = output.strip().split("\n")
|
||||
columns = lines[0].split("\t")
|
||||
data = [columns]
|
||||
for line in lines[1:]:
|
||||
row = line.split("\t")
|
||||
data.append(row[0].strip())
|
||||
|
||||
|
||||
commits = []
|
||||
changes = []
|
||||
dates = []
|
||||
@@ -67,14 +82,24 @@ class DowngradeWindow(Adw.Window):
|
||||
self.versions_group.add(group_button)
|
||||
for i in range(len(self.versions)):
|
||||
version = self.versions[i]
|
||||
date_time = version[2].split(' ')
|
||||
date = date_time[0].split('-')
|
||||
date_time = version[2].split(" ")
|
||||
date = date_time[0].split("-")
|
||||
offset = date_time[2][:3] + ":" + date_time[2][3:]
|
||||
time = date_time[1].split(':')
|
||||
display_time = GLib.DateTime.new(GLib.TimeZone.new(offset), int(date[0]), int(date[1]), int(date[2]), int(time[0]), int(time[1]), int(time[2]))
|
||||
time = date_time[1].split(":")
|
||||
display_time = GLib.DateTime.new(
|
||||
GLib.TimeZone.new(offset),
|
||||
int(date[0]),
|
||||
int(date[1]),
|
||||
int(date[2]),
|
||||
int(time[0]),
|
||||
int(time[1]),
|
||||
int(time[2]),
|
||||
)
|
||||
display_time = display_time.format("%x %X")
|
||||
change = version[1].split('(')
|
||||
row = Adw.ActionRow(title=GLib.markup_escape_text(change[0]), subtitle=str(display_time))
|
||||
change = version[1].split("(")
|
||||
row = Adw.ActionRow(
|
||||
title=GLib.markup_escape_text(change[0]), subtitle=str(display_time)
|
||||
)
|
||||
row.set_tooltip_text(_("Commit Hash: {}").format(version[0]))
|
||||
select = Gtk.CheckButton()
|
||||
select.connect("toggled", self.selectionHandler, i)
|
||||
@@ -98,18 +123,26 @@ class DowngradeWindow(Adw.Window):
|
||||
self.progress_bar.set_visible = False
|
||||
|
||||
if self.response != 0:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not downgrade {}").format(self.app_name)))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not downgrade {}").format(self.app_name))
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
if self.mask_row.get_active():
|
||||
if self.my_utils.maskFlatpak(self.app_id, self.install_type) != 0:
|
||||
self.parent_window.toast_overlay.add_toast(Adw.Toast.new(_("Could not disable updates for {}").format(self.app_name)))
|
||||
self.parent_window.toast_overlay.add_toast(
|
||||
Adw.Toast.new(
|
||||
_("Could not disable updates for {}").format(self.app_name)
|
||||
)
|
||||
)
|
||||
|
||||
self.parent_window.refresh_list_of_flatpaks(self, False)
|
||||
self.close()
|
||||
|
||||
def downgradeThread(self):
|
||||
self.response = self.my_utils.downgradeFlatpak(self.app_ref, self.commit_to_use, self.install_type)
|
||||
self.response = self.my_utils.downgradeFlatpak(
|
||||
self.app_ref, self.commit_to_use, self.install_type
|
||||
)
|
||||
|
||||
def onApply(self):
|
||||
self.set_title(_("Downgrading…"))
|
||||
@@ -118,7 +151,7 @@ class DowngradeWindow(Adw.Window):
|
||||
self.should_pulse = True
|
||||
self.progress_bar.set_visible(True)
|
||||
self.pulser()
|
||||
|
||||
|
||||
task = Gio.Task.new(None, None, lambda *_: self.downgradeCallack())
|
||||
task.run_in_thread(lambda *_: self.downgradeThread())
|
||||
|
||||
@@ -152,8 +185,12 @@ class DowngradeWindow(Adw.Window):
|
||||
self.add_controller(event_controller)
|
||||
self.set_title(_("Fetching Releases…"))
|
||||
self.set_transient_for(parent_window)
|
||||
self.mask_row.set_subtitle(_("Ensure that {} will never be updated to a newer version").format(self.app_name))
|
||||
self.mask_row.set_subtitle(
|
||||
_("Ensure that {} will never be updated to a newer version").format(
|
||||
self.app_name
|
||||
)
|
||||
)
|
||||
|
||||
self.generateList()
|
||||
|
||||
self.present()
|
||||
self.present()
|
||||
|
||||
@@ -4,6 +4,7 @@ import subprocess
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/filter.ui")
|
||||
class FilterWindow(Adw.Window):
|
||||
__gtype_name__ = "FilterWindow"
|
||||
@@ -15,7 +16,6 @@ class FilterWindow(Adw.Window):
|
||||
remotes_expander = Gtk.Template.Child()
|
||||
runtimes_expander = Gtk.Template.Child()
|
||||
|
||||
|
||||
def key_handler(self, _a, event, _c, _d):
|
||||
if event == Gdk.KEY_Escape:
|
||||
self.close()
|
||||
@@ -35,10 +35,12 @@ class FilterWindow(Adw.Window):
|
||||
self.apply_button.set_sensitive(False)
|
||||
return
|
||||
|
||||
if self.apps_switch.get_active() and\
|
||||
(not self.runtimes_switch.get_active()) and\
|
||||
(not self.remotes_expander_switch.get_active()) and\
|
||||
(not self.runtimes_expander_switch.get_active()):
|
||||
if (
|
||||
self.apps_switch.get_active()
|
||||
and (not self.runtimes_switch.get_active())
|
||||
and (not self.remotes_expander_switch.get_active())
|
||||
and (not self.runtimes_expander_switch.get_active())
|
||||
):
|
||||
self.apply_button.set_sensitive(False)
|
||||
return
|
||||
|
||||
@@ -69,7 +71,7 @@ class FilterWindow(Adw.Window):
|
||||
|
||||
def runtimesEnableHandler(self, switch, is_enabled):
|
||||
self.runtimes_expander.set_enable_expansion(is_enabled)
|
||||
|
||||
|
||||
for i in range(len(self.runtime_checkboxes)):
|
||||
self.runtime_checkboxes[i].set_active(not is_enabled)
|
||||
|
||||
@@ -82,21 +84,25 @@ class FilterWindow(Adw.Window):
|
||||
self.filter_list[4].append(runtime)
|
||||
else:
|
||||
self.filter_list[4].remove(runtime)
|
||||
|
||||
|
||||
self.isListApplicable()
|
||||
|
||||
def generateList(self):
|
||||
self.remotes_expander_switch = Gtk.Switch(valign=Gtk.Align.CENTER)
|
||||
self.runtimes_expander_switch = Gtk.Switch(valign=Gtk.Align.CENTER)
|
||||
|
||||
|
||||
dependent_runtimes = self.my_utils.getDependentRuntimes()
|
||||
|
||||
if len(self.host_remotes) < 2: # Don't give the ability to filter by remotes if there is only 1
|
||||
if (
|
||||
len(self.host_remotes) < 2
|
||||
): # Don't give the ability to filter by remotes if there is only 1
|
||||
self.remotes_expander.set_visible(False)
|
||||
|
||||
if len(dependent_runtimes) < 2: # Don't give the ability to filter by runtimes if there is only 1
|
||||
if (
|
||||
len(dependent_runtimes) < 2
|
||||
): # Don't give the ability to filter by runtimes if there is only 1
|
||||
self.runtimes_expander.set_visible(False)
|
||||
|
||||
|
||||
self.remote_checkboxes = []
|
||||
total = 0
|
||||
for i in range(len(self.host_remotes)):
|
||||
@@ -125,7 +131,9 @@ class FilterWindow(Adw.Window):
|
||||
|
||||
remote_row.add_suffix(remote_check)
|
||||
remote_row.set_activatable_widget(remote_check)
|
||||
remote_check.connect("toggled", self.remoteCheckHandler, install_type, name)
|
||||
remote_check.connect(
|
||||
"toggled", self.remoteCheckHandler, install_type, name
|
||||
)
|
||||
self.remote_checkboxes.append(remote_check)
|
||||
remote_check.set_active(True)
|
||||
except:
|
||||
@@ -154,7 +162,7 @@ class FilterWindow(Adw.Window):
|
||||
if not self.remotes_expander_switch.get_active():
|
||||
self.filter_list[3] = "all"
|
||||
if not self.runtimes_expander_switch.get_active():
|
||||
self.filter_list[4] = "all"
|
||||
self.filter_list[4] = "all"
|
||||
|
||||
def disableFilterToggle(self, _widget):
|
||||
self.app_window.filter_button.set_active(self.has_apply_button_been_clicked)
|
||||
@@ -176,8 +184,12 @@ class FilterWindow(Adw.Window):
|
||||
self.add_controller(event_controller)
|
||||
|
||||
# Connections
|
||||
self.apply_button.connect("clicked", lambda *_: self.setHas_apply_button_been_clicked(True))
|
||||
self.apply_button.connect("clicked", lambda *_: main_window.applyFilter(self.filter_list))
|
||||
self.apply_button.connect(
|
||||
"clicked", lambda *_: self.setHas_apply_button_been_clicked(True)
|
||||
)
|
||||
self.apply_button.connect(
|
||||
"clicked", lambda *_: main_window.applyFilter(self.filter_list)
|
||||
)
|
||||
self.apply_button.connect("clicked", lambda *_: self.close())
|
||||
|
||||
self.cancel_button.connect("clicked", lambda *_: self.close())
|
||||
@@ -191,7 +203,7 @@ class FilterWindow(Adw.Window):
|
||||
# Calls
|
||||
self.apps_switch.set_active(True)
|
||||
self.set_size_request(260, 230)
|
||||
if not self.host_remotes[0][0] == '':
|
||||
if not self.host_remotes[0][0] == "":
|
||||
self.generateList()
|
||||
else:
|
||||
self.remotes_expander.set_visible(False)
|
||||
@@ -199,5 +211,3 @@ class FilterWindow(Adw.Window):
|
||||
self.filter_list[2] = "all"
|
||||
self.filter_list[3] = "all"
|
||||
self.filter_list[4] = "all"
|
||||
|
||||
|
||||
|
||||
91
src/main.py
91
src/main.py
@@ -32,6 +32,7 @@ from .orphans_window import OrphansWindow
|
||||
from .search_install_window import SearchInstallWindow
|
||||
from .const import Config
|
||||
|
||||
|
||||
class WarehouseApplication(Adw.Application):
|
||||
"""The main application singleton class."""
|
||||
|
||||
@@ -48,22 +49,54 @@ class WarehouseApplication(Adw.Application):
|
||||
self.create_action("preferences", self.on_preferences_action)
|
||||
self.create_action("search", self.on_search_action, ["<primary>f"])
|
||||
self.create_action("manage-data-folders", self.manage_data_shortcut)
|
||||
self.create_action("toggle-batch-mode", self.batch_mode_shortcut, ["<primary>b", "<primary>Return"])
|
||||
self.create_action("toggle-batch-mode-keypad", self.batch_mode_shortcut, ["<primary>KP_Enter"]) # This action is not added to the shortcuts window
|
||||
self.create_action("manage-data-folders", self.manage_data_shortcut, ["<primary>d"])
|
||||
self.create_action("refresh-list", self.refresh_list_shortcut, ["<primary>r", "F5"])
|
||||
self.create_action("show-remotes-window", self.show_remotes_shortcut, ["<primary>m"])
|
||||
self.create_action(
|
||||
"toggle-batch-mode",
|
||||
self.batch_mode_shortcut,
|
||||
["<primary>b", "<primary>Return"],
|
||||
)
|
||||
self.create_action(
|
||||
"toggle-batch-mode-keypad", self.batch_mode_shortcut, ["<primary>KP_Enter"]
|
||||
) # This action is not added to the shortcuts window
|
||||
self.create_action(
|
||||
"manage-data-folders", self.manage_data_shortcut, ["<primary>d"]
|
||||
)
|
||||
self.create_action(
|
||||
"refresh-list", self.refresh_list_shortcut, ["<primary>r", "F5"]
|
||||
)
|
||||
self.create_action(
|
||||
"show-remotes-window", self.show_remotes_shortcut, ["<primary>m"]
|
||||
)
|
||||
self.create_action("set-filter", self.filters_shortcut, ["<primary>t"])
|
||||
self.create_action("install-from-file", self.install_from_file, ["<primary>o"])
|
||||
self.create_action("open-menu", self.main_menu_shortcut, ["F10"])
|
||||
# self.create_action("open-search-install", self.open_search_install, ["<primary>i"])
|
||||
|
||||
gtk_version = str(Gtk.MAJOR_VERSION) + "." + str(Gtk.MINOR_VERSION) + "." + str(Gtk.MICRO_VERSION)
|
||||
adw_version = str(Adw.MAJOR_VERSION) + "." + str(Adw.MINOR_VERSION) + "." + str(Adw.MICRO_VERSION)
|
||||
gtk_version = (
|
||||
str(Gtk.MAJOR_VERSION)
|
||||
+ "."
|
||||
+ str(Gtk.MINOR_VERSION)
|
||||
+ "."
|
||||
+ str(Gtk.MICRO_VERSION)
|
||||
)
|
||||
adw_version = (
|
||||
str(Adw.MAJOR_VERSION)
|
||||
+ "."
|
||||
+ str(Adw.MINOR_VERSION)
|
||||
+ "."
|
||||
+ str(Adw.MICRO_VERSION)
|
||||
)
|
||||
os_string = GLib.get_os_info("NAME") + " " + GLib.get_os_info("VERSION")
|
||||
lang = GLib.environ_getenv(GLib.get_environ(), "LANG")
|
||||
|
||||
self.troubleshooting = self.troubleshooting.format( os = os_string, wv = self.version, gtk = gtk_version, adw = adw_version, profile = Config.PROFILE, app_id = self.get_application_id(), lang = lang )
|
||||
self.troubleshooting = self.troubleshooting.format(
|
||||
os=os_string,
|
||||
wv=self.version,
|
||||
gtk=gtk_version,
|
||||
adw=adw_version,
|
||||
profile=Config.PROFILE,
|
||||
app_id=self.get_application_id(),
|
||||
lang=lang,
|
||||
)
|
||||
|
||||
def open_search_install(self, widget, _):
|
||||
SearchInstallWindow(self.props.active_window).present()
|
||||
@@ -129,25 +162,37 @@ class WarehouseApplication(Adw.Application):
|
||||
application_icon="io.github.flattool.Warehouse",
|
||||
developer_name="Heliguy",
|
||||
version=self.version,
|
||||
developers=["Heliguy https://github.com/heliguy4599", "kramo https://kramo.hu"],
|
||||
artists=["Heliguy https://github.com/heliguy4599", "kramo https://kramo.hu", "Amy https://github.com/AtiusAmy", "eryn https://github.com/hericiumvevo"],
|
||||
copyright='© 2023 Heliguy',
|
||||
developers=[
|
||||
"Heliguy https://github.com/heliguy4599",
|
||||
"kramo https://kramo.hu",
|
||||
],
|
||||
artists=[
|
||||
"Heliguy https://github.com/heliguy4599",
|
||||
"kramo https://kramo.hu",
|
||||
"Amy https://github.com/AtiusAmy",
|
||||
"eryn https://github.com/hericiumvevo",
|
||||
],
|
||||
copyright="© 2023 Heliguy",
|
||||
license_type=Gtk.License.GPL_3_0_ONLY,
|
||||
debug_info=self.troubleshooting,
|
||||
# Translators: do one of the following, one per line: Your Name, Your Name <email@email.org>, Your Name https://websi.te
|
||||
translator_credits=_("translator-credits"),
|
||||
debug_info_filename="{}.txt".format(self.get_application_id()),
|
||||
website='https://github.com/flattool/warehouse',
|
||||
support_url='https://matrix.to/#/#warehouse-development:matrix.org',
|
||||
issue_url='https://github.com/flattool/warehouse/issues')
|
||||
website="https://github.com/flattool/warehouse",
|
||||
support_url="https://matrix.to/#/#warehouse-development:matrix.org",
|
||||
issue_url="https://github.com/flattool/warehouse/issues",
|
||||
)
|
||||
about.add_link(_("Donate"), "https://github.com/flattool/warehouse/issues")
|
||||
about.add_credit_section(_("Contributors"), [
|
||||
# Contributors: do one of the following, one per line: Your Name, Your Name <email@email.org>, Your Name https://websi.te
|
||||
"Win <winsdominoes2018@gmail.com>",
|
||||
"Óscar Fernández Díaz",
|
||||
"Runar https://github.com/runarcn",
|
||||
"skøldis <warehouse@turtle.garden>"
|
||||
])
|
||||
about.add_credit_section(
|
||||
_("Contributors"),
|
||||
[
|
||||
# Contributors: do one of the following, one per line: Your Name, Your Name <email@email.org>, Your Name https://websi.te
|
||||
"Win <winsdominoes2018@gmail.com>",
|
||||
"Óscar Fernández Díaz",
|
||||
"Runar https://github.com/runarcn",
|
||||
"skøldis <warehouse@turtle.garden>",
|
||||
],
|
||||
)
|
||||
about.present()
|
||||
|
||||
def on_preferences_action(self, widget, _):
|
||||
@@ -155,7 +200,9 @@ class WarehouseApplication(Adw.Application):
|
||||
print("app.preferences action activated")
|
||||
|
||||
def on_search_action(self, widget, _):
|
||||
self.props.active_window.search_bar.set_search_mode(not self.props.active_window.search_bar.get_search_mode())
|
||||
self.props.active_window.search_bar.set_search_mode(
|
||||
not self.props.active_window.search_bar.get_search_mode()
|
||||
)
|
||||
|
||||
def create_action(self, name, callback, shortcuts=None):
|
||||
"""Add an application action.
|
||||
|
||||
@@ -4,6 +4,7 @@ import subprocess
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/orphans.ui")
|
||||
class OrphansWindow(Adw.Window):
|
||||
__gtype_name__ = "OrphansWindow"
|
||||
@@ -37,7 +38,7 @@ class OrphansWindow(Adw.Window):
|
||||
def key_handler(self, _a, event, _c, _d):
|
||||
if event == Gdk.KEY_Escape:
|
||||
self.close()
|
||||
|
||||
|
||||
def selectionHandler(self, widget, dir_name):
|
||||
if widget.get_active():
|
||||
self.selected_dirs.append(dir_name)
|
||||
@@ -45,9 +46,13 @@ class OrphansWindow(Adw.Window):
|
||||
self.selected_dirs.remove(dir_name)
|
||||
|
||||
if len(self.selected_dirs) == 0:
|
||||
self.set_title(self.window_title) # Set the window title back to what it was when there are no selected dirs
|
||||
self.set_title(
|
||||
self.window_title
|
||||
) # Set the window title back to what it was when there are no selected dirs
|
||||
else:
|
||||
self.set_title(("{} selected").format(str(len(self.selected_dirs)))) # Set the window title to the amount of selected dirs
|
||||
self.set_title(
|
||||
("{} selected").format(str(len(self.selected_dirs)))
|
||||
) # Set the window title to the amount of selected dirs
|
||||
|
||||
if len(self.selected_dirs) == 0:
|
||||
self.install_button.set_sensitive(False)
|
||||
@@ -67,12 +72,14 @@ class OrphansWindow(Adw.Window):
|
||||
self.generateList()
|
||||
self.progress_bar.set_visible(False)
|
||||
self.app_window.refresh_list_of_flatpaks(self, False)
|
||||
self.disconnect(self.no_close_id) # Make window able to close
|
||||
self.disconnect(self.no_close_id) # Make window able to close
|
||||
self.search_button.set_sensitive(True)
|
||||
if self.my_utils.install_success:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Installed successfully")))
|
||||
else:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not install some apps")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not install some apps"))
|
||||
)
|
||||
|
||||
def installHandler(self):
|
||||
self.main_stack.set_visible_child(self.installing)
|
||||
@@ -80,15 +87,20 @@ class OrphansWindow(Adw.Window):
|
||||
self.set_title(self.window_title)
|
||||
self.keep_checking = True
|
||||
task = Gio.Task.new(None, None, self.installCallback)
|
||||
task.run_in_thread(lambda _task, _obj, _data, _cancellable, id_list=self.selected_dirs, remote=self.selected_remote, app_type=self.selected_remote_type, progress_bar=self.progress_bar: self.my_utils.installFlatpak(id_list, remote, app_type, progress_bar))
|
||||
|
||||
def installButtonHandler(self, button):
|
||||
task.run_in_thread(
|
||||
lambda _task, _obj, _data, _cancellable, id_list=self.selected_dirs, remote=self.selected_remote, app_type=self.selected_remote_type, progress_bar=self.progress_bar: self.my_utils.installFlatpak(
|
||||
id_list, remote, app_type, progress_bar
|
||||
)
|
||||
)
|
||||
|
||||
def installButtonHandler(self, button):
|
||||
def remote_select_handler(button, index):
|
||||
if not button.get_active():
|
||||
return
|
||||
self.selected_remote = self.host_remotes[index][0]
|
||||
self.selected_remote_type = self.my_utils.getInstallType(self.host_remotes[index][7])
|
||||
self.selected_remote_type = self.my_utils.getInstallType(
|
||||
self.host_remotes[index][7]
|
||||
)
|
||||
|
||||
def onResponse(dialog, response_id, _function):
|
||||
if response_id == "cancel":
|
||||
@@ -96,9 +108,15 @@ class OrphansWindow(Adw.Window):
|
||||
self.installHandler()
|
||||
self.progress_bar.set_visible(True)
|
||||
self.action_bar.set_visible(False)
|
||||
self.no_close_id = self.connect("close-request", lambda event: True) # Make window unable to close
|
||||
|
||||
dialog = Adw.MessageDialog.new(self, _("Attempt to Install?"), _("Warehouse will attempt to install apps matching the selected data."))
|
||||
self.no_close_id = self.connect(
|
||||
"close-request", lambda event: True
|
||||
) # Make window unable to close
|
||||
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self,
|
||||
_("Attempt to Install?"),
|
||||
_("Warehouse will attempt to install apps matching the selected data."),
|
||||
)
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.add_response("continue", _("Install"))
|
||||
@@ -135,7 +153,7 @@ class OrphansWindow(Adw.Window):
|
||||
else:
|
||||
remote_row.set_subtitle(_("Unknown install type"))
|
||||
|
||||
if remote_row.get_title() == '-':
|
||||
if remote_row.get_title() == "-":
|
||||
remote_row.set_title(self.host_remotes[i][0])
|
||||
|
||||
if total_added > 0:
|
||||
@@ -146,7 +164,7 @@ class OrphansWindow(Adw.Window):
|
||||
total_added += 1
|
||||
|
||||
remote_select_buttons[0].set_active(True)
|
||||
|
||||
|
||||
if total_added > 1:
|
||||
dialog.set_extra_child(remotes_scroll)
|
||||
|
||||
@@ -154,7 +172,6 @@ class OrphansWindow(Adw.Window):
|
||||
dialog.present()
|
||||
|
||||
def trashHandler(self, button):
|
||||
|
||||
def onResponse(dialog, response_id, _function):
|
||||
if response_id == "cancel":
|
||||
return
|
||||
@@ -163,8 +180,10 @@ class OrphansWindow(Adw.Window):
|
||||
self.my_utils.trashFolder(path)
|
||||
self.select_all_button.set_active(False)
|
||||
self.generateList()
|
||||
|
||||
dialog = Adw.MessageDialog.new(self, _("Trash folders?"), _("These folders will be sent to the trash."))
|
||||
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self, _("Trash folders?"), _("These folders will be sent to the trash.")
|
||||
)
|
||||
dialog.connect("response", onResponse, dialog.choose_finish)
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
@@ -176,7 +195,9 @@ class OrphansWindow(Adw.Window):
|
||||
try:
|
||||
Gio.AppInfo.launch_default_for_uri(f"file://{path}", None)
|
||||
except GLib.GError:
|
||||
properties_toast_overlay.add_toast(Adw.Toast.new(_("Could not open folder")))
|
||||
properties_toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not open folder"))
|
||||
)
|
||||
|
||||
def sizeCallBack(self, row_index):
|
||||
row = self.list_of_data.get_row_at_index(row_index)
|
||||
@@ -191,8 +212,10 @@ class OrphansWindow(Adw.Window):
|
||||
self.data_rows = []
|
||||
self.host_flatpaks = self.my_utils.getHostFlatpaks()
|
||||
|
||||
if self.host_flatpaks == [['', '']]:
|
||||
self.app_window.toast_overlay.add_toast(Adw.Toast.new(_("Could not manage data")))
|
||||
if self.host_flatpaks == [["", ""]]:
|
||||
self.app_window.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not manage data"))
|
||||
)
|
||||
self.this_just_crashes_the_window_so_it_doesnt_open()
|
||||
return
|
||||
|
||||
@@ -221,12 +244,24 @@ class OrphansWindow(Adw.Window):
|
||||
self.data_rows.append([dir_row])
|
||||
path = self.user_data_path + dir_name
|
||||
index = len(self.data_rows) - 1
|
||||
task = Gio.Task.new(None, None, lambda *_, index=index: self.sizeCallBack(index))
|
||||
task.run_in_thread(lambda _task, _obj, _data, _cancellable, *_, index=index: self.sizeThread(index, path))
|
||||
task = Gio.Task.new(
|
||||
None, None, lambda *_, index=index: self.sizeCallBack(index)
|
||||
)
|
||||
task.run_in_thread(
|
||||
lambda _task, _obj, _data, _cancellable, *_, index=index: self.sizeThread(
|
||||
index, path
|
||||
)
|
||||
)
|
||||
|
||||
open_row_button = Gtk.Button(icon_name="document-open-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Open User Data Folder"))
|
||||
open_row_button = Gtk.Button(
|
||||
icon_name="document-open-symbolic",
|
||||
valign=Gtk.Align.CENTER,
|
||||
tooltip_text=_("Open User Data Folder"),
|
||||
)
|
||||
open_row_button.add_css_class("flat")
|
||||
open_row_button.connect("clicked", self.open_button_handler, (self.user_data_path + dir_name))
|
||||
open_row_button.connect(
|
||||
"clicked", self.open_button_handler, (self.user_data_path + dir_name)
|
||||
)
|
||||
dir_row.add_suffix(open_row_button)
|
||||
|
||||
select_button = Gtk.CheckButton()
|
||||
@@ -247,7 +282,7 @@ class OrphansWindow(Adw.Window):
|
||||
self.action_bar.set_visible(True)
|
||||
|
||||
def filter_func(self, row):
|
||||
if (self.search_entry.get_text().lower() in row.get_title().lower()):
|
||||
if self.search_entry.get_text().lower() in row.get_title().lower():
|
||||
self.is_result = True
|
||||
return True
|
||||
|
||||
@@ -276,7 +311,9 @@ class OrphansWindow(Adw.Window):
|
||||
|
||||
def __init__(self, main_window, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.my_utils = myUtils(self) # Access common utils and set the window to this window
|
||||
self.my_utils = myUtils(
|
||||
self
|
||||
) # Access common utils and set the window to this window
|
||||
self.host_remotes = self.my_utils.getHostRemotes()
|
||||
self.host_flatpaks = self.my_utils.getHostFlatpaks()
|
||||
|
||||
@@ -294,7 +331,7 @@ class OrphansWindow(Adw.Window):
|
||||
self.add_controller(event_controller)
|
||||
|
||||
self.install_button.connect("clicked", self.installButtonHandler)
|
||||
if self.host_remotes[0][0] == '':
|
||||
if self.host_remotes[0][0] == "":
|
||||
self.install_button.set_visible(False)
|
||||
self.trash_button.connect("clicked", self.trashHandler)
|
||||
self.select_all_button.connect("toggled", self.selectAllHandler)
|
||||
@@ -304,4 +341,4 @@ class OrphansWindow(Adw.Window):
|
||||
self.search_entry.connect("search-changed", self.on_invalidate)
|
||||
self.search_bar.connect("notify", self.on_change)
|
||||
self.search_bar.connect_entry(self.search_entry)
|
||||
self.oepn_folder_button.connect("clicked", self.open_button_handler)
|
||||
self.oepn_folder_button.connect("clicked", self.open_button_handler)
|
||||
|
||||
@@ -4,12 +4,13 @@ import subprocess
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/properties.ui")
|
||||
class PropertiesWindow(Adw.Window):
|
||||
__gtype_name__ = "PropertiesWindow"
|
||||
|
||||
new_env = dict( os.environ )
|
||||
new_env['LC_ALL'] = 'C'
|
||||
|
||||
new_env = dict(os.environ)
|
||||
new_env["LC_ALL"] = "C"
|
||||
host_home = str(pathlib.Path.home())
|
||||
user_data_path = host_home + "/.var/app/"
|
||||
|
||||
@@ -81,9 +82,19 @@ class PropertiesWindow(Adw.Window):
|
||||
|
||||
def generateLower(self):
|
||||
column_headers = [
|
||||
_('Name'), _('Description'), _('App ID'), _('Version'), _('Branch'),
|
||||
_('Arch'), _('Origin'), _('Installation'), _('Ref'), _('Active Commit'),
|
||||
_('Latest Commit'), _('Installed Size'), _('Options')
|
||||
_("Name"),
|
||||
_("Description"),
|
||||
_("App ID"),
|
||||
_("Version"),
|
||||
_("Branch"),
|
||||
_("Arch"),
|
||||
_("Origin"),
|
||||
_("Installation"),
|
||||
_("Ref"),
|
||||
_("Active Commit"),
|
||||
_("Latest Commit"),
|
||||
_("Installed Size"),
|
||||
_("Options"),
|
||||
]
|
||||
|
||||
for i in range(len(column_headers)):
|
||||
@@ -93,7 +104,10 @@ class PropertiesWindow(Adw.Window):
|
||||
row = Adw.ActionRow(title=column_headers[i], activatable=True)
|
||||
row.add_suffix(Gtk.Image.new_from_icon_name("edit-copy-symbolic"))
|
||||
row.set_subtitle(GLib.markup_escape_text(self.current_flatpak[i]))
|
||||
row.connect("activated", lambda *_a, row=row: self.copyItem(row.get_subtitle(), row.get_title()))
|
||||
row.connect(
|
||||
"activated",
|
||||
lambda *_a, row=row: self.copyItem(row.get_subtitle(), row.get_title()),
|
||||
)
|
||||
self.lower.add(row)
|
||||
|
||||
def viewAppsHandler(self, widget):
|
||||
@@ -121,16 +135,20 @@ class PropertiesWindow(Adw.Window):
|
||||
self.open_data.set_visible(False)
|
||||
self.trash_data.set_visible(False)
|
||||
else:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not trash user data")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not trash user data"))
|
||||
)
|
||||
|
||||
dialog = Adw.MessageDialog.new(self, _("Send {}'s User Data to the Trash?").format(self.app_name))
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self, _("Send {}'s User Data to the Trash?").format(self.app_name)
|
||||
)
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("continue", _("Trash Data"))
|
||||
dialog.set_response_appearance("continue", Adw.ResponseAppearance.DESTRUCTIVE)
|
||||
dialog.connect("response", onResponse, dialog.choose_finish)
|
||||
dialog.present()
|
||||
|
||||
|
||||
def __init__(self, flatpak_index, host_flatpaks, parent_window, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.my_utils = myUtils(self)
|
||||
@@ -147,27 +165,47 @@ class PropertiesWindow(Adw.Window):
|
||||
self.user_data_path += self.app_id
|
||||
|
||||
self.details.connect("activated", self.show_details)
|
||||
self.runtime_copy.connect("clicked", lambda *_: self.copyItem(self.runtime.get_subtitle(), self.runtime.get_title()))
|
||||
self.runtime_copy.connect(
|
||||
"clicked",
|
||||
lambda *_: self.copyItem(
|
||||
self.runtime.get_subtitle(), self.runtime.get_title()
|
||||
),
|
||||
)
|
||||
self.runtime_properties.connect("clicked", lambda *_: self.close())
|
||||
self.runtime_properties.connect("clicked", lambda *_: self.showPropertiesHandler())
|
||||
self.runtime_properties.connect(
|
||||
"clicked", lambda *_: self.showPropertiesHandler()
|
||||
)
|
||||
self.view_apps.connect("activated", self.viewAppsHandler)
|
||||
self.trash_data.connect("clicked", lambda *_: self.trashDataHandler())
|
||||
|
||||
|
||||
if "eol" in self.current_flatpak[12]:
|
||||
self.eol_app_banner.set_revealed(True)
|
||||
self.eol_app_banner.set_title(_("{} has reached its End of Life and will not receive any security updates").format(self.app_name))
|
||||
self.eol_app_banner.set_title(
|
||||
_(
|
||||
"{} has reached its End of Life and will not receive any security updates"
|
||||
).format(self.app_name)
|
||||
)
|
||||
|
||||
if self.current_flatpak[13] in parent_window.eol_list:
|
||||
self.eol_runtime_banner.set_revealed(True)
|
||||
self.eol_runtime_banner.set_title(_("{}'s runtime has reached its End of Life and will not receive any security updates").format(self.app_name))
|
||||
self.eol_runtime_banner.set_title(
|
||||
_(
|
||||
"{}'s runtime has reached its End of Life and will not receive any security updates"
|
||||
).format(self.app_name)
|
||||
)
|
||||
|
||||
if self.app_id in self.my_utils.getHostMasks("system") or self.app_id in self.my_utils.getHostMasks("user"):
|
||||
if self.app_id in self.my_utils.getHostMasks(
|
||||
"system"
|
||||
) or self.app_id in self.my_utils.getHostMasks("user"):
|
||||
self.mask_banner.set_revealed(True)
|
||||
self.mask_banner.set_title(_("{} is masked and will not be updated").format(self.app_name))
|
||||
self.mask_banner.set_title(
|
||||
_("{} is masked and will not be updated").format(self.app_name)
|
||||
)
|
||||
|
||||
def key_handler(_a, event, _c, _d):
|
||||
if event == Gdk.KEY_Escape:
|
||||
self.close()
|
||||
|
||||
event_controller = Gtk.EventControllerKey()
|
||||
event_controller.connect("key-pressed", key_handler)
|
||||
self.add_controller(event_controller)
|
||||
@@ -178,4 +216,4 @@ class PropertiesWindow(Adw.Window):
|
||||
self.set_title(_("{} Properties").format(self.app_name))
|
||||
self.set_size_request(260, 230)
|
||||
self.set_transient_for(parent_window)
|
||||
self.present()
|
||||
self.present()
|
||||
|
||||
@@ -4,6 +4,7 @@ import subprocess
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/remotes.ui")
|
||||
class RemotesWindow(Adw.Window):
|
||||
__gtype_name__ = "RemotesWindow"
|
||||
@@ -34,7 +35,12 @@ class RemotesWindow(Adw.Window):
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(text))
|
||||
|
||||
def get_host_flatpaks(self):
|
||||
output = subprocess.run(["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"], capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
["flatpak-spawn", "--host", "flatpak", "list", "--columns=all"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.new_env,
|
||||
).stdout
|
||||
lines = output.strip().split("\n")
|
||||
columns = lines[0].split("\t")
|
||||
data = [columns]
|
||||
@@ -50,7 +56,15 @@ class RemotesWindow(Adw.Window):
|
||||
name = self.host_remotes[index][0]
|
||||
title = self.host_remotes[index][1]
|
||||
install_type = self.host_remotes[index][7]
|
||||
command = ['flatpak-spawn', '--host', 'flatpak', 'remote-delete', '--force', name, f'--{install_type}']
|
||||
command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"remote-delete",
|
||||
"--force",
|
||||
name,
|
||||
f"--{install_type}",
|
||||
]
|
||||
try:
|
||||
subprocess.run(command, capture_output=True, check=True, env=self.new_env)
|
||||
except subprocess.CalledProcessError as e:
|
||||
@@ -63,7 +77,9 @@ class RemotesWindow(Adw.Window):
|
||||
title = self.host_remotes[index][1]
|
||||
install_type = self.host_remotes[index][7]
|
||||
|
||||
body_text = _("Any installed apps from {} will stop receiving updates").format(name)
|
||||
body_text = _("Any installed apps from {} will stop receiving updates").format(
|
||||
name
|
||||
)
|
||||
dialog = Adw.MessageDialog.new(self, _("Remove {}?").format(title), body_text)
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
@@ -82,11 +98,24 @@ class RemotesWindow(Adw.Window):
|
||||
type = "user"
|
||||
|
||||
try:
|
||||
command = ['flatpak-spawn', '--host', 'flatpak', 'remote-modify', name, f"--{type}", "--enable"]
|
||||
command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"remote-modify",
|
||||
name,
|
||||
f"--{type}",
|
||||
"--enable",
|
||||
]
|
||||
subprocess.run(command, capture_output=False, check=True, env=self.new_env)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not enable {}").format(name)))
|
||||
print(f"error in remotes_window.enable_handler: could not enable remote {name}:", e)
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not enable {}").format(name))
|
||||
)
|
||||
print(
|
||||
f"error in remotes_window.enable_handler: could not enable remote {name}:",
|
||||
e,
|
||||
)
|
||||
|
||||
self.generate_list()
|
||||
|
||||
@@ -95,11 +124,26 @@ class RemotesWindow(Adw.Window):
|
||||
if response == "cancel":
|
||||
return
|
||||
try:
|
||||
command = ['flatpak-spawn', '--host', 'flatpak', 'remote-modify', name, f"--{type}", "--disable"]
|
||||
subprocess.run(command, capture_output=False, check=True, env=self.new_env)
|
||||
command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"remote-modify",
|
||||
name,
|
||||
f"--{type}",
|
||||
"--disable",
|
||||
]
|
||||
subprocess.run(
|
||||
command, capture_output=False, check=True, env=self.new_env
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not disable {}").format(name)))
|
||||
print(f"error in remotes_window.enable_handler: could not disable remote {name}:", e)
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not disable {}").format(name))
|
||||
)
|
||||
print(
|
||||
f"error in remotes_window.enable_handler: could not disable remote {name}:",
|
||||
e,
|
||||
)
|
||||
|
||||
self.generate_list()
|
||||
|
||||
@@ -114,7 +158,9 @@ class RemotesWindow(Adw.Window):
|
||||
|
||||
popoever.popdown()
|
||||
|
||||
body_text = _("Any installed apps from {} will stop receiving updates").format(name)
|
||||
body_text = _("Any installed apps from {} will stop receiving updates").format(
|
||||
name
|
||||
)
|
||||
dialog = Adw.MessageDialog.new(self, _("Disable {}?").format(title), body_text)
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
@@ -130,7 +176,10 @@ class RemotesWindow(Adw.Window):
|
||||
type = "system"
|
||||
else:
|
||||
self.make_toast(_("Could not view apps").format(to_copy))
|
||||
print("error in remotes_window.view_apps(): remote installation type is not either system or user. type is:", type)
|
||||
print(
|
||||
"error in remotes_window.view_apps(): remote installation type is not either system or user. type is:",
|
||||
type,
|
||||
)
|
||||
return
|
||||
self.app_window.should_open_filter_window = False
|
||||
self.app_window.filter_button.set_active(True)
|
||||
@@ -140,9 +189,13 @@ class RemotesWindow(Adw.Window):
|
||||
|
||||
def generate_list(self):
|
||||
if self.show_disabled_button.get_active():
|
||||
self.show_disabled_button_button_content.set_icon_name("eye-open-negative-filled-symbolic")
|
||||
self.show_disabled_button_button_content.set_icon_name(
|
||||
"eye-open-negative-filled-symbolic"
|
||||
)
|
||||
else:
|
||||
self.show_disabled_button_button_content.set_icon_name("eye-not-looking-symbolic")
|
||||
self.show_disabled_button_button_content.set_icon_name(
|
||||
"eye-not-looking-symbolic"
|
||||
)
|
||||
|
||||
self.host_remotes = self.my_utils.getHostRemotes()
|
||||
self.host_flatpaks = self.get_host_flatpaks()
|
||||
@@ -164,28 +217,55 @@ class RemotesWindow(Adw.Window):
|
||||
install_type = self.host_remotes[i][7]
|
||||
remote_row = Adw.ActionRow(title=title)
|
||||
|
||||
more = Gtk.MenuButton(icon_name="view-more-symbolic", valign=Gtk.Align.CENTER)
|
||||
more = Gtk.MenuButton(
|
||||
icon_name="view-more-symbolic", valign=Gtk.Align.CENTER
|
||||
)
|
||||
more.add_css_class("flat")
|
||||
options = Gtk.Popover()
|
||||
options_box = Gtk.Box(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, orientation=Gtk.Orientation.VERTICAL)
|
||||
|
||||
options_box = Gtk.Box(
|
||||
halign=Gtk.Align.CENTER,
|
||||
valign=Gtk.Align.CENTER,
|
||||
orientation=Gtk.Orientation.VERTICAL,
|
||||
)
|
||||
|
||||
filter_button = Gtk.Button()
|
||||
filter_button.set_child(Adw.ButtonContent(icon_name="funnel-symbolic", label=_("Set Filter")))
|
||||
filter_button.set_child(
|
||||
Adw.ButtonContent(
|
||||
icon_name="funnel-symbolic", label=_("Set Filter")
|
||||
)
|
||||
)
|
||||
filter_button.add_css_class("flat")
|
||||
filter_button.connect("clicked", lambda *_, i=i: self.view_paks(self.host_remotes[i][7], self.host_remotes[i][0]))
|
||||
filter_button.connect(
|
||||
"clicked",
|
||||
lambda *_, i=i: self.view_paks(
|
||||
self.host_remotes[i][7], self.host_remotes[i][0]
|
||||
),
|
||||
)
|
||||
|
||||
enable_button = Gtk.Button(visible=False)
|
||||
enable_button.set_child(Adw.ButtonContent(icon_name="eye-open-negative-filled-symbolic", label=_("Enable")))
|
||||
enable_button.set_child(
|
||||
Adw.ButtonContent(
|
||||
icon_name="eye-open-negative-filled-symbolic", label=_("Enable")
|
||||
)
|
||||
)
|
||||
enable_button.add_css_class("flat")
|
||||
enable_button.connect("clicked", self.enable_handler, i)
|
||||
|
||||
disable_button = Gtk.Button()
|
||||
disable_button.set_child(Adw.ButtonContent(icon_name="eye-not-looking-symbolic", label=_("Disable")))
|
||||
disable_button.set_child(
|
||||
Adw.ButtonContent(
|
||||
icon_name="eye-not-looking-symbolic", label=_("Disable")
|
||||
)
|
||||
)
|
||||
disable_button.add_css_class("flat")
|
||||
disable_button.connect("clicked", self.disable_handler, i, options)
|
||||
|
||||
remove_button = Gtk.Button()
|
||||
remove_button.set_child(Adw.ButtonContent(icon_name="user-trash-symbolic", label=_("Remove")))
|
||||
remove_button.set_child(
|
||||
Adw.ButtonContent(
|
||||
icon_name="user-trash-symbolic", label=_("Remove")
|
||||
)
|
||||
)
|
||||
remove_button.add_css_class("flat")
|
||||
remove_button.connect("clicked", self.remove_handler, i, options)
|
||||
|
||||
@@ -196,7 +276,11 @@ class RemotesWindow(Adw.Window):
|
||||
options.set_child(options_box)
|
||||
more.set_popover(options)
|
||||
|
||||
copy_button = Gtk.Button(icon_name="edit-copy-symbolic", valign=Gtk.Align.CENTER, tooltip_text=_("Copy remote name"))
|
||||
copy_button = Gtk.Button(
|
||||
icon_name="edit-copy-symbolic",
|
||||
valign=Gtk.Align.CENTER,
|
||||
tooltip_text=_("Copy remote name"),
|
||||
)
|
||||
copy_button.add_css_class("flat")
|
||||
copy_button.connect("clicked", rowCopyHandler, name)
|
||||
|
||||
@@ -207,7 +291,7 @@ class RemotesWindow(Adw.Window):
|
||||
if install_type == "disabled":
|
||||
if not self.show_disabled_button.get_active():
|
||||
continue
|
||||
|
||||
|
||||
remote_row.set_subtitle(_("Disabled"))
|
||||
enable_button.set_visible(True)
|
||||
disable_button.set_visible(False)
|
||||
@@ -227,23 +311,61 @@ class RemotesWindow(Adw.Window):
|
||||
self.rows_in_list.append(remote_row)
|
||||
self.no_remotes.set_visible(False)
|
||||
except Exception as e:
|
||||
print("error in remotes_window.generate_list: could not add remote. error:", e)
|
||||
print(
|
||||
"error in remotes_window.generate_list: could not add remote. error:",
|
||||
e,
|
||||
)
|
||||
|
||||
# Popular remotes
|
||||
for i in range(len(self.rows_in_popular_list)):
|
||||
self.popular_remotes_list.remove(self.rows_in_popular_list[i])
|
||||
|
||||
|
||||
self.rows_in_popular_list = []
|
||||
|
||||
remotes = [
|
||||
# [Name to show in GUI, Name of remote for system, Link to repo to add, Description of remote]
|
||||
["AppCenter", "appcenter", "https://flatpak.elementary.io/repo.flatpakrepo", _("The open source, pay-what-you-want app store from elementary")],
|
||||
["Flathub", "flathub", "https://dl.flathub.org/repo/flathub.flatpakrepo", _("Central repository of Flatpak applications")],
|
||||
["Flathub beta", "flathub-beta", "https://flathub.org/beta-repo/flathub-beta.flatpakrepo", _("Beta builds of Flatpak applications")],
|
||||
["Fedora", "fedora", "oci+https://registry.fedoraproject.org", _("Flatpaks packaged by Fedora Linux")],
|
||||
["GNOME Nightly", "gnome-nightly", "https://nightly.gnome.org/gnome-nightly.flatpakrepo", _("The latest beta GNOME Apps and Runtimes")],
|
||||
["KDE Testing Applications", "kdeapps", "https://distribute.kde.org/kdeapps.flatpakrepo", _("Beta KDE Apps and Runtimes")],
|
||||
["WebKit Developer SDK", "webkit-sdk", "https://software.igalia.com/flatpak-refs/webkit-sdk.flatpakrepo", _("Central repository of the WebKit Developer and Runtime SDK")],
|
||||
# [Name to show in GUI, Name of remote for system, Link to repo to add, Description of remote]
|
||||
[
|
||||
"AppCenter",
|
||||
"appcenter",
|
||||
"https://flatpak.elementary.io/repo.flatpakrepo",
|
||||
_("The open source, pay-what-you-want app store from elementary"),
|
||||
],
|
||||
[
|
||||
"Flathub",
|
||||
"flathub",
|
||||
"https://dl.flathub.org/repo/flathub.flatpakrepo",
|
||||
_("Central repository of Flatpak applications"),
|
||||
],
|
||||
[
|
||||
"Flathub beta",
|
||||
"flathub-beta",
|
||||
"https://flathub.org/beta-repo/flathub-beta.flatpakrepo",
|
||||
_("Beta builds of Flatpak applications"),
|
||||
],
|
||||
[
|
||||
"Fedora",
|
||||
"fedora",
|
||||
"oci+https://registry.fedoraproject.org",
|
||||
_("Flatpaks packaged by Fedora Linux"),
|
||||
],
|
||||
[
|
||||
"GNOME Nightly",
|
||||
"gnome-nightly",
|
||||
"https://nightly.gnome.org/gnome-nightly.flatpakrepo",
|
||||
_("The latest beta GNOME Apps and Runtimes"),
|
||||
],
|
||||
[
|
||||
"KDE Testing Applications",
|
||||
"kdeapps",
|
||||
"https://distribute.kde.org/kdeapps.flatpakrepo",
|
||||
_("Beta KDE Apps and Runtimes"),
|
||||
],
|
||||
[
|
||||
"WebKit Developer SDK",
|
||||
"webkit-sdk",
|
||||
"https://software.igalia.com/flatpak-refs/webkit-sdk.flatpakrepo",
|
||||
_("Central repository of the WebKit Developer and Runtime SDK"),
|
||||
],
|
||||
]
|
||||
|
||||
host_remotes = self.my_utils.getHostRemotes()
|
||||
@@ -257,9 +379,11 @@ class RemotesWindow(Adw.Window):
|
||||
for i in range(len(remotes)):
|
||||
if remotes[i][1] in host_remotes_names:
|
||||
continue
|
||||
|
||||
|
||||
total_added += 1
|
||||
row = Adw.ActionRow(title=remotes[i][0], subtitle=(remotes[i][2]), activatable=True)
|
||||
row = Adw.ActionRow(
|
||||
title=remotes[i][0], subtitle=(remotes[i][2]), activatable=True
|
||||
)
|
||||
row.connect("activated", self.add_handler, remotes[i][1], remotes[i][2])
|
||||
row.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic"))
|
||||
self.rows_in_popular_list.append(row)
|
||||
@@ -275,8 +399,13 @@ class RemotesWindow(Adw.Window):
|
||||
try:
|
||||
subprocess.run(command, capture_output=True, check=True, env=self.new_env)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not add {}").format(self.name_to_add)))
|
||||
print("error in remotes_window.addRemoteThread: could not add remote. error:", e)
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not add {}").format(self.name_to_add))
|
||||
)
|
||||
print(
|
||||
"error in remotes_window.addRemoteThread: could not add remote. error:",
|
||||
e,
|
||||
)
|
||||
|
||||
def on_add_response(self, _dialog, response_id, _function, row):
|
||||
if response_id == "cancel":
|
||||
@@ -292,9 +421,20 @@ class RemotesWindow(Adw.Window):
|
||||
self.name_to_add = self.name_to_add.strip()
|
||||
self.url_to_add = self.url_to_add.strip()
|
||||
|
||||
command = ['flatpak-spawn', '--host', 'flatpak', 'remote-add', '--if-not-exists', self.name_to_add, self.url_to_add, install_type]
|
||||
command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"remote-add",
|
||||
"--if-not-exists",
|
||||
self.name_to_add,
|
||||
self.url_to_add,
|
||||
install_type,
|
||||
]
|
||||
task = Gio.Task.new(None, None, self.addRemoteCallback)
|
||||
task.run_in_thread(lambda _task, _obj, _data, _cancellable: self.addRemoteThread(command))
|
||||
task.run_in_thread(
|
||||
lambda _task, _obj, _data, _cancellable: self.addRemoteThread(command)
|
||||
)
|
||||
|
||||
def add_handler(self, row, name="", link=""):
|
||||
dialog = Adw.MessageDialog.new(self, _("Add Flatpak Remote"))
|
||||
@@ -308,7 +448,7 @@ class RemotesWindow(Adw.Window):
|
||||
def name_update(widget):
|
||||
is_enabled = True
|
||||
self.name_to_add = widget.get_text()
|
||||
name_pattern = re.compile(r'^[a-zA-Z\-]+$')
|
||||
name_pattern = re.compile(r"^[a-zA-Z\-]+$")
|
||||
if not name_pattern.match(self.name_to_add):
|
||||
is_enabled = False
|
||||
|
||||
@@ -325,7 +465,7 @@ class RemotesWindow(Adw.Window):
|
||||
def url_update(widget):
|
||||
is_enabled = True
|
||||
self.url_to_add = widget.get_text()
|
||||
url_pattern = re.compile(r'^[a-zA-Z0-9\-._~:/?#[\]@!$&\'()*+,;=]+$')
|
||||
url_pattern = re.compile(r"^[a-zA-Z0-9\-._~:/?#[\]@!$&\'()*+,;=]+$")
|
||||
if not url_pattern.match(self.url_to_add):
|
||||
is_enabled = False
|
||||
|
||||
@@ -354,7 +494,7 @@ class RemotesWindow(Adw.Window):
|
||||
info_box = Gtk.Box(orientation="vertical")
|
||||
entry_list = Gtk.ListBox(selection_mode="none", margin_bottom=12)
|
||||
entry_list.add_css_class("boxed-list")
|
||||
|
||||
|
||||
name_entry = Adw.EntryRow(title=_("Name"))
|
||||
name_entry.set_text(name)
|
||||
name_entry.connect("changed", name_update)
|
||||
@@ -370,13 +510,18 @@ class RemotesWindow(Adw.Window):
|
||||
install_type_list = Gtk.ListBox(selection_mode="none")
|
||||
install_type_list.add_css_class("boxed-list")
|
||||
|
||||
user_row = Adw.ActionRow(title=_("User"), subtitle=_("Remote will be available to only you"))
|
||||
user_row = Adw.ActionRow(
|
||||
title=_("User"), subtitle=_("Remote will be available to only you")
|
||||
)
|
||||
user_check = Gtk.CheckButton(active=True)
|
||||
user_check.connect("toggled", set_user)
|
||||
user_row.add_prefix(user_check)
|
||||
user_row.set_activatable_widget(user_check)
|
||||
|
||||
system_row = Adw.ActionRow(title=_("System"), subtitle=_("Remote will be available to every user on the system"))
|
||||
system_row = Adw.ActionRow(
|
||||
title=_("System"),
|
||||
subtitle=_("Remote will be available to every user on the system"),
|
||||
)
|
||||
system_check = Gtk.CheckButton()
|
||||
system_row.add_prefix(system_check)
|
||||
system_check.set_group(user_check)
|
||||
@@ -398,11 +543,32 @@ class RemotesWindow(Adw.Window):
|
||||
|
||||
def addRemoteFromFileThread(self, filepath, system_or_user, name):
|
||||
try:
|
||||
subprocess.run(['flatpak-spawn', '--host', 'flatpak', 'remote-add', '--if-not-exists', name, filepath, f"--{system_or_user}"], capture_output=True, check=True, env=self.new_env)
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("{} successfully added").format(name)))
|
||||
subprocess.run(
|
||||
[
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"remote-add",
|
||||
"--if-not-exists",
|
||||
name,
|
||||
filepath,
|
||||
f"--{system_or_user}",
|
||||
],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
env=self.new_env,
|
||||
)
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("{} successfully added").format(name))
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not add {}").format(self.name_to_add)))
|
||||
print("error in remotes_window.addRemoteFromFileThread: could not add remote. error:", e)
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not add {}").format(self.name_to_add))
|
||||
)
|
||||
print(
|
||||
"error in remotes_window.addRemoteFromFileThread: could not add remote. error:",
|
||||
e,
|
||||
)
|
||||
|
||||
def addRemoteFromFile(self, filepath):
|
||||
def response(dialog, response, _a):
|
||||
@@ -415,12 +581,16 @@ class RemotesWindow(Adw.Window):
|
||||
user_or_system = "system"
|
||||
|
||||
task = Gio.Task.new(None, None, self.addRemoteCallback)
|
||||
task.run_in_thread(lambda *_: self.addRemoteFromFileThread(filepath, user_or_system, name_row.get_text()))
|
||||
task.run_in_thread(
|
||||
lambda *_: self.addRemoteFromFileThread(
|
||||
filepath, user_or_system, name_row.get_text()
|
||||
)
|
||||
)
|
||||
|
||||
def name_update(widget):
|
||||
is_enabled = True
|
||||
self.name_to_add = widget.get_text()
|
||||
name_pattern = re.compile(r'^[a-zA-Z\-]+$')
|
||||
name_pattern = re.compile(r"^[a-zA-Z\-]+$")
|
||||
if not name_pattern.match(self.name_to_add):
|
||||
is_enabled = False
|
||||
|
||||
@@ -436,7 +606,7 @@ class RemotesWindow(Adw.Window):
|
||||
|
||||
self.should_pulse = True
|
||||
|
||||
name = filepath.split('/')
|
||||
name = filepath.split("/")
|
||||
name = name[len(name) - 1]
|
||||
|
||||
dialog = Adw.MessageDialog.new(self, _("Add {}?").format(name))
|
||||
@@ -452,8 +622,13 @@ class RemotesWindow(Adw.Window):
|
||||
options_list = Gtk.ListBox(selection_mode="none", margin_top=15)
|
||||
name_row = Adw.EntryRow(title=_("Name"))
|
||||
name_row.connect("changed", name_update)
|
||||
user_row = Adw.ActionRow(title=_("User"), subtitle=_("Remote will be available to only you"))
|
||||
system_row = Adw.ActionRow(title=_("System"), subtitle=_("Remote will be available to every user on the system"))
|
||||
user_row = Adw.ActionRow(
|
||||
title=_("User"), subtitle=_("Remote will be available to only you")
|
||||
)
|
||||
system_row = Adw.ActionRow(
|
||||
title=_("System"),
|
||||
subtitle=_("Remote will be available to every user on the system"),
|
||||
)
|
||||
user_check = Gtk.CheckButton()
|
||||
system_check = Gtk.CheckButton()
|
||||
|
||||
@@ -473,7 +648,7 @@ class RemotesWindow(Adw.Window):
|
||||
user_check.set_active(True)
|
||||
options_list.add_css_class("boxed-list")
|
||||
Gtk.Window.present(dialog)
|
||||
|
||||
|
||||
def file_callback(self, object, result):
|
||||
try:
|
||||
file = object.open_finish(result)
|
||||
@@ -499,8 +674,8 @@ class RemotesWindow(Adw.Window):
|
||||
self.host_remotes = []
|
||||
self.host_flatpaks = []
|
||||
self.app_window = main_window
|
||||
self.new_env = dict( os.environ )
|
||||
self.new_env['LC_ALL'] = 'C'
|
||||
self.new_env = dict(os.environ)
|
||||
self.new_env["LC_ALL"] = "C"
|
||||
self.should_pulse = False
|
||||
|
||||
# Window Stuffs
|
||||
@@ -514,12 +689,16 @@ class RemotesWindow(Adw.Window):
|
||||
self.refresh.connect("clicked", lambda *_: self.generate_list())
|
||||
self.set_transient_for(main_window)
|
||||
|
||||
self.add_from_file.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic"))
|
||||
self.add_from_file.add_suffix(
|
||||
Gtk.Image.new_from_icon_name("right-large-symbolic")
|
||||
)
|
||||
self.add_from_file.connect("activated", self.addFromFileHandler)
|
||||
self.custom_remote.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic"))
|
||||
self.custom_remote.add_suffix(
|
||||
Gtk.Image.new_from_icon_name("right-large-symbolic")
|
||||
)
|
||||
self.custom_remote.connect("activated", self.add_handler)
|
||||
self.show_disabled_button.connect("clicked", lambda *_: self.generate_list())
|
||||
|
||||
# Calls
|
||||
self.generate_list()
|
||||
# self.show_new_remote_options()
|
||||
# self.show_new_remote_options()
|
||||
|
||||
@@ -4,8 +4,13 @@ import subprocess
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/search_install.ui")
|
||||
class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when search is changed
|
||||
|
||||
@Gtk.Template(
|
||||
resource_path="/io/github/flattool/Warehouse/../data/ui/search_install.ui"
|
||||
)
|
||||
class SearchInstallWindow(
|
||||
Adw.Window
|
||||
): # TODO: stop execution of thread when search is changed
|
||||
__gtype_name__ = "SearchInstallWindow"
|
||||
|
||||
results_list_box = Gtk.Template.Child()
|
||||
@@ -25,7 +30,9 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se
|
||||
def searchResponse(self, a, b):
|
||||
self.results_list_box.remove_all()
|
||||
print(self.search_results)
|
||||
if (self.is_debug and len(self.search_results) == 5) or (len(self.search_results) == 1 and len(self.search_results[0]) == 1): #This is unreliable with G_DEBUG
|
||||
if (self.is_debug and len(self.search_results) == 5) or (
|
||||
len(self.search_results) == 1 and len(self.search_results[0]) == 1
|
||||
): # This is unreliable with G_DEBUG
|
||||
self.main_stack.set_visible_child(self.no_results)
|
||||
return
|
||||
if len(self.search_results) > 50:
|
||||
@@ -35,12 +42,20 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se
|
||||
for i in range(len(self.search_results)):
|
||||
try:
|
||||
print("creating row {}".format(str(i)))
|
||||
row = Adw.ActionRow(title=GLib.markup_escape_text(self.search_results[i][0]), subtitle=self.search_results[i][2])
|
||||
row = Adw.ActionRow(
|
||||
title=GLib.markup_escape_text(self.search_results[i][0]),
|
||||
subtitle=self.search_results[i][2],
|
||||
)
|
||||
print("row {} is {}".format(str(i), self.search_results[i][0]))
|
||||
check = Gtk.CheckButton()
|
||||
check.add_css_class("selection-mode")
|
||||
check.connect("toggled", self.on_check)
|
||||
label = Gtk.Label(label=self.search_results[i][3], justify=Gtk.Justification.RIGHT, wrap=True, hexpand=True)
|
||||
label = Gtk.Label(
|
||||
label=self.search_results[i][3],
|
||||
justify=Gtk.Justification.RIGHT,
|
||||
wrap=True,
|
||||
hexpand=True,
|
||||
)
|
||||
row.add_suffix(label)
|
||||
row.add_suffix(check)
|
||||
row.set_activatable_widget(check)
|
||||
@@ -52,11 +67,20 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se
|
||||
print(button.get_active())
|
||||
|
||||
def searchThread(self):
|
||||
command = ["flatpak-spawn", "--host", "flatpak", "search", "--columns=all", self.to_search]
|
||||
command = [
|
||||
"flatpak-spawn",
|
||||
"--host",
|
||||
"flatpak",
|
||||
"search",
|
||||
"--columns=all",
|
||||
self.to_search,
|
||||
]
|
||||
if self.remote_to_search:
|
||||
command += self.remote_to_search
|
||||
|
||||
output = subprocess.run(command, capture_output=True, text=True, env=self.new_env).stdout
|
||||
output = subprocess.run(
|
||||
command, capture_output=True, text=True, env=self.new_env
|
||||
).stdout
|
||||
lines = output.strip().split("\n")
|
||||
columns = lines[0].split("\t")
|
||||
data = [columns]
|
||||
@@ -83,7 +107,7 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se
|
||||
remotes_pop = Gtk.Popover()
|
||||
remotes_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
# remotes_pop.set_size_request(400, 1) # why?
|
||||
remotes_pop.set_child(remotes_box) # don't use ScrolledWindows in popovers!
|
||||
remotes_pop.set_child(remotes_box) # don't use ScrolledWindows in popovers!
|
||||
|
||||
# why not just comment this code out and leave it unimplemented— it does nothing of use
|
||||
for i in range(1, 3):
|
||||
@@ -107,8 +131,8 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se
|
||||
self.my_utils = myUtils(self)
|
||||
self.search_results = []
|
||||
self.to_search = ""
|
||||
self.new_env = dict( os.environ )
|
||||
self.new_env['LC_ALL'] = 'C'
|
||||
self.new_env = dict(os.environ)
|
||||
self.new_env["LC_ALL"] = "C"
|
||||
event_controller = Gtk.EventControllerKey()
|
||||
event_controller.connect("key-pressed", self.key_handler)
|
||||
self.cancel_button.connect("clicked", lambda *_: self.close())
|
||||
@@ -130,6 +154,3 @@ class SearchInstallWindow (Adw.Window): # TODO: stop execution of thread when se
|
||||
|
||||
self.remote_to_search = []
|
||||
self.main_stack.set_visible_child(self.blank_page)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,15 +5,18 @@ import os
|
||||
import pathlib
|
||||
import time
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/snapshots.ui")
|
||||
class SnapshotsWindow(Adw.Window):
|
||||
__gtype_name__ = "SnapshotsWindow"
|
||||
|
||||
new_env = dict( os.environ )
|
||||
new_env['LC_ALL'] = 'C'
|
||||
|
||||
new_env = dict(os.environ)
|
||||
new_env["LC_ALL"] = "C"
|
||||
host_home = str(pathlib.Path.home())
|
||||
user_data_path = host_home + "/.var/app/"
|
||||
snapshots_path = host_home + "/.var/app/io.github.flattool.Warehouse/data/Snapshots/"
|
||||
snapshots_path = (
|
||||
host_home + "/.var/app/io.github.flattool.Warehouse/data/Snapshots/"
|
||||
)
|
||||
|
||||
snapshots_group = Gtk.Template.Child()
|
||||
main_stack = Gtk.Template.Child()
|
||||
@@ -28,7 +31,7 @@ class SnapshotsWindow(Adw.Window):
|
||||
|
||||
def showListOrEmpty(self):
|
||||
try:
|
||||
self.disconnect(self.no_close_id) # Make window able to close
|
||||
self.disconnect(self.no_close_id) # Make window able to close
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -51,7 +54,7 @@ class SnapshotsWindow(Adw.Window):
|
||||
|
||||
snapshot_files = os.listdir(self.snapshots_of_app_path)
|
||||
to_trash = []
|
||||
|
||||
|
||||
for i in range(len(snapshot_files)):
|
||||
if not snapshot_files[i].endswith(".tar.zst"):
|
||||
# Find all files that aren't snapshots
|
||||
@@ -81,8 +84,13 @@ class SnapshotsWindow(Adw.Window):
|
||||
|
||||
task = Gio.Task()
|
||||
task.run_in_thread(sizeThread)
|
||||
|
||||
label = Gtk.Label(label=_("Version {}").format(split_file[1]), hexpand=True, wrap=True, justify=Gtk.Justification.RIGHT)
|
||||
|
||||
label = Gtk.Label(
|
||||
label=_("Version {}").format(split_file[1]),
|
||||
hexpand=True,
|
||||
wrap=True,
|
||||
justify=Gtk.Justification.RIGHT,
|
||||
)
|
||||
row.add_suffix(label)
|
||||
|
||||
apply = Gtk.Button(icon_name="check-plain-symbolic", valign=Gtk.Align.CENTER)
|
||||
@@ -97,7 +105,7 @@ class SnapshotsWindow(Adw.Window):
|
||||
self.snapshots_group.insert(row, 0)
|
||||
self.main_stack.set_visible_child(self.outerbox)
|
||||
self.open_folder_button.set_sensitive(True)
|
||||
|
||||
|
||||
def trash_snapshot(self, button, file, row):
|
||||
def on_response(dialog, response, func):
|
||||
if response == "cancel":
|
||||
@@ -109,9 +117,15 @@ class SnapshotsWindow(Adw.Window):
|
||||
self.my_utils.trashFolder(self.snapshots_of_app_path)
|
||||
self.showListOrEmpty()
|
||||
else:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not trash snapshot")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not trash snapshot"))
|
||||
)
|
||||
|
||||
dialog = Adw.MessageDialog.new(self, _("Trash Snapshot?"), _("This snapshot and its contents will be sent to the trash."))
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self,
|
||||
_("Trash Snapshot?"),
|
||||
_("This snapshot and its contents will be sent to the trash."),
|
||||
)
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("continue", _("Trash Snapshot"))
|
||||
@@ -123,14 +137,25 @@ class SnapshotsWindow(Adw.Window):
|
||||
epoch = int(time.time())
|
||||
|
||||
def thread():
|
||||
response = self.my_utils.snapshotApps(epoch, [self.snapshots_of_app_path], [self.app_version], [self.app_user_data])
|
||||
response = self.my_utils.snapshotApps(
|
||||
epoch,
|
||||
[self.snapshots_of_app_path],
|
||||
[self.app_version],
|
||||
[self.app_user_data],
|
||||
)
|
||||
if response != 0:
|
||||
GLib.idle_add(self.toast_overlay.add_toast(Adw.Toast.new(_("Could not create snapshot"))))
|
||||
GLib.idle_add(
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not create snapshot"))
|
||||
)
|
||||
)
|
||||
return
|
||||
if self.showListOrEmpty() == "list":
|
||||
self.create_row(f"{epoch}_{self.app_version}.tar.zst")
|
||||
|
||||
self.no_close_id = self.connect("close-request", lambda event: True) # Make window unable to close
|
||||
self.no_close_id = self.connect(
|
||||
"close-request", lambda event: True
|
||||
) # Make window unable to close
|
||||
self.loading_label.set_label(_("Creating Snapshot…"))
|
||||
self.action_bar.set_revealed(False)
|
||||
self.main_stack.set_visible_child(self.loading)
|
||||
@@ -140,19 +165,33 @@ class SnapshotsWindow(Adw.Window):
|
||||
|
||||
def apply_snapshot(self, button, file, row):
|
||||
self.applied = False
|
||||
|
||||
def thread():
|
||||
try:
|
||||
subprocess.run(
|
||||
['tar', '--zstd', '-xvf', f"{self.snapshots_of_app_path}{file}", "-C", f"{self.app_user_data}"],
|
||||
check=True, env=self.new_env
|
||||
[
|
||||
"tar",
|
||||
"--zstd",
|
||||
"-xvf",
|
||||
f"{self.snapshots_of_app_path}{file}",
|
||||
"-C",
|
||||
f"{self.app_user_data}",
|
||||
],
|
||||
check=True,
|
||||
env=self.new_env,
|
||||
)
|
||||
self.applied = True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("error in snapshots_window.apply_snapshot.thread: CalledProcessError:", e)
|
||||
print(
|
||||
"error in snapshots_window.apply_snapshot.thread: CalledProcessError:",
|
||||
e,
|
||||
)
|
||||
|
||||
def callback():
|
||||
if not self.applied:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not apply snapshot")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not apply snapshot"))
|
||||
)
|
||||
else:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Snapshot applied")))
|
||||
self.parent_window.refresh_list_of_flatpaks(self, False)
|
||||
@@ -168,23 +207,35 @@ class SnapshotsWindow(Adw.Window):
|
||||
if os.path.exists(to_trash):
|
||||
a = self.my_utils.trashFolder(to_trash)
|
||||
if a != 0:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not apply snapshot")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not apply snapshot"))
|
||||
)
|
||||
return
|
||||
data = Gio.File.new_for_path(self.app_user_data)
|
||||
data.make_directory()
|
||||
if not os.path.exists(data.get_path()):
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not apply snapshot")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not apply snapshot"))
|
||||
)
|
||||
return
|
||||
|
||||
self.no_close_id = self.connect("close-request", lambda event: True) # Make window unable to close
|
||||
self.no_close_id = self.connect(
|
||||
"close-request", lambda event: True
|
||||
) # Make window unable to close
|
||||
self.loading_label.set_label(_("Applying Snapshot…"))
|
||||
self.action_bar.set_revealed(False)
|
||||
self.main_stack.set_visible_child(self.loading)
|
||||
|
||||
task = Gio.Task.new(None, None, lambda *_: callback())
|
||||
task.run_in_thread(lambda *_: thread())
|
||||
|
||||
dialog = Adw.MessageDialog.new(self, _("Apply Snapshot?"), _("Applying this snapshot will trash any current user data for {}.").format(self.app_name))
|
||||
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self,
|
||||
_("Apply Snapshot?"),
|
||||
_("Applying this snapshot will trash any current user data for {}.").format(
|
||||
self.app_name
|
||||
),
|
||||
)
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("continue", _("Apply Snapshot"))
|
||||
@@ -215,7 +266,11 @@ class SnapshotsWindow(Adw.Window):
|
||||
self.app_user_data = self.user_data_path + self.app_id + "/"
|
||||
self.parent_window = parent_window
|
||||
|
||||
if self.app_version == "" or self.app_version == "-" or self.app_version == None:
|
||||
if (
|
||||
self.app_version == ""
|
||||
or self.app_version == "-"
|
||||
or self.app_version == None
|
||||
):
|
||||
self.app_version = 0.0
|
||||
|
||||
if not os.path.exists(self.snapshots_path):
|
||||
@@ -225,9 +280,11 @@ class SnapshotsWindow(Adw.Window):
|
||||
|
||||
# Calls
|
||||
self.generateList()
|
||||
self.open_folder_button.connect("clicked", self.open_button_handler, self.snapshots_of_app_path)
|
||||
self.open_folder_button.connect(
|
||||
"clicked", self.open_button_handler, self.snapshots_of_app_path
|
||||
)
|
||||
self.new_snapshot.connect("clicked", lambda *_: self.createSnapshot())
|
||||
|
||||
|
||||
event_controller = Gtk.EventControllerKey()
|
||||
event_controller.connect("key-pressed", self.key_handler)
|
||||
self.add_controller(event_controller)
|
||||
@@ -235,4 +292,4 @@ class SnapshotsWindow(Adw.Window):
|
||||
# Window stuffs
|
||||
self.set_title(_("{} Snapshots").format(self.app_name))
|
||||
self.set_transient_for(parent_window)
|
||||
self.set_size_request(0, 230)
|
||||
self.set_size_request(0, 230)
|
||||
|
||||
274
src/window.py
274
src/window.py
@@ -33,6 +33,7 @@ from .const import Config
|
||||
|
||||
from .app_row_widget import AppRow
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/../data/ui/window.ui")
|
||||
class WarehouseWindow(Adw.ApplicationWindow):
|
||||
__gtype_name__ = "WarehouseWindow"
|
||||
@@ -86,7 +87,9 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
total_selected = 0
|
||||
|
||||
def filter_func(self, row):
|
||||
if (self.search_entry.get_text().lower() in row.get_title().lower()) or (self.search_entry.get_text().lower() in row.get_subtitle().lower()):
|
||||
if (self.search_entry.get_text().lower() in row.get_title().lower()) or (
|
||||
self.search_entry.get_text().lower() in row.get_subtitle().lower()
|
||||
):
|
||||
self.is_result = True
|
||||
return True
|
||||
|
||||
@@ -114,10 +117,14 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
self.refresh_list_of_flatpaks(self, False)
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Uninstalled successfully")))
|
||||
else:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not uninstall some apps")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not uninstall some apps"))
|
||||
)
|
||||
|
||||
def uninstallFlatpakThread(self, ref_arr, id_arr, type_arr, should_trash):
|
||||
self.my_utils.uninstallFlatpak(ref_arr, type_arr, should_trash, self.main_progress_bar)
|
||||
self.my_utils.uninstallFlatpak(
|
||||
ref_arr, type_arr, should_trash, self.main_progress_bar
|
||||
)
|
||||
|
||||
def uninstallFlatpak(self, should_trash):
|
||||
ref_arr = []
|
||||
@@ -125,7 +132,7 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
type_arr = []
|
||||
self.currently_uninstalling = True
|
||||
i = 0
|
||||
while(self.flatpaks_list_box.get_row_at_index(i) != None):
|
||||
while self.flatpaks_list_box.get_row_at_index(i) != None:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
if current.tickbox.get_active() == True:
|
||||
ref_arr.append(current.app_ref)
|
||||
@@ -134,14 +141,18 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
i += 1
|
||||
self.set_title(self.main_window_title)
|
||||
task = Gio.Task.new(None, None, self.uninstallFlatpakCallback)
|
||||
task.run_in_thread(lambda _task, _obj, _data, _cancellable, ref_arr=ref_arr, id_arr=id_arr, type_arr=type_arr, should_trash=should_trash: self.uninstallFlatpakThread(ref_arr, id_arr, type_arr, should_trash))
|
||||
task.run_in_thread(
|
||||
lambda _task, _obj, _data, _cancellable, ref_arr=ref_arr, id_arr=id_arr, type_arr=type_arr, should_trash=should_trash: self.uninstallFlatpakThread(
|
||||
ref_arr, id_arr, type_arr, should_trash
|
||||
)
|
||||
)
|
||||
|
||||
def batchUninstallButtonHandler(self, _widget):
|
||||
has_user_data = False
|
||||
|
||||
def batchUninstallResponse(_idk, response_id, _widget):
|
||||
if response_id == "cancel":
|
||||
return 1
|
||||
return 1
|
||||
|
||||
try:
|
||||
should_trash = trash_check.get_active()
|
||||
@@ -150,32 +161,48 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
|
||||
self.uninstallButtonsEnable(False)
|
||||
|
||||
self.no_close = self.connect("close-request", lambda event: True) # Make window unable to close
|
||||
self.no_close = self.connect(
|
||||
"close-request", lambda event: True
|
||||
) # Make window unable to close
|
||||
self.main_stack.set_visible_child(self.uninstalling)
|
||||
self.search_button.set_sensitive(False)
|
||||
self.uninstallFlatpak(should_trash)
|
||||
|
||||
# Create Widgets
|
||||
dialog = Adw.MessageDialog.new(self, _("Uninstall Selected Apps?"), _("It will not be possible to use these apps after removal."))
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self,
|
||||
_("Uninstall Selected Apps?"),
|
||||
_("It will not be possible to use these apps after removal."),
|
||||
)
|
||||
|
||||
# Check to see if at least one app in the list has user data
|
||||
i = 0
|
||||
while(True):
|
||||
while True:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
i += 1
|
||||
if(current == None):
|
||||
if current == None:
|
||||
break
|
||||
if current.tickbox.get_active() and os.path.exists(f"{self.user_data_path}{current.app_id}"):
|
||||
if current.tickbox.get_active() and os.path.exists(
|
||||
f"{self.user_data_path}{current.app_id}"
|
||||
):
|
||||
has_user_data = True
|
||||
break
|
||||
|
||||
if has_user_data:
|
||||
# Create Widgets
|
||||
options_box = Gtk.Box(orientation="vertical")
|
||||
header = Gtk.Label(label=_("App Settings & Data"), halign="start", margin_top=10)
|
||||
header = Gtk.Label(
|
||||
label=_("App Settings & Data"), halign="start", margin_top=10
|
||||
)
|
||||
options_list = Gtk.ListBox(selection_mode="none", margin_top=15)
|
||||
keep_data = Adw.ActionRow(title=_("Keep"), subtitle=_("Allow restoring these apps' settings and content"))
|
||||
trash_data = Adw.ActionRow(title=_("Trash"), subtitle=_("Send these apps' settings and content to the trash"))
|
||||
keep_data = Adw.ActionRow(
|
||||
title=_("Keep"),
|
||||
subtitle=_("Allow restoring these apps' settings and content"),
|
||||
)
|
||||
trash_data = Adw.ActionRow(
|
||||
title=_("Trash"),
|
||||
subtitle=_("Send these apps' settings and content to the trash"),
|
||||
)
|
||||
keep_check = Gtk.CheckButton()
|
||||
trash_check = Gtk.CheckButton()
|
||||
|
||||
@@ -209,7 +236,9 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
|
||||
def uninstallButtonHandler(self, row, name, ref, id):
|
||||
if self.currently_uninstalling:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Cannot uninstall while already uninstalling")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Cannot uninstall while already uninstalling"))
|
||||
)
|
||||
return
|
||||
|
||||
def uninstallResponse(_idk, response_id, _widget):
|
||||
@@ -226,7 +255,9 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
|
||||
self.uninstallButtonsEnable(False)
|
||||
|
||||
self.no_close = self.connect("close-request", lambda event: True) # Make window unable to close
|
||||
self.no_close = self.connect(
|
||||
"close-request", lambda event: True
|
||||
) # Make window unable to close
|
||||
self.main_stack.set_visible_child(self.uninstalling)
|
||||
self.search_button.set_sensitive(False)
|
||||
self.uninstallFlatpak(should_trash)
|
||||
@@ -234,15 +265,27 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
row.tickbox.set_active(True)
|
||||
|
||||
# Create Widgets
|
||||
dialog = Adw.MessageDialog.new(self, _("Uninstall {}?").format(name), _("It will not be possible to use {} after removal.").format(name))
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self,
|
||||
_("Uninstall {}?").format(name),
|
||||
_("It will not be possible to use {} after removal.").format(name),
|
||||
)
|
||||
|
||||
if os.path.exists(f"{self.user_data_path}{id}"):
|
||||
# Create Widgets for Trash
|
||||
options_box = Gtk.Box(orientation="vertical")
|
||||
header = Gtk.Label(label=_("App Settings & Data"), halign="start", margin_top=10)
|
||||
header = Gtk.Label(
|
||||
label=_("App Settings & Data"), halign="start", margin_top=10
|
||||
)
|
||||
options_list = Gtk.ListBox(selection_mode="none", margin_top=15)
|
||||
keep_data = Adw.ActionRow(title=_("Keep"), subtitle=_("Allow restoring this app's settings and content"))
|
||||
trash_data = Adw.ActionRow(title=_("Trash"), subtitle=_("Send this app's settings and content to the trash"))
|
||||
keep_data = Adw.ActionRow(
|
||||
title=_("Keep"),
|
||||
subtitle=_("Allow restoring this app's settings and content"),
|
||||
)
|
||||
trash_data = Adw.ActionRow(
|
||||
title=_("Trash"),
|
||||
subtitle=_("Send this app's settings and content to the trash"),
|
||||
)
|
||||
keep_check = Gtk.CheckButton(active=True)
|
||||
trash_check = Gtk.CheckButton()
|
||||
|
||||
@@ -283,7 +326,7 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
def create_row(self, index):
|
||||
row = AppRow(self, self.host_flatpaks, index)
|
||||
self.flatpaks_list_box.insert(row, index)
|
||||
|
||||
|
||||
def generate_list_of_flatpaks(self):
|
||||
self.host_flatpaks = self.my_utils.getHostFlatpaks()
|
||||
self.dependent_runtimes = self.my_utils.getDependentRuntimes()
|
||||
@@ -328,14 +371,20 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
return
|
||||
result = self.my_utils.trashFolder(f"{self.user_data_path}{id}")
|
||||
if result != 0:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not trash user data")))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not trash user data"))
|
||||
)
|
||||
return
|
||||
self.lookup_action(f"open-data{index}").set_enabled(False)
|
||||
self.lookup_action(f"trash{index}").set_enabled(False)
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Trashed user data")))
|
||||
|
||||
dialog = Adw.MessageDialog.new(self,_("Send {}'s User Data to the Trash?").format(name))
|
||||
dialog.set_body(_("Your files and data for this app will be sent to the trash."))
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self, _("Send {}'s User Data to the Trash?").format(name)
|
||||
)
|
||||
dialog.set_body(
|
||||
_("Your files and data for this app will be sent to the trash.")
|
||||
)
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("continue", _("Trash Data"))
|
||||
@@ -344,12 +393,18 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
dialog.present()
|
||||
|
||||
def maskFlatpak(self, row):
|
||||
is_masked = row.mask_label.get_visible() # Check the visibility of the mask label to see if the flatpak is masked
|
||||
is_masked = (
|
||||
row.mask_label.get_visible()
|
||||
) # Check the visibility of the mask label to see if the flatpak is masked
|
||||
result = []
|
||||
|
||||
def callback():
|
||||
if result[0] == 1:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not disable updates for {}").format(row.app_name)))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(
|
||||
_("Could not disable updates for {}").format(row.app_name)
|
||||
)
|
||||
)
|
||||
return
|
||||
row.set_masked(not is_masked)
|
||||
self.lookup_action(f"mask{row.index}").set_enabled(is_masked)
|
||||
@@ -359,13 +414,23 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
if response == "cancel":
|
||||
return
|
||||
task = Gio.Task.new(None, None, lambda *_: callback())
|
||||
task.run_in_thread(lambda *_: result.append(self.my_utils.maskFlatpak(row.app_id, row.install_type, is_masked)))
|
||||
task.run_in_thread(
|
||||
lambda *_: result.append(
|
||||
self.my_utils.maskFlatpak(row.app_id, row.install_type, is_masked)
|
||||
)
|
||||
)
|
||||
|
||||
if is_masked:
|
||||
onContinue(self, None)
|
||||
else:
|
||||
dialog = Adw.MessageDialog.new(self, _("Disable Updates for {}?").format(row.app_name))
|
||||
dialog.set_body(_("This will mask {} ensuring it will never recieve any feature or security updates.").format(row.app_name))
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self, _("Disable Updates for {}?").format(row.app_name)
|
||||
)
|
||||
dialog.set_body(
|
||||
_(
|
||||
"This will mask {} ensuring it will never recieve any feature or security updates."
|
||||
).format(row.app_name)
|
||||
)
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("continue", _("Disable Updates"))
|
||||
@@ -380,10 +445,12 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
def runCallback(self, _a, _b):
|
||||
if not self.my_utils.run_app_error:
|
||||
return
|
||||
|
||||
|
||||
error = self.my_utils.run_app_error_message
|
||||
dialog = Adw.MessageDialog.new(self, _("Could not Run App"), error)
|
||||
copy_button = Gtk.Button(label=_("Copy"), halign=Gtk.Align.CENTER, margin_top=12)
|
||||
copy_button = Gtk.Button(
|
||||
label=_("Copy"), halign=Gtk.Align.CENTER, margin_top=12
|
||||
)
|
||||
copy_button.add_css_class("pill")
|
||||
copy_button.add_css_class("suggested-action")
|
||||
copy_button.connect("clicked", lambda *_: self.clipboard.set(error))
|
||||
@@ -402,7 +469,7 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
def batch_mode_handler(self, widget):
|
||||
batch_mode = widget.get_active()
|
||||
i = 0
|
||||
while(self.flatpaks_list_box.get_row_at_index(i) != None):
|
||||
while self.flatpaks_list_box.get_row_at_index(i) != None:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
current.set_selectable(batch_mode)
|
||||
i += 1
|
||||
@@ -428,7 +495,7 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
return
|
||||
i = 0
|
||||
trashReturnCodes = 0
|
||||
while(True):
|
||||
while True:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
i += 1
|
||||
if current == None:
|
||||
@@ -437,16 +504,30 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
continue
|
||||
trash = self.my_utils.trashFolder(f"{self.user_data_path}{current.app_id}")
|
||||
if trash == 1:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("{} has no data to trash").format(current.app_name)))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("{} has no data to trash").format(current.app_name))
|
||||
)
|
||||
continue
|
||||
if trash == 2:
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not trash {}'s data").format(current.app_name)))
|
||||
self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(
|
||||
_("Could not trash {}'s data").format(current.app_name)
|
||||
)
|
||||
)
|
||||
continue
|
||||
self.lookup_action(f"open-data{current.index}").set_enabled(False) # Disable the Open User Data dropdown option when the data was deleted
|
||||
self.lookup_action(f"trash{current.index}").set_enabled(False) # Disable the Trash User Data dropdown option when the data was deleted
|
||||
self.lookup_action(f"open-data{current.index}").set_enabled(
|
||||
False
|
||||
) # Disable the Open User Data dropdown option when the data was deleted
|
||||
self.lookup_action(f"trash{current.index}").set_enabled(
|
||||
False
|
||||
) # Disable the Trash User Data dropdown option when the data was deleted
|
||||
|
||||
def batchCleanHandler(self, widget):
|
||||
dialog = Adw.MessageDialog.new(self, _("Trash Selected Apps' User Data?"), _("Your files and data for these apps will be sent to the trash."))
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self,
|
||||
_("Trash Selected Apps' User Data?"),
|
||||
_("Your files and data for these apps will be sent to the trash."),
|
||||
)
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.add_response("continue", _("Trash Data"))
|
||||
@@ -458,18 +539,22 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
self.set_select_all(widget.get_active())
|
||||
|
||||
def batchSnapshotHandler(self, widget):
|
||||
|
||||
def batchSnapshotResponse(dialog, response, _a):
|
||||
if response == "cancel":
|
||||
return
|
||||
i = 0
|
||||
snapshots_path = self.host_home + "/.var/app/io.github.flattool.Warehouse/data/Snapshots/"
|
||||
snapshots_path = (
|
||||
self.host_home
|
||||
+ "/.var/app/io.github.flattool.Warehouse/data/Snapshots/"
|
||||
)
|
||||
snapshot_arr = []
|
||||
app_ver_arr = []
|
||||
app_data_arr = []
|
||||
epoch = int(time.time())
|
||||
self.no_close = self.connect("close-request", lambda event: True) # Make window unable to close
|
||||
while(self.flatpaks_list_box.get_row_at_index(i) != None):
|
||||
self.no_close = self.connect(
|
||||
"close-request", lambda event: True
|
||||
) # Make window unable to close
|
||||
while self.flatpaks_list_box.get_row_at_index(i) != None:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
i += 1
|
||||
if current.tickbox.get_active() == False:
|
||||
@@ -479,11 +564,21 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
snapshot_arr.append(snapshots_path + current.app_id + "/")
|
||||
app_ver_arr.append(current.app_version)
|
||||
app_data_arr.append(f"{self.user_data_path}{current.app_id}")
|
||||
|
||||
|
||||
def thread():
|
||||
capture = self.my_utils.snapshotApps(epoch, snapshot_arr, app_ver_arr, app_data_arr, self.main_progress_bar)
|
||||
capture = self.my_utils.snapshotApps(
|
||||
epoch,
|
||||
snapshot_arr,
|
||||
app_ver_arr,
|
||||
app_data_arr,
|
||||
self.main_progress_bar,
|
||||
)
|
||||
if capture != 0:
|
||||
GLib.idle_add(lambda *_: self.toast_overlay.add_toast(Adw.Toast.new(_("Could not snapshot some apps"))))
|
||||
GLib.idle_add(
|
||||
lambda *_: self.toast_overlay.add_toast(
|
||||
Adw.Toast.new(_("Could not snapshot some apps"))
|
||||
)
|
||||
)
|
||||
|
||||
def callback(*args):
|
||||
self.main_stack.set_visible_child(self.main_box)
|
||||
@@ -503,17 +598,22 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
task = Gio.Task.new(None, None, callback)
|
||||
task.run_in_thread(lambda *_: thread())
|
||||
|
||||
dialog = Adw.MessageDialog.new(self, _("Create Snapshots?"), _("Snapshots are backups of the app's user data. They can be reapplied at any time. This could take a while."))
|
||||
dialog = Adw.MessageDialog.new(
|
||||
self,
|
||||
_("Create Snapshots?"),
|
||||
_(
|
||||
"Snapshots are backups of the app's user data. They can be reapplied at any time. This could take a while."
|
||||
),
|
||||
)
|
||||
dialog.set_close_response("cancel")
|
||||
dialog.add_response("cancel", _("Cancel"))
|
||||
dialog.add_response("continue", _("Create Snapshots"))
|
||||
dialog.connect("response", batchSnapshotResponse, dialog.choose_finish)
|
||||
Gtk.Window.present(dialog)
|
||||
|
||||
|
||||
def set_select_all(self, should_select_all):
|
||||
i = 0
|
||||
while(self.flatpaks_list_box.get_row_at_index(i) != None):
|
||||
while self.flatpaks_list_box.get_row_at_index(i) != None:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
if current.get_visible() == True:
|
||||
current.tickbox.set_active(should_select_all)
|
||||
@@ -551,10 +651,10 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
def copyNames(self, widget, _a):
|
||||
to_copy = ""
|
||||
i = 0
|
||||
while(True):
|
||||
while True:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
i += 1
|
||||
if(current == None):
|
||||
if current == None:
|
||||
break
|
||||
if current.tickbox.get_active():
|
||||
to_copy += f"{current.app_name}\n"
|
||||
@@ -564,10 +664,10 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
def copyIDs(self, widget, _a):
|
||||
to_copy = ""
|
||||
i = 0
|
||||
while(True):
|
||||
while True:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
i += 1
|
||||
if(current == None):
|
||||
if current == None:
|
||||
break
|
||||
if current.tickbox.get_active():
|
||||
to_copy += f"{current.app_id}\n"
|
||||
@@ -577,10 +677,10 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
def copyRefs(self, widget, _a):
|
||||
to_copy = ""
|
||||
i = 0
|
||||
while(True):
|
||||
while True:
|
||||
current = self.flatpaks_list_box.get_row_at_index(i)
|
||||
i += 1
|
||||
if(current == None):
|
||||
if current == None:
|
||||
break
|
||||
if current.tickbox.get_active():
|
||||
to_copy += f"{current.app_ref}\n"
|
||||
@@ -614,34 +714,34 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
self.set_select_all(False)
|
||||
|
||||
index = 0
|
||||
while(self.flatpaks_list_box.get_row_at_index(index) != None):
|
||||
while self.flatpaks_list_box.get_row_at_index(index) != None:
|
||||
current = self.flatpaks_list_box.get_row_at_index(index)
|
||||
visible = True
|
||||
|
||||
if show_apps == False and current.is_runtime == False:
|
||||
visible = False
|
||||
|
||||
|
||||
if show_runtimes == False and current.is_runtime == True:
|
||||
visible = False
|
||||
|
||||
if (not 'all' in filter_install_type):
|
||||
if not "all" in filter_install_type:
|
||||
if not current.install_type in filter_install_type:
|
||||
visible = False
|
||||
|
||||
if (not 'all' in filter_remotes_list):
|
||||
if not "all" in filter_remotes_list:
|
||||
if not current.origin_remote in filter_remotes_list:
|
||||
visible = False
|
||||
|
||||
if (not 'all' in filter_runtimes_list):
|
||||
if not "all" in filter_runtimes_list:
|
||||
if not current.dependent_runtime in filter_runtimes_list:
|
||||
visible = False
|
||||
|
||||
|
||||
if visible == True:
|
||||
total_visible += 1
|
||||
|
||||
|
||||
current.set_visible(visible)
|
||||
index += 1
|
||||
|
||||
|
||||
if total_visible == 0:
|
||||
self.main_stack.set_visible_child(self.no_matches)
|
||||
self.search_button.set_sensitive(False)
|
||||
@@ -659,7 +759,9 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not install app")))
|
||||
|
||||
def installThread(self, filepath, user_or_system):
|
||||
self.my_utils.installFlatpak([filepath], None, user_or_system, self.main_progress_bar)
|
||||
self.my_utils.installFlatpak(
|
||||
[filepath], None, user_or_system, self.main_progress_bar
|
||||
)
|
||||
|
||||
def install_file(self, filepath):
|
||||
def response(dialog, response, _a):
|
||||
@@ -675,7 +777,7 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
task = Gio.Task.new(None, None, self.installCallback)
|
||||
task.run_in_thread(lambda *_: self.installThread(filepath, user_or_system))
|
||||
|
||||
name = filepath.split('/')
|
||||
name = filepath.split("/")
|
||||
name = name[len(name) - 1]
|
||||
|
||||
dialog = Adw.MessageDialog.new(self, _("Install {}?").format(name))
|
||||
@@ -688,8 +790,13 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
# Create Widgets
|
||||
options_box = Gtk.Box(orientation="vertical")
|
||||
options_list = Gtk.ListBox(selection_mode="none", margin_top=15)
|
||||
user_row = Adw.ActionRow(title=_("User"), subtitle=_("The app will be available to only you"))
|
||||
system_row = Adw.ActionRow(title=_("System"), subtitle=_("The app will be available to every user on the system"))
|
||||
user_row = Adw.ActionRow(
|
||||
title=_("User"), subtitle=_("The app will be available to only you")
|
||||
)
|
||||
system_row = Adw.ActionRow(
|
||||
title=_("System"),
|
||||
subtitle=_("The app will be available to every user on the system"),
|
||||
)
|
||||
user_check = Gtk.CheckButton()
|
||||
system_check = Gtk.CheckButton()
|
||||
|
||||
@@ -751,23 +858,33 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
self.filter_list = [True, False, ["all"], ["all"], ["all"]]
|
||||
self.set_size_request(0, 230)
|
||||
self.settings = Gio.Settings.new("io.github.flattool.Warehouse")
|
||||
self.settings.bind("window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind("window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind("is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind("is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind(
|
||||
"window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT
|
||||
)
|
||||
self.settings.bind(
|
||||
"window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT
|
||||
)
|
||||
self.settings.bind(
|
||||
"is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT
|
||||
)
|
||||
self.settings.bind(
|
||||
"is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT
|
||||
)
|
||||
|
||||
self.new_env = dict( os.environ )
|
||||
self.new_env['LC_ALL'] = 'C'
|
||||
self.new_env = dict(os.environ)
|
||||
self.new_env["LC_ALL"] = "C"
|
||||
|
||||
if self.host_flatpaks == [['', '']]:
|
||||
if self.host_flatpaks == [["", ""]]:
|
||||
self.windowSetEmpty(True)
|
||||
return
|
||||
|
||||
self.flatpaks_list_box.set_filter_func(self.filter_func)
|
||||
|
||||
|
||||
task = Gio.Task()
|
||||
task.run_in_thread(lambda *_: GLib.idle_add(lambda *_: self.generate_list_of_flatpaks()))
|
||||
|
||||
task.run_in_thread(
|
||||
lambda *_: GLib.idle_add(lambda *_: self.generate_list_of_flatpaks())
|
||||
)
|
||||
|
||||
self.search_entry.connect("search-changed", self.on_invalidate)
|
||||
self.search_bar.connect_entry(self.search_entry)
|
||||
self.search_bar.connect("notify", self.on_change)
|
||||
@@ -775,7 +892,9 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
self.batch_mode_button.connect("toggled", self.batch_mode_handler)
|
||||
self.batch_clean_button.connect("clicked", self.batchCleanHandler)
|
||||
self.batch_uninstall_button.connect("clicked", self.batchUninstallButtonHandler)
|
||||
self.batch_select_all_button.connect("clicked", self.batchSelectAllButtonHandler)
|
||||
self.batch_select_all_button.connect(
|
||||
"clicked", self.batchSelectAllButtonHandler
|
||||
)
|
||||
self.batch_snapshot_button.connect("clicked", self.batchSnapshotHandler)
|
||||
self.batchActionsEnable(False)
|
||||
event_controller = Gtk.EventControllerKey()
|
||||
@@ -796,4 +915,3 @@ class WarehouseWindow(Adw.ApplicationWindow):
|
||||
|
||||
if Config.DEVEL:
|
||||
self.add_css_class("devel")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user