Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions internal/ui/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"testing"

"deedles.dev/trayscale/internal/gutil"
"deedles.dev/trayscale/internal/tsutil"
"tailscale.com/ipn"
"tailscale.com/tailcfg"
)

// TestFillFromBuilder builds every .ui file into its Go struct so that
Expand All @@ -27,20 +30,21 @@ func TestFillFromBuilder(t *testing.T) {
fill(t, func() { gutil.FillFromUI(&win, menuXML, mainWindowXML); gutil.UnrefFields(&win) })
})
t.Run("OfflinePage", func(t *testing.T) {
var page OfflinePage
fill(t, func() { gutil.FillFromUI(&page, offlinePageXML); gutil.UnrefFields(&page) })
fill(t, func() { offlinePageClass.New().Destroy() })
})
t.Run("PeerPage", func(t *testing.T) {
var page PeerPage
fill(t, func() { gutil.FillFromUI(&page, peerPageXML); gutil.UnrefFields(&page) })
peer := layoutPeer(t, "peer", "peer", true, false, false)
status := layoutStatus([]tailcfg.NodeView{peer})
status.Prefs = ipn.NewPrefs().View()
fill(t, func() { NewPeerPage(&App{}, status, peer).Destroy() })
})
t.Run("SelfPage", func(t *testing.T) {
var page SelfPage
fill(t, func() { gutil.FillFromUI(&page, selfPageXML); gutil.UnrefFields(&page) })
status := &tsutil.IPNStatus{State: ipn.Running, Prefs: ipn.NewPrefs().View()}
fill(t, func() { NewSelfPage(&App{}, status).Destroy() })
})
t.Run("MullvadPage", func(t *testing.T) {
var page MullvadPage
fill(t, func() { gutil.FillFromUI(&page, mullvadPageXML); gutil.UnrefFields(&page) })
status := &tsutil.IPNStatus{State: ipn.Running, Prefs: ipn.NewPrefs().View()}
fill(t, func() { NewMullvadPage(&App{}, status).Destroy() })
})
t.Run("PreferencesDialog", func(t *testing.T) {
var dialog PreferencesDialog
Expand Down
2 changes: 1 addition & 1 deletion internal/ui/mainwindow.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ func (win *MainWindow) updatePeers(status *tsutil.IPNStatus) {
win.ipn = status
if !status.Online() {
if _, ok := win.pages["offline"]; !ok {
win.addPage("offline", NewOfflinePage(win.app))
win.addPage("offline", offlinePageClass.New())
}
win.updatePages(status)
return
Expand Down
30 changes: 18 additions & 12 deletions internal/ui/mullvadpage.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"codeberg.org/puregotk/puregotk/v4/adw"
"codeberg.org/puregotk/puregotk/v4/gio"
"codeberg.org/puregotk/puregotk/v4/gtk"
"deedles.dev/trayscale/internal/gobj"
"deedles.dev/trayscale/internal/gutil"
"deedles.dev/trayscale/internal/locale"
"deedles.dev/trayscale/internal/peersearch"
Expand All @@ -25,7 +26,15 @@ import (
//go:embed mullvadpage.ui
var mullvadPageXML string

var mullvadPageClass = gobj.Widget[MullvadPage](gobj.WidgetSpec{
Name: "TrayscaleMullvadPage",
Parent: adw.BinGLibType,
Template: mullvadPageXML,
})

type MullvadPage struct {
gobj.Base

app *App
stackPage *adw.ViewStackPage

Expand All @@ -40,12 +49,10 @@ type MullvadPage struct {
}

func NewMullvadPage(a *App, status *tsutil.IPNStatus) *MullvadPage {
page := MullvadPage{
app: a,
locations: make(map[string]*adw.ExpanderRow),
exitNodes: make(map[tailcfg.StableNodeID]*mullvadExitNodeRow),
}
gutil.FillFromUI(&page, mullvadPageXML)
page := mullvadPageClass.New()
page.app = a
page.locations = make(map[string]*adw.ExpanderRow)
page.exitNodes = make(map[tailcfg.StableNodeID]*mullvadExitNodeRow)

setSortFunc(page.LocationList, page.compareListRows)
setFilterFunc(page.LocationList, page.listRowVisible)
Expand All @@ -54,7 +61,7 @@ func NewMullvadPage(a *App, status *tsutil.IPNStatus) *MullvadPage {
page.setQuery(page.SearchEntry.GetText())
})

return &page
return page
}

func (page *MullvadPage) setQuery(q string) {
Expand Down Expand Up @@ -100,15 +107,15 @@ func (page *MullvadPage) expanderTitle(row *gtk.ListBoxRow) string {
return row.GetName()
}

func (page *MullvadPage) Widget() *gtk.Widget {
return &page.Page.Widget
}

func (page *MullvadPage) Actions() *gio.SimpleActionGroup {
return nil
}

func (page *MullvadPage) Destroy() {
page.Widget().Unref()
}

func (page *MullvadPage) Dispose() {
for _, node := range page.exitNodes {
node.row.Unref()
}
Expand All @@ -117,7 +124,6 @@ func (page *MullvadPage) Destroy() {
loc.Unref()
}
clear(page.locations)
gutil.UnrefFields(page)
}

func (page *MullvadPage) Bind(stackPage *adw.ViewStackPage) {
Expand Down
60 changes: 32 additions & 28 deletions internal/ui/mullvadpage.ui
Original file line number Diff line number Diff line change
@@ -1,41 +1,45 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.96.1 -->
<interface>
<interface domain="trayscale">
<!-- interface-name mullvadpage.ui -->
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.0"/>
<object class="AdwStatusPage" id="Page">
<property name="title" translatable="yes">Mullvad Exit Nodes</property>
<child>
<object class="AdwClamp">
<template class="TrayscaleMullvadPage" parent="AdwBin">
<property name="child">
<object class="AdwStatusPage" id="Page">
<property name="title" translatable="yes">Mullvad Exit Nodes</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<object class="AdwClamp">
<child>
<object class="GtkSearchEntry" id="SearchEntry">
<property name="hexpand">True</property>
<property name="placeholder-text">Search locations</property>
</object>
</child>
<child>
<object class="GtkListBox" id="LocationList">
<property name="css-classes">boxed-list</property>
<property name="selection-mode">none</property>
</object>
</child>
<child>
<object class="GtkLabel" id="EmptyLabel">
<property name="css-classes">dim-label</property>
<property name="halign">center</property>
<property name="label" translatable="yes">No matching exit nodes</property>
<property name="margin-top">24</property>
<property name="visible">False</property>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkSearchEntry" id="SearchEntry">
<property name="hexpand">True</property>
<property name="placeholder-text">Search locations</property>
</object>
</child>
<child>
<object class="GtkListBox" id="LocationList">
<property name="css-classes">boxed-list</property>
<property name="selection-mode">none</property>
</object>
</child>
<child>
<object class="GtkLabel" id="EmptyLabel">
<property name="css-classes">dim-label</property>
<property name="halign">center</property>
<property name="label" translatable="yes">No matching exit nodes</property>
<property name="margin-top">24</property>
<property name="visible">False</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</template>
</interface>
23 changes: 9 additions & 14 deletions internal/ui/offlinepage.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,26 @@ import (

"codeberg.org/puregotk/puregotk/v4/adw"
"codeberg.org/puregotk/puregotk/v4/gio"
"codeberg.org/puregotk/puregotk/v4/gtk"
"deedles.dev/trayscale/internal/gutil"
"deedles.dev/trayscale/internal/gobj"
"deedles.dev/trayscale/internal/tsutil"
)

//go:embed offlinepage.ui
var offlinePageXML string

var offlinePageClass = gobj.Widget[OfflinePage](gobj.WidgetSpec{
Name: "TrayscaleOfflinePage",
Parent: adw.BinGLibType,
Template: offlinePageXML,
})

type OfflinePage struct {
app *App
gobj.Base

Page *adw.StatusPage
NeedsAuthGroup *adw.PreferencesGroup
}

func NewOfflinePage(app *App) *OfflinePage {
page := OfflinePage{app: app}
gutil.FillFromUI(&page, offlinePageXML)
return &page
}

func (page *OfflinePage) Widget() *gtk.Widget {
return &page.Page.Widget
}

func (page *OfflinePage) Actions() *gio.SimpleActionGroup {
return nil
}
Expand All @@ -40,7 +35,7 @@ func (page *OfflinePage) Bind(stackPage *adw.ViewStackPage) {
}

func (page *OfflinePage) Destroy() {
gutil.UnrefFields(page)
page.Widget().Unref()
}

func (page *OfflinePage) Update(status tsutil.Status) bool {
Expand Down
38 changes: 21 additions & 17 deletions internal/ui/offlinepage.ui
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.96.1 -->
<interface>
<interface domain="trayscale">
<!-- interface-name offlinepage.ui -->
<requires lib="gtk" version="4.18"/>
<requires lib="libadwaita" version="1.6"/>
<object class="AdwStatusPage" id="Page">
<template class="TrayscaleOfflinePage" parent="AdwBin">
<property name="child">
<object class="AdwClamp">
<object class="AdwStatusPage" id="Page">
<property name="child">
<object class="AdwPreferencesGroup" id="NeedsAuthGroup">
<property name="description" translatable="yes">Tailscale must be authenticated before it can connect.</property>
<property name="title" translatable="yes">Login Required</property>
<child>
<object class="AdwButtonRow">
<property name="action-name">app.login</property>
<property name="css-classes">button
suggested-action</property>
<property name="title" translatable="yes">Open Browser to Login</property>
<object class="AdwClamp">
<property name="child">
<object class="AdwPreferencesGroup" id="NeedsAuthGroup">
<property name="description" translatable="yes">Tailscale must be authenticated before it can connect.</property>
<property name="title" translatable="yes">Login Required</property>
<child>
<object class="AdwButtonRow">
<property name="action-name">app.login</property>
<property name="css-classes">button
suggested-action</property>
<property name="title" translatable="yes">Open Browser to Login</property>
</object>
</child>
</object>
</child>
</property>
</object>
</property>
<property name="description" translatable="yes">Tailscale is not connected</property>
<property name="icon-name">network-offline-symbolic</property>
<property name="title" translatable="yes">Not Connected</property>
</object>
</property>
<property name="description" translatable="yes">Tailscale is not connected</property>
<property name="icon-name">network-offline-symbolic</property>
<property name="title" translatable="yes">Not Connected</property>
</object>
</template>
</interface>
24 changes: 15 additions & 9 deletions internal/ui/peerpage.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ import (
//go:embed peerpage.ui
var peerPageXML string

var peerPageClass = gobj.Widget[PeerPage](gobj.WidgetSpec{
Name: "TrayscalePeerPage",
Parent: adw.BinGLibType,
Template: peerPageXML,
})

type PeerPage struct {
gobj.Base

app *App
stackPage *adw.ViewStackPage
peer tailcfg.NodeView
Expand Down Expand Up @@ -63,10 +71,9 @@ type PeerPage struct {
}

func NewPeerPage(a *App, status *tsutil.IPNStatus, peer tailcfg.NodeView) *PeerPage {
var page PeerPage
gutil.FillFromUI(&page, peerPageXML)
page := peerPageClass.New()
page.init(a, status, peer)
return &page
return page
}

func (page *PeerPage) init(a *App, status *tsutil.IPNStatus, peer tailcfg.NodeView) {
Expand Down Expand Up @@ -113,7 +120,7 @@ func (page *PeerPage) init(a *App, status *tsutil.IPNStatus, peer tailcfg.NodeVi
}))
})

page.DropTarget.Ref() // AddController takes a reference; the field keeps its own.
page.DropTarget.Ref() // AddController takes over a reference; the template keeps its own.
page.Page.AddController(&page.DropTarget.EventController)
page.DropTarget.SetGtypes([]types.GType{gio.FileGLibType()}, 1)
gutil.Connect(page.DropTarget, page.DropTarget.ConnectDrop, func(_ gtk.DropTarget, val uintptr, x, y float64) bool {
Expand Down Expand Up @@ -170,20 +177,19 @@ func (page *PeerPage) init(a *App, status *tsutil.IPNStatus, peer tailcfg.NodeVi
})
}

func (page *PeerPage) Widget() *gtk.Widget {
return &page.Page.Widget
}

func (page *PeerPage) Actions() *gio.SimpleActionGroup {
return page.actions
}

func (page *PeerPage) Destroy() {
page.Widget().Unref()
}

func (page *PeerPage) Dispose() {
page.addrModel.Unref()
page.routeModel.Unref()
page.sendFileAction.Unref()
page.actions.Unref()
gutil.UnrefFields(page)
}

func (page *PeerPage) Bind(stackPage *adw.ViewStackPage) {
Expand Down
Loading
Loading