add ability to install from .flatpakref file via drag and drop or command
This commit is contained in:
parent
6a4e165d04
commit
c6eab03914
2 changed files with 156 additions and 47 deletions
|
|
@ -901,6 +901,41 @@ def install_flatpak(app: AppStreamPackage, repo_name=None, system=False) -> tupl
|
|||
return False, f"Installation failed: {e}"
|
||||
return True, f"Successfully installed {app.id}"
|
||||
|
||||
def install_flatpakref(ref_file, system=False):
|
||||
"""Add a new repository using a .flatpakrepo file"""
|
||||
# Get existing repositories
|
||||
installation = get_installation(system)
|
||||
|
||||
if not ref_file.endswith('.flatpakref'):
|
||||
return False, "Flatpak ref file path or URL must end with .flatpakref extension."
|
||||
|
||||
if not os.path.exists(ref_file):
|
||||
return False, f"Flatpak ref file '{ref_file}' does not exist."
|
||||
|
||||
# Read the flatpakref file
|
||||
try:
|
||||
with open(ref_file, 'rb') as f:
|
||||
repo_data = f.read()
|
||||
except IOError as e:
|
||||
return False, f"Failed to read flatpakref file: {str(e)}"
|
||||
|
||||
# Convert the data to GLib.Bytes
|
||||
repo_bytes = GLib.Bytes.new(repo_data)
|
||||
|
||||
installation = get_installation(system)
|
||||
|
||||
transaction = Flatpak.Transaction.new_for_installation(installation)
|
||||
|
||||
# Add the install operation
|
||||
transaction.add_install_flatpakref(repo_bytes)
|
||||
# Run the transaction
|
||||
try:
|
||||
transaction.run()
|
||||
except GLib.Error as e:
|
||||
return False, f"Installation failed: {e}"
|
||||
return True, f"Successfully installed {ref_file}"
|
||||
|
||||
|
||||
def remove_flatpak(app: AppStreamPackage, repo_name=None, system=False) -> tuple[bool, str]:
|
||||
"""
|
||||
Remove a Flatpak package using transactions.
|
||||
|
|
@ -1240,17 +1275,25 @@ def handle_remove_repo(args):
|
|||
print(f"\nRepository removed successfully: {args.remove_repo}")
|
||||
|
||||
def handle_install(args, searcher):
|
||||
packagelist = searcher.search_flatpak(args.install, args.repo)
|
||||
result_message = ""
|
||||
for package in packagelist:
|
||||
if args.install.endswith('.flatpakref'):
|
||||
try:
|
||||
success, message = install_flatpak(package, args.repo, args.system)
|
||||
success, message = install_flatpakref(args.install, args.system)
|
||||
result_message = f"{message}"
|
||||
break
|
||||
except GLib.Error as e:
|
||||
result_message = f"Installation of {args.install} failed: {str(e)}"
|
||||
pass
|
||||
print(result_message)
|
||||
print(result_message)
|
||||
else:
|
||||
packagelist = searcher.search_flatpak(args.install, args.repo)
|
||||
result_message = ""
|
||||
for package in packagelist:
|
||||
try:
|
||||
success, message = install_flatpak(package, args.repo, args.system)
|
||||
result_message = f"{message}"
|
||||
break
|
||||
except GLib.Error as e:
|
||||
result_message = f"Installation of {args.install} failed: {str(e)}"
|
||||
pass
|
||||
print(result_message)
|
||||
|
||||
def handle_remove(args, searcher):
|
||||
packagelist = searcher.search_flatpak(args.remove, args.repo)
|
||||
|
|
|
|||
146
main.py
146
main.py
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import gi
|
||||
import sys
|
||||
gi.require_version("Gtk", "3.0")
|
||||
gi.require_version("GLib", "2.0")
|
||||
gi.require_version("Flatpak", "1.0")
|
||||
|
|
@ -32,6 +33,11 @@ class MainWindow(Gtk.Window):
|
|||
# Set window size
|
||||
self.set_default_size(1280, 720)
|
||||
|
||||
# Enable drag and drop
|
||||
self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
|
||||
self.drag_dest_add_uri_targets()
|
||||
self.connect("drag-data-received", self.on_drag_data_received)
|
||||
|
||||
# Define category groups and their titles
|
||||
self.category_groups = {
|
||||
'system': {
|
||||
|
|
@ -305,6 +311,27 @@ class MainWindow(Gtk.Window):
|
|||
# Select Trending by default
|
||||
self.select_default_category()
|
||||
|
||||
def on_drag_data_received(self, widget, context, x, y, data, info, time):
|
||||
"""Handle drag and drop events"""
|
||||
# Check if data is a URI list
|
||||
if isinstance(data, int):
|
||||
return
|
||||
uri = data.get_uris()[0]
|
||||
file_path = Gio.File.new_for_uri(uri).get_path()
|
||||
if file_path and file_path.endswith('.flatpakref'):
|
||||
self.handle_flatpakref_file(file_path)
|
||||
if file_path and file_path.endswith('.flatpakrepo'):
|
||||
self.handle_flatpakref_file(file_path)
|
||||
context.finish(True, False, time)
|
||||
|
||||
def handle_flatpakref_file(self, file_path):
|
||||
"""Handle .flatpakref file installation"""
|
||||
self.on_install_clicked(file_path, None)
|
||||
|
||||
def handle_flatpakrepo_file(self, file_path):
|
||||
"""Handle .flatpakrepo file installation"""
|
||||
# Show waiting dialog
|
||||
|
||||
def create_header_bar(self):
|
||||
# Create horizontal bar
|
||||
self.top_bar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
|
|
@ -1435,13 +1462,38 @@ class MainWindow(Gtk.Window):
|
|||
# Show dialog
|
||||
self.waiting_dialog.show_all()
|
||||
|
||||
def on_install_clicked(self, button, app):
|
||||
def on_install_clicked(self, button=None, app=None):
|
||||
"""Handle the Install button click with installation options"""
|
||||
details = app.get_details()
|
||||
|
||||
id=""
|
||||
if button and app:
|
||||
details = app.get_details()
|
||||
title=f"Install {details['name']}?"
|
||||
label=f"Install: {details['id']}?"
|
||||
id=details['id']
|
||||
# this is a stupid workaround for our button creator
|
||||
# so that we can use the same function in drag and drop
|
||||
# which of course does not have a button object
|
||||
elif button and not app:
|
||||
app = button
|
||||
button = None
|
||||
title=f"Install {app}?"
|
||||
label=f"Install: {app}?"
|
||||
else:
|
||||
message_type=Gtk.MessageType.ERROR
|
||||
finished_dialog = Gtk.MessageDialog(
|
||||
transient_for=self,
|
||||
modal=True,
|
||||
destroy_with_parent=True,
|
||||
message_type=message_type,
|
||||
buttons=Gtk.ButtonsType.OK,
|
||||
text="Error: No app specified"
|
||||
)
|
||||
finished_dialog.run()
|
||||
finished_dialog.destroy()
|
||||
return
|
||||
# Create dialog
|
||||
dialog = Gtk.Dialog(
|
||||
title=f"Install {details['name']}?",
|
||||
title=title,
|
||||
transient_for=self,
|
||||
modal=True,
|
||||
destroy_with_parent=True,
|
||||
|
|
@ -1458,7 +1510,7 @@ class MainWindow(Gtk.Window):
|
|||
# Create repository dropdown
|
||||
repo_combo = Gtk.ComboBoxText()
|
||||
|
||||
content_area.pack_start(Gtk.Label(label=f"Install: {details['id']}?"), False, False, 0)
|
||||
content_area.pack_start(Gtk.Label(label=label), False, False, 0)
|
||||
|
||||
# Search for available repositories containing this app
|
||||
searcher = libflatpak_query.get_reposearcher(self.system_mode)
|
||||
|
|
@ -1468,56 +1520,59 @@ class MainWindow(Gtk.Window):
|
|||
content_area.pack_start(Gtk.Label(label="Installation Type: System"), False, False, 0)
|
||||
|
||||
# Populate repository dropdown
|
||||
available_repos = set()
|
||||
repos = libflatpak_query.repolist(self.system_mode)
|
||||
for repo in repos:
|
||||
if not repo.get_disabled():
|
||||
search_results = searcher.search_flatpak(details['id'], repo.get_name())
|
||||
if search_results:
|
||||
available_repos.add(repo)
|
||||
if button and app:
|
||||
available_repos = set()
|
||||
repos = libflatpak_query.repolist(self.system_mode)
|
||||
for repo in repos:
|
||||
if not repo.get_disabled():
|
||||
search_results = searcher.search_flatpak(id, repo.get_name())
|
||||
if search_results:
|
||||
available_repos.add(repo)
|
||||
|
||||
# Add repositories to dropdown
|
||||
if available_repos:
|
||||
repo_combo.remove_all() # Clear any existing items
|
||||
# Add repositories to dropdown
|
||||
if available_repos:
|
||||
repo_combo.remove_all() # Clear any existing items
|
||||
|
||||
# Add all repositories
|
||||
for repo in available_repos:
|
||||
repo_combo.append_text(repo.get_name())
|
||||
# Add all repositories
|
||||
for repo in available_repos:
|
||||
repo_combo.append_text(repo.get_name())
|
||||
|
||||
# Only show dropdown if there are multiple repositories
|
||||
if len(available_repos) >= 2:
|
||||
# Remove and re-add with dropdown visible
|
||||
content_area.pack_start(repo_combo, False, False, 0)
|
||||
repo_combo.set_button_sensitivity(Gtk.SensitivityType.AUTO)
|
||||
repo_combo.set_active(0)
|
||||
# Only show dropdown if there are multiple repositories
|
||||
if len(available_repos) >= 2:
|
||||
# Remove and re-add with dropdown visible
|
||||
content_area.pack_start(repo_combo, False, False, 0)
|
||||
repo_combo.set_button_sensitivity(Gtk.SensitivityType.AUTO)
|
||||
repo_combo.set_active(0)
|
||||
else:
|
||||
# Remove and re-add without dropdown
|
||||
content_area.remove(repo_combo)
|
||||
repo_combo.set_active(0)
|
||||
else:
|
||||
# Remove and re-add without dropdown
|
||||
repo_combo.remove_all() # Clear any existing items
|
||||
repo_combo.append_text("No repositories available")
|
||||
content_area.remove(repo_combo)
|
||||
repo_combo.set_active(0)
|
||||
# Show dialog
|
||||
dialog.show_all()
|
||||
else:
|
||||
repo_combo.remove_all() # Clear any existing items
|
||||
repo_combo.append_text("No repositories available")
|
||||
content_area.remove(repo_combo)
|
||||
|
||||
# Show dialog
|
||||
dialog.show_all()
|
||||
# Show dialog
|
||||
dialog.show_all()
|
||||
|
||||
# Run dialog
|
||||
response = dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
selected_repo = repo_combo.get_active_text()
|
||||
|
||||
selected_repo = None
|
||||
if button and app:
|
||||
selected_repo = repo_combo.get_active_text()
|
||||
# Perform installation
|
||||
def perform_installation():
|
||||
# Show waiting dialog
|
||||
GLib.idle_add(self.show_waiting_dialog)
|
||||
|
||||
success, message = libflatpak_query.install_flatpak(app, selected_repo, self.system_mode)
|
||||
|
||||
# Update UI on main thread
|
||||
if button and app:
|
||||
success, message = libflatpak_query.install_flatpak(app, selected_repo, self.system_mode)
|
||||
else:
|
||||
success, message = libflatpak_query.install_flatpakref(app, self.system_mode)
|
||||
GLib.idle_add(lambda: self.on_task_complete(dialog, success, message))
|
||||
|
||||
# Start spinner and begin installation
|
||||
# Start spinner and begin installation
|
||||
thread = threading.Thread(target=perform_installation)
|
||||
thread.daemon = True # Allow program to exit even if thread is still running
|
||||
thread.start()
|
||||
|
|
@ -1836,6 +1891,17 @@ class MainWindow(Gtk.Window):
|
|||
self.on_category_clicked('trending', 'collections')
|
||||
|
||||
def main():
|
||||
# Check for command line argument
|
||||
if len(sys.argv) > 1:
|
||||
arg = sys.argv[1]
|
||||
if arg.endswith('.flatpakref'):
|
||||
# Create a temporary window just to handle the installation
|
||||
app = MainWindow()
|
||||
app.handle_flatpakref_file(arg)
|
||||
# Keep the window open for 5 seconds to show the result
|
||||
GLib.timeout_add_seconds(5, Gtk.main_quit)
|
||||
Gtk.main()
|
||||
return
|
||||
app = MainWindow()
|
||||
app.connect("destroy", Gtk.main_quit)
|
||||
app.show_all()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue