Add remote from file & more

Add remote from a repo file either from the picker in the popular remotes window or by a drag and drop.
Allow main menu to be opened with F10
This commit is contained in:
heliguy4599
2023-10-10 09:09:12 -04:00
parent a2921c8223
commit 01f2382d7a
7 changed files with 154 additions and 23 deletions

View File

@@ -5,7 +5,7 @@ ShortcutsWindow help_overlay {
ShortcutsSection {
section-name: "shortcuts";
max-height: 7;
max-height: 8;
ShortcutsGroup {
title: C_("shortcut window", "App Management");
@@ -56,6 +56,11 @@ ShortcutsWindow help_overlay {
ShortcutsGroup {
title: C_("shortcut window", "General");
ShortcutsShortcut {
title: C_("shortcut window", "Open Menu");
action-name: "app.open-menu";
}
ShortcutsShortcut {
title: C_("shortcut window", "Show Shortcuts");
action-name: "win.show-help-overlay";

View File

@@ -50,6 +50,7 @@ class WarehouseApplication(Adw.Application):
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"])
def batch_mode_shortcut(self, widget, _):
button = self.props.active_window.batch_mode_button
@@ -75,6 +76,10 @@ class WarehouseApplication(Adw.Application):
window = self.props.active_window
window.filterWindowKeyboardHandler(window)
def main_menu_shortcut(self, widget, _):
window = self.props.active_window
window.main_menu.set_active(True)
def file_callback(self, object, result):
window = self.props.active_window
try:

View File

@@ -3,7 +3,7 @@ using Adw 1;
template PopularRemotesWindow : Adw.Window {
default-width: 450;
default-height: 613;
default-height: 530;
title: "";
Adw.ToolbarView main_toolbar_view {
@@ -16,7 +16,7 @@ template PopularRemotesWindow : Adw.Window {
Adw.StatusPage {
valign: start;
title: _("Add a Remote");
description: _("Choose from a list of popular remotes.");
description: _("Choose from a list of popular remotes or add a new one.");
Adw.Clamp {
Box {
orientation: vertical;
@@ -31,6 +31,15 @@ template PopularRemotesWindow : Adw.Window {
valign: start;
selection-mode: none;
styles["boxed-list"]
Adw.ActionRow add_from_file {
title: _("Add a Repo File");
activatable: true;
}
Adw.ActionRow custom_remote {
title: _("Add a Custom Remote");
activatable: true;
}
}
}
}

View File

@@ -12,34 +12,52 @@ class PopularRemotesWindow(Adw.Window):
list_of_remotes = Gtk.Template.Child()
custom_list = Gtk.Template.Child()
toast_overlay = Gtk.Template.Child()
add_from_file = Gtk.Template.Child()
custom_remote = Gtk.Template.Child()
def key_handler(self, _a, event, _c, _d):
if event == Gdk.KEY_Escape:
self.close()
def file_callback(self, object, result):
try:
file = object.open_finish(result)
self.parent_window.addRemoteFromFile(file.get_path())
self.close()
except GLib.GError:
pass
def addFromFileHandler(self, widet):
filter = Gtk.FileFilter(name=_("Flatpaks Repos"))
filter.add_suffix("flatpakrepo")
filters = Gio.ListStore.new(Gtk.FileFilter)
filters.append(filter)
file_chooser = Gtk.FileDialog()
file_chooser.set_filters(filters)
file_chooser.set_default_filter(filter)
file_chooser.open(self, None, self.file_callback)
def generate_list(self):
self.host_remotes = self.my_utils.getHostRemotes()
self.list_of_remotes.remove_all()
self.custom_list.remove_all()
host_remotes_names = []
for i in range(len(self.remotes)):
remote_row = Adw.ActionRow(activatable=True)
remote_row.set_title(self.remotes[i][0])
remote_row.set_subtitle(self.remotes[i][3])
image = Gtk.Image.new_from_icon_name("right-large-symbolic")
remote_row.add_suffix(image)
remote_row.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic"))
remote_row.connect("activated", self.parent_window.add_handler, self.remotes[i][1], self.remotes[i][2])
remote_row.connect("activated", lambda *_: self.close())
self.list_of_remotes.append(remote_row)
image2 = Gtk.Image.new_from_icon_name("right-large-symbolic")
custom_remote = Adw.ActionRow(activatable=True)
custom_remote.set_title(_("Add a Custom Remote"))
custom_remote.add_suffix(image2)
custom_remote.connect("activated", self.parent_window.add_handler)
custom_remote.connect("activated", lambda *_: self.close())
self.custom_list.append(custom_remote)
self.add_from_file.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic"))
self.add_from_file.connect("activated", self.addFromFileHandler)
#self.add_from_file.connect("activated", lambda *_: self.close())
self.custom_remote.add_suffix(Gtk.Image.new_from_icon_name("right-large-symbolic"))
self.custom_remote.connect("activated", self.parent_window.add_handler)
self.custom_remote.connect("activated", lambda *_: self.close())
if not self.list_of_remotes.get_row_at_index(0):
self.list_of_remotes.set_visible(False)

View File

@@ -106,7 +106,7 @@ class RemotesWindow(Adw.Window):
def addRemoteThread(self, command):
try:
subprocess.run(command, capture_output=True, check=True, env=self.new_env)
except Exception as e:
except subprocess.CalledProcessError as e:
self.toast_overlay.add_toast(Adw.Toast.new(_("Could not add {}").format(self.name_to_add)))
print(e)
@@ -235,6 +235,86 @@ class RemotesWindow(Adw.Window):
if link != "":
url_update(url_entry)
def addRemoteFromFileThread(self, filepath, system_or_user, name):
try:
subprocess.run(['flatpak-spawn', '--host', 'flatpak', 'remote-add', 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(e)
def addRemoteFromFile(self, filepath):
def response(dialog, response, _a):
if response == "cancel":
self.should_pulse = False
return
self.progress_bar.set_visible(True)
user_or_system = "user"
if system_check.get_active():
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()))
def name_update(widget):
is_enabled = True
self.name_to_add = widget.get_text()
name_pattern = re.compile(r'^[a-zA-Z\-]+$')
if not name_pattern.match(self.name_to_add):
is_enabled = False
if is_enabled:
widget.remove_css_class("error")
else:
widget.add_css_class("error")
if len(self.name_to_add) == 0:
is_enabled = False
dialog.set_response_enabled("continue", is_enabled)
self.should_pulse = True
self.mainPulser()
name = filepath.split('/')
name = name[len(name) - 1]
dialog = Adw.MessageDialog.new(self, _("Add {}?").format(name))
dialog.set_close_response("cancel")
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("continue", _("Add"))
dialog.set_response_enabled("continue", False)
dialog.set_response_appearance("continue", Adw.ResponseAppearance.SUGGESTED)
dialog.connect("response", response, dialog.choose_finish)
# Create Widgets
options_box = Gtk.Box(orientation="vertical")
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=_("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()
# Apply Widgets
user_row.add_prefix(user_check)
user_row.set_activatable_widget(user_check)
system_row.add_prefix(system_check)
system_row.set_activatable_widget(system_check)
user_check.set_group(system_check)
options_list.append(name_row)
options_list.append(user_row)
options_list.append(system_row)
options_box.append(options_list)
dialog.set_extra_child(options_box)
# Calls
user_check.set_active(True)
options_list.add_css_class("boxed-list")
Gtk.Window.present(dialog)
def showPopularRemotes(self, widget):
remotes = [
@@ -259,10 +339,7 @@ class RemotesWindow(Adw.Window):
if remotes[i][1] not in host_remotes_names:
non_added_remotes.append(remotes[i])
if len(non_added_remotes) > 0:
PopularRemotesWindow(self, non_added_remotes).present()
else:
self.add_handler(widget)
PopularRemotesWindow(self, non_added_remotes).present()
def __init__(self, main_window, **kwargs):
super().__init__(**kwargs)

View File

@@ -27,7 +27,7 @@ template WarehouseWindow : Adw.ApplicationWindow {
}
[end]
MenuButton {
MenuButton main_menu {
icon-name: "open-menu-symbolic";
tooltip-text: _("Main Menu");
menu-model: primary_menu;

View File

@@ -19,11 +19,13 @@
import os
import pathlib
import subprocess
import re
from gi.repository import Adw, Gdk, Gio, GLib, Gtk
from .properties_window import show_properties_window
from .filter_window import FilterWindow
from .common import myUtils
from .remotes_window import RemotesWindow
@Gtk.Template(resource_path="/io/github/flattool/Warehouse/window.ui")
class WarehouseWindow(Adw.ApplicationWindow):
@@ -48,6 +50,7 @@ class WarehouseWindow(Adw.ApplicationWindow):
main_toolbar_view = Gtk.Template.Child()
filter_button = Gtk.Template.Child()
scrolled_window = Gtk.Template.Child()
main_menu = Gtk.Template.Child()
main_progress_bar = Gtk.ProgressBar(visible=False, pulse_step=0.7, can_target=False)
main_progress_bar.add_css_class("osd")
@@ -503,17 +506,20 @@ class WarehouseWindow(Adw.ApplicationWindow):
total_visible += 1
if total_visible > 0:
#self.main_stack.set_visible_child(self.main_box)
self.windowSetEmpty(False)
else:
# self.main_stack.set_visible_child(self.no_flatpaks)
self.windowSetEmpty(True)
self.filter_button.set_sensitive(True)
def installCallback(self, _a, _b):
self.main_progress_bar.set_visible(False)
self.should_pulse = False
self.refresh_list_of_flatpaks(self, False)
if self.my_utils.install_success:
self.toast_overlay.add_toast(Adw.Toast.new(_("Installed successfully")))
self.refresh_list_of_flatpaks(self, False)
else:
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)
@@ -570,7 +576,15 @@ class WarehouseWindow(Adw.ApplicationWindow):
Gtk.Window.present(dialog)
def drop_callback(self, target, _x, _y, _data):
print(target.get_value().get_path())
filepath = target.get_value().get_path()
if filepath.endswith(".flatpak") or filepath.endswith(".flatpakref"):
self.install_file(filepath)
elif filepath.endswith(".flatpakrepo"):
remotes_window = RemotesWindow(self)
remotes_window.present()
remotes_window.addRemoteFromFile(filepath)
else:
self.toast_overlay.add_toast(Adw.Toast.new(_("File type not supported")))
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -584,6 +598,9 @@ class WarehouseWindow(Adw.ApplicationWindow):
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'
if self.host_flatpaks == [['', '']]:
self.windowSetEmpty(True)
return