mirror of
https://github.com/morgan9e/warehouse
synced 2026-04-14 00:04:08 +09:00
300 lines
9.8 KiB
Python
300 lines
9.8 KiB
Python
from gi.repository import Adw, Gtk, GLib, Gio
|
|
from src.host_info import HostInfo
|
|
from src.gtk.error_toast import ErrorToast
|
|
from src.remotes_page.remote_row import RemoteRow
|
|
from src.remotes_page.add_remote_dialog import AddRemoteDialog
|
|
from src.gtk.loading_status import LoadingStatus
|
|
import subprocess
|
|
import gettext
|
|
|
|
_ = gettext.gettext
|
|
|
|
|
|
class NewRemoteRow(Adw.ActionRow):
|
|
__gtype_name__ = "NewRemoteRow"
|
|
|
|
def idle_stuff(self, *args):
|
|
self.set_title(self.info["title"])
|
|
self.set_subtitle(self.info["description"])
|
|
self.add_suffix(Gtk.Image.new_from_icon_name("warehouse:plus-large-symbolic"))
|
|
|
|
def __init__(self, info, **kwargs):
|
|
super().__init__(**kwargs)
|
|
self.info = info
|
|
GLib.idle_add(self.idle_stuff)
|
|
self.set_activatable(True)
|
|
|
|
|
|
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/remotes_page/remotes_page.ui")
|
|
class RemotesPage(Adw.NavigationPage):
|
|
# Preselected Remotes
|
|
new_remotes = [
|
|
{
|
|
"title": "AppCenter",
|
|
"name": "appcenter",
|
|
"link": "https://flatpak.elementary.io/repo.flatpakrepo",
|
|
"description": _("The open source, pay-what-you-want app store from elementary"),
|
|
},
|
|
{
|
|
"title": "Flathub",
|
|
"name": "flathub",
|
|
"link": "https://dl.flathub.org/repo/flathub.flatpakrepo",
|
|
"description": _("Central repository of Flatpak applications"),
|
|
},
|
|
{
|
|
"title": "Flathub beta",
|
|
"name": "flathub-beta",
|
|
"link": "https://flathub.org/beta-repo/flathub-beta.flatpakrepo",
|
|
"description": _("Beta builds of Flatpak applications"),
|
|
},
|
|
{
|
|
"title": "Fedora",
|
|
"name": "fedora",
|
|
"link": "oci+https://registry.fedoraproject.org",
|
|
"description": _("Flatpaks packaged by Fedora Linux"),
|
|
},
|
|
{
|
|
"title": "GNOME Nightly",
|
|
"name": "gnome-nightly",
|
|
"link": "https://nightly.gnome.org/gnome-nightly.flatpakrepo",
|
|
"description": _("The latest beta GNOME Apps and Runtimes"),
|
|
},
|
|
{
|
|
"title": "WebKit Developer SDK",
|
|
"name": "webkit-sdk",
|
|
"link": "https://software.igalia.com/flatpak-refs/webkit-sdk.flatpakrepo",
|
|
"description": _("Central repository of the WebKit Developer and Runtime SDK"),
|
|
},
|
|
]
|
|
|
|
__gtype_name__ = "RemotesPage"
|
|
gtc = Gtk.Template.Child
|
|
|
|
search_button = gtc()
|
|
search_bar = gtc()
|
|
search_entry = gtc()
|
|
toast_overlay = gtc()
|
|
stack = gtc()
|
|
current_remotes_group = gtc()
|
|
show_disabled_button = gtc()
|
|
show_disabled_button_content = gtc()
|
|
new_remotes_group = gtc()
|
|
file_remote_row = gtc()
|
|
custom_remote_row = gtc()
|
|
none_visible = gtc()
|
|
status_stack = gtc()
|
|
loading_view = gtc()
|
|
adding_view = gtc()
|
|
main_view = gtc()
|
|
|
|
no_results = gtc()
|
|
no_remotes = gtc()
|
|
content_page = gtc()
|
|
|
|
# Referred to in the main window
|
|
# It is used to determine if a new page should be made or not
|
|
# This must be set to the created object from within the class's __init__ method
|
|
instance = None
|
|
page_name = "remotes"
|
|
|
|
def start_loading(self):
|
|
self.search_button.set_active(False)
|
|
self.status_stack.set_visible_child(self.loading_view)
|
|
self.total_disabled = 0
|
|
for row in self.current_remote_rows:
|
|
self.current_remotes_group.remove(row)
|
|
|
|
self.current_remote_rows.clear()
|
|
|
|
def end_loading(self):
|
|
show_disabled = self.show_disabled_button.get_active()
|
|
self.show_disabled_button.set_visible(False)
|
|
total_visible = 0
|
|
for installation, remotes in HostInfo.remotes.items():
|
|
for remote in remotes:
|
|
row = RemoteRow(self, installation, remote)
|
|
self.current_remote_rows.append(row)
|
|
self.current_remotes_group.add(row)
|
|
if row.remote.disabled:
|
|
self.total_disabled += 1
|
|
self.show_disabled_button.set_visible(True)
|
|
if show_disabled:
|
|
total_visible += 1
|
|
else:
|
|
row.set_visible(False)
|
|
else:
|
|
total_visible += 1
|
|
|
|
self.none_visible.set_visible(total_visible == 0)
|
|
|
|
if len(self.current_remote_rows) == 0:
|
|
self.no_remotes.set_visible(True)
|
|
self.none_visible.set_visible(False)
|
|
else:
|
|
self.no_remotes.set_visible(False)
|
|
|
|
GLib.idle_add(lambda *_: self.status_stack.set_visible_child(self.main_view))
|
|
|
|
def none_visible_handler(self):
|
|
any_visible = False
|
|
for row in self.current_remote_rows:
|
|
if row.get_visible():
|
|
any_visible = True
|
|
break
|
|
|
|
self.none_visible.set_visible(not any_visible)
|
|
|
|
def filter_remote(self, row):
|
|
self.filter_setting.set_boolean("show-apps", True)
|
|
self.filter_setting.set_boolean("show-runtimes", True)
|
|
self.filter_setting.set_string("remotes-list", f"{row.remote.name}<>{row.installation};")
|
|
self.filter_setting.reset("runtimes-list")
|
|
packages_page = self.main_window.pages[self.main_window.packages_row]
|
|
packages_page.filters_page.generate_filters()
|
|
packages_page.apply_filters()
|
|
GLib.idle_add(lambda *_: self.main_window.activate_row(self.main_window.packages_row))
|
|
GLib.idle_add(lambda *args: packages_page.packages_toast_overlay.add_toast(Adw.Toast(title=_("Showing all packages from {}").format(row.remote.title))))
|
|
|
|
def remove_remote(self, row):
|
|
error = [None]
|
|
|
|
def thread(*args):
|
|
install = row.installation
|
|
cmd = ["flatpak-spawn", "--host", "flatpak", "remote-delete", row.remote.name, "--force"]
|
|
if install == "user" or install == "system":
|
|
cmd.append(f"--{install}")
|
|
else:
|
|
cmd.append(f"--installation={install}")
|
|
|
|
try:
|
|
subprocess.run(cmd, check=True, capture_output=True, text=True)
|
|
except subprocess.CalledProcessError as cpe:
|
|
error[0] = cpe.stderr
|
|
except Exception as e:
|
|
error[0] = e
|
|
|
|
def callback(*args):
|
|
if error[0]:
|
|
self.toast_overlay.add_toast(ErrorToast(_("Could not remove remote"), str(error[0])).toast)
|
|
else:
|
|
filters_page = HostInfo.main_window.pages[HostInfo.main_window.packages_row].filters_page
|
|
filters_page.settings.reset("remotes-list")
|
|
filters_page.all_remotes_switch.set_active(False)
|
|
# filters_page.packages_page.apply_filters()
|
|
self.main_window.refresh_handler()
|
|
self.toast_overlay.add_toast(Adw.Toast(title=_("Removed {}").format(row.remote.title)))
|
|
|
|
def on_response(_, response):
|
|
if response != "continue":
|
|
return
|
|
|
|
Gio.Task.new(None, None, callback).run_in_thread(thread)
|
|
|
|
dialog = Adw.AlertDialog(
|
|
heading=_("Remove {}?").format(row.remote.title), body=_("Any installed apps from {} will stop receiving updates").format(row.remote.name)
|
|
)
|
|
dialog.add_response("cancel", _("Cancel"))
|
|
dialog.add_response("continue", _("Remove"))
|
|
dialog.set_response_appearance("continue", Adw.ResponseAppearance.DESTRUCTIVE)
|
|
dialog.connect("response", on_response)
|
|
dialog.present(self.main_window)
|
|
|
|
def on_search(self, entry):
|
|
text = entry.get_text().lower()
|
|
total = 0
|
|
show_disabled = self.show_disabled_button.get_active()
|
|
|
|
for row in self.current_remote_rows:
|
|
title_match = text in row.get_title().lower()
|
|
subtitle_match = text in row.get_subtitle().lower()
|
|
visible = (title_match or subtitle_match) and (show_disabled or not row.remote.disabled)
|
|
total += visible
|
|
row.set_visible(visible)
|
|
|
|
if text == "":
|
|
self.stack.set_visible_child(self.content_page)
|
|
return
|
|
|
|
self.stack.set_visible_child(self.content_page if total > 0 else self.no_results)
|
|
|
|
def local_file_handler(self, path):
|
|
try:
|
|
name = path.split("/")[-1].split(".")[0]
|
|
info = {
|
|
"title": name.title(),
|
|
"name": name,
|
|
"description": "local file",
|
|
"link": path,
|
|
}
|
|
AddRemoteDialog(self.main_window, self, info).present(self.main_window)
|
|
except Exception as e:
|
|
self.toast_overlay.add_toast(ErrorToast(_("Could not open file"), str(e)).toast)
|
|
|
|
def file_callback(self, chooser, result):
|
|
try:
|
|
file = chooser.open_finish(result)
|
|
path = file.get_path()
|
|
self.local_file_handler(path)
|
|
except GLib.GError as ge:
|
|
if "Dismissed by user" in str(ge):
|
|
return
|
|
self.toast_overlay.add_toast(ErrorToast(_("Could not open file"), str(ge)).toast)
|
|
except Exception as e:
|
|
self.toast_overlay.add_toast(ErrorToast(_("Could not open file"), str(e)).toast)
|
|
|
|
def add_file_handler(self):
|
|
file_filter = Gtk.FileFilter(name=_("Flatpak Repos"))
|
|
file_filter.add_suffix("flatpakrepo")
|
|
filters = Gio.ListStore.new(Gtk.FileFilter)
|
|
filters.append(file_filter)
|
|
file_chooser = Gtk.FileDialog()
|
|
file_chooser.set_filters(filters)
|
|
file_chooser.set_default_filter(file_filter)
|
|
file_chooser.open(self.main_window, None, self.file_callback)
|
|
|
|
def show_disabled_handler(self, button):
|
|
show_disabled = button.get_active()
|
|
self.show_disabled_button_content.set_icon_name(
|
|
"warehouse:eye-open-negative-filled-symbolic" if show_disabled else "warehouse:eye-not-looking-symbolic"
|
|
)
|
|
total_visible = 0
|
|
for row in self.current_remote_rows:
|
|
if row.remote.disabled:
|
|
if show_disabled: # show disabled
|
|
row.set_visible(True)
|
|
total_visible += 1
|
|
else:
|
|
row.set_visible(False)
|
|
else:
|
|
total_visible += 1
|
|
|
|
self.none_visible.set_visible(total_visible == 0)
|
|
|
|
def new_custom_handler(self, *args):
|
|
AddRemoteDialog(self.main_window, self).present(self.main_window)
|
|
|
|
def __init__(self, main_window, **kwargs):
|
|
super().__init__(**kwargs)
|
|
|
|
# Extra Object Creation
|
|
self.__class__.instance = self
|
|
self.main_window = main_window
|
|
self.search_bar.set_key_capture_widget(main_window)
|
|
self.current_remote_rows = []
|
|
self.filter_setting = Gio.Settings.new("io.github.flattool.Warehouse.filter")
|
|
self.total_disabled = 0
|
|
|
|
# Connections
|
|
self.file_remote_row.connect("activated", lambda *_: self.add_file_handler())
|
|
self.custom_remote_row.connect("activated", self.new_custom_handler)
|
|
self.search_entry.connect("search-changed", self.on_search)
|
|
self.show_disabled_button.connect("toggled", self.show_disabled_handler)
|
|
|
|
# Apply
|
|
self.adding_view.set_content(LoadingStatus(_("Adding Remote"), _("This should only take a moment")))
|
|
self.loading_view.set_content(LoadingStatus(_("Loading Remotes"), _("This should only take a moment")))
|
|
for item in self.new_remotes:
|
|
row = NewRemoteRow(item)
|
|
row.connect("activated", lambda *_, remote_info=item: AddRemoteDialog(main_window, self, remote_info).present(main_window))
|
|
self.new_remotes_group.add(row)
|