A shepherd for your Appimages.
0

Configure Feed

Select the types of activity you want to include in your feed.

appherder-gui: drag and drop installs

Aly Raffauf (Jun 19, 2026, 4:20 AM EDT) 85418ef0 e562f496

+39
+39
cmd/appherder-gui/main_window.go
··· 11 11 12 12 "github.com/alyraffauf/appherder/internal/appherder" 13 13 "github.com/diamondburned/gotk4-adwaita/pkg/adw" 14 + "github.com/diamondburned/gotk4/pkg/gdk/v4" 14 15 "github.com/diamondburned/gotk4/pkg/gio/v2" 15 16 "github.com/diamondburned/gotk4/pkg/glib/v2" 16 17 "github.com/diamondburned/gotk4/pkg/gtk/v4" ··· 49 50 win.split.SetSidebar(adw.NewNavigationPage(win.sidebarView(), "AppHerder")) 50 51 win.split.SetContent(adw.NewNavigationPage(emptyDetailsPage(), "AppHerder")) 51 52 win.installBreakpoints() 53 + win.installDropTarget() 52 54 53 55 win.SetContent(win.split) 54 56 ··· 62 64 breakpoint.AddSetterDirect(w.split.Object, "collapsed", glib.NewValue(true)) 63 65 breakpoint.AddSetterDirect(w.split.Object, "show-content", glib.NewValue(false)) 64 66 w.AddBreakpoint(breakpoint) 67 + } 68 + 69 + func (w *mainWindow) installDropTarget() { 70 + target := gtk.NewDropTarget(gdk.GTypeFileList, gdk.ActionCopy) 71 + target.ConnectDrop(func(value *glib.Value, x, y float64) bool { 72 + fileList, ok := value.GoValue().(*gdk.FileList) 73 + if !ok || fileList == nil { 74 + return false 75 + } 76 + return w.installDroppedFiles(fileList.Files()) 77 + }) 78 + w.split.AddController(target) 65 79 } 66 80 67 81 func (w *mainWindow) sidebarView() *adw.ToolbarView { ··· 440 454 dialog.Present(w) 441 455 } 442 456 457 + func (w *mainWindow) installDroppedFiles(files []*gio.File) bool { 458 + if len(files) == 0 { 459 + return false 460 + } 461 + if len(files) > 1 { 462 + w.showError("Cannot Install Files", "Drop one AppImage at a time.") 463 + return false 464 + } 465 + path := files[0].Path() 466 + if path == "" { 467 + w.showError("Cannot Install File", "Drop a local AppImage file.") 468 + return false 469 + } 470 + if !isAppImagePath(path) { 471 + w.showError("Cannot Install File", "Drop a file ending in .AppImage.") 472 + return false 473 + } 474 + w.install(path) 475 + return true 476 + } 477 + 443 478 func (w *mainWindow) install(target string) { 444 479 w.run("Installing AppImage", func() (string, error) { 445 480 var name string ··· 521 556 func looksLikeURL(s string) bool { 522 557 parsed, err := url.Parse(s) 523 558 return err == nil && (parsed.Scheme == "http" || parsed.Scheme == "https") && parsed.Host != "" 559 + } 560 + 561 + func isAppImagePath(path string) bool { 562 + return strings.EqualFold(filepath.Ext(path), ".appimage") 524 563 } 525 564 526 565 func summarizeApplied(applied []appherder.UpgradeApplied) (upgraded, failed int) {