Skip to content

Commit

Permalink
Add connection bar
Browse files Browse the repository at this point in the history
At the bottom a bar was added, which shows the connection status to the
server and the application version.
  • Loading branch information
seternate committed Sep 18, 2024
1 parent 7b4b8bc commit 642e716
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 25 deletions.
1 change: 1 addition & 0 deletions cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func main() {
}

controller := controller.NewController(signalCtx).
WithConnectionController().
WithSettingsController().
WithStatusController().
WithGameController().
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/rs/zerolog v1.31.0
github.com/seternate/go-lanty v0.2.0
github.com/seternate/go-lanty v0.2.1-0.20240918184806-7684fbfb8ee5
golang.design/x/clipboard v0.7.0
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWR
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seternate/go-lanty v0.2.0 h1:Oj/ubPDZOvJerYcsCZXkiHQpXyzAZkcvpS+keiYrTTU=
github.com/seternate/go-lanty v0.2.0/go.mod h1:QL66bV5xXhUysHVUI8VaX773dsvXJp0bDzrXWWq3IOs=
github.com/seternate/go-lanty v0.2.1-0.20240918184806-7684fbfb8ee5 h1:zlp8eARrysYzkl34w3WdbKfS8QPSTa3LI92fH7KcceA=
github.com/seternate/go-lanty v0.2.1-0.20240918184806-7684fbfb8ee5/go.mod h1:QL66bV5xXhUysHVUI8VaX773dsvXJp0bDzrXWWq3IOs=
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
Expand Down
88 changes: 88 additions & 0 deletions pkg/controller/connectioncontroller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package controller

import (
"slices"
"sync"
"time"

"github.com/rs/zerolog/log"
"github.com/seternate/go-lanty/pkg/util"
)

type ConnectionStatus int

const (
Connected ConnectionStatus = iota
Disconnected
)

type ConnectionController struct {
parent *Controller
subscriber []chan struct{}
refreshinterval time.Duration
mutex sync.RWMutex
Status ConnectionStatus
}

func NewConnectionController(parent *Controller, refreshinterval time.Duration) (controller *ConnectionController) {
controller = &ConnectionController{
parent: parent,
subscriber: make([]chan struct{}, 0, 50),
refreshinterval: refreshinterval,
Status: Disconnected,
}
parent.WaitGroup().Add(1)
go controller.run()
return
}

func (controller *ConnectionController) run() {
defer controller.parent.WaitGroup().Done()
ticker := time.NewTicker(controller.refreshinterval)
controller.updateStatus()
for {
select {
case <-controller.parent.Context().Done():
log.Trace().Err(controller.parent.Context().Err()).Msg("exiting connectioncontroller run()")
return
case <-ticker.C:
controller.updateStatus()
}
}
}

func (controller *ConnectionController) updateStatus() {
controller.mutex.Lock()
oldstatus := controller.Status
if controller.parent.client.Health.Health() != nil {
controller.Status = Disconnected
} else {
controller.Status = Connected
}
newstatus := controller.Status
controller.mutex.Unlock()
if newstatus != oldstatus {
controller.notifySubcriber()
}
}

func (controller *ConnectionController) Subscribe(subscriber chan struct{}) {
defer controller.mutex.Unlock()
controller.mutex.Lock()
controller.subscriber = append(controller.subscriber, subscriber)
}

func (controller *ConnectionController) Unsubscribe(subscriber chan struct{}) {
defer controller.mutex.Unlock()
controller.mutex.Lock()
index := slices.Index(controller.subscriber, subscriber)
_ = slices.Delete(controller.subscriber, index, index+1)
}

func (controller *ConnectionController) notifySubcriber() {
defer controller.mutex.RUnlock()
controller.mutex.RLock()
for _, subscriber := range controller.subscriber {
util.ChannelWriteNonBlocking(subscriber, struct{}{})
}
}
18 changes: 12 additions & 6 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import (
)

type Controller struct {
Settings *SettingsController
Status *StatusController
Download *DownloadController
Game *GameController
User *UserController
Chat *ChatController
Settings *SettingsController
Status *StatusController
Download *DownloadController
Game *GameController
User *UserController
Chat *ChatController
Connection *ConnectionController

settings *setting.Settings
client *api.Client
Expand Down Expand Up @@ -96,3 +97,8 @@ func (controller *Controller) WithChatController() *Controller {
controller.Chat = NewChatController(controller)
return controller
}

func (controller *Controller) WithConnectionController() *Controller {
controller.Connection = NewConnectionController(controller, 1*time.Second)
return controller
}
121 changes: 121 additions & 0 deletions pkg/widget/connectionbar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package widget

import (
"fmt"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
fynetheme "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/rs/zerolog/log"
"github.com/seternate/go-lanty-client/pkg/controller"
"github.com/seternate/go-lanty-client/pkg/setting"
"github.com/seternate/go-lanty-client/pkg/theme"
)

type Connectionbar struct {
widget.BaseWidget

controller *controller.Controller
statusupdated chan struct{}
statustext string
}

func NewConnectionbar(controller *controller.Controller) *Connectionbar {
connectionbar := &Connectionbar{
controller: controller,
statusupdated: make(chan struct{}, 50),
statustext: "UNKNOWN",
}
connectionbar.ExtendBaseWidget(connectionbar)

controller.Connection.Subscribe(connectionbar.statusupdated)
controller.WaitGroup().Add(1)
go connectionbar.statusUpdater()

return connectionbar
}

func (widget *Connectionbar) statusUpdater() {
defer widget.controller.WaitGroup().Done()
widget.updateStatus()
for {
select {
case <-widget.controller.Context().Done():
log.Trace().Msg("exiting connectionbar statusUpdater()")
return
case <-widget.statusupdated:
widget.updateStatus()
widget.Refresh()
}
}
}

func (widget *Connectionbar) updateStatus() {
status := widget.controller.Connection.Status
if status == controller.Connected {
widget.statustext = fmt.Sprintf("Connected to server: %s", widget.controller.Settings.Settings().ServerURL)
} else if status == controller.Disconnected {
widget.statustext = fmt.Sprintf("Error connecting to server: %s", widget.controller.Settings.Settings().ServerURL)
}
}

func (widget *Connectionbar) CreateRenderer() fyne.WidgetRenderer {
return newConnectionbarRenderer(widget)
}

type connectionbarRenderer struct {
widget *Connectionbar
line *canvas.Line
status *canvas.Text
version *canvas.Text
}

func newConnectionbarRenderer(widget *Connectionbar) *connectionbarRenderer {
renderer := &connectionbarRenderer{
widget: widget,
line: canvas.NewLine(fynetheme.InputBorderColor()),
status: canvas.NewText(widget.statustext, theme.ForegroundColor()),
version: canvas.NewText(setting.VERSION, theme.ForegroundColor()),
}
renderer.line.StrokeWidth = 2.0
return renderer
}

func (renderer *connectionbarRenderer) Objects() []fyne.CanvasObject {
objects := []fyne.CanvasObject{
renderer.line,
renderer.status,
renderer.version,
}
return objects
}

func (renderer *connectionbarRenderer) Layout(size fyne.Size) {
renderer.line.Resize(fyne.NewSize(size.Width, 0))

versiontextsize := fyne.MeasureText(renderer.version.Text, renderer.version.TextSize, renderer.version.TextStyle)
statustextsize := fyne.MeasureText(renderer.status.Text, renderer.status.TextSize, renderer.status.TextStyle)

renderer.version.Move(fyne.NewPos(theme.InnerPadding(), (size.Height-versiontextsize.Height)/2))
renderer.status.Move(fyne.NewPos(size.Width-statustextsize.Width-theme.InnerPadding(), (size.Height-statustextsize.Height)/2))
}

func (renderer *connectionbarRenderer) MinSize() fyne.Size {
versiontextsize := fyne.MeasureText(renderer.version.Text, renderer.version.TextSize, renderer.version.TextStyle)
statustextsize := fyne.MeasureText(renderer.status.Text, renderer.status.TextSize, renderer.status.TextStyle)

minHeight := fyne.Max(versiontextsize.Height, statustextsize.Height) + theme.InnerPadding()
minWidth := versiontextsize.Width + statustextsize.Width + 3*theme.InnerPadding()

return fyne.NewSize(minWidth, minHeight)
}

func (renderer *connectionbarRenderer) Refresh() {
renderer.line.Refresh()
renderer.status.Text = renderer.widget.statustext
renderer.status.Refresh()
renderer.version.Refresh()
}

func (renderer *connectionbarRenderer) Destroy() {}
18 changes: 12 additions & 6 deletions pkg/widget/lanty.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Lanty struct {
widget.BaseWidget

controller *controller.Controller
connectionbar *Connectionbar
sidebar *Sidebar
gamebrowser *ScrollWithState
startserver *ScrollWithState
Expand Down Expand Up @@ -46,6 +47,7 @@ func NewLanty(controller *controller.Controller, window fyne.Window) *Lanty {

lanty := &Lanty{
controller: controller,
connectionbar: NewConnectionbar(controller),
sidebar: NewSidebar(setting.APPLICATION_NAME),
gamebrowser: NewVScrollWithState(gamebrowser),
startserver: NewVScrollWithState(startserver),
Expand Down Expand Up @@ -206,7 +208,7 @@ func (widget *Lanty) showSettingsBrowser() {
}

func (widget *Lanty) showStartServer() {
widget.sidebar.Show()
widget.sidebar.Hide()
widget.gamebrowser.Hide()
widget.downloadbrowser.Hide()
widget.chatbrowser.Hide()
Expand All @@ -218,7 +220,7 @@ func (widget *Lanty) showStartServer() {
}

func (widget *Lanty) showJoinServer() {
widget.sidebar.Show()
widget.sidebar.Hide()
widget.gamebrowser.Hide()
widget.downloadbrowser.Hide()
widget.chatbrowser.Hide()
Expand Down Expand Up @@ -274,23 +276,26 @@ func (renderer *lantyRenderer) Objects() []fyne.CanvasObject {
renderer.widget.sidebar,
renderer.main,
renderer.widget.statusbar,
renderer.widget.connectionbar,
}
}

func (renderer *lantyRenderer) Layout(size fyne.Size) {
renderer.widget.defaultusernamebrowser.Move(fyne.NewPos(0, 0))
renderer.widget.defaultusernamebrowser.Resize(size)
renderer.widget.defaultusernamebrowser.Resize(size.SubtractWidthHeight(0, renderer.widget.connectionbar.MinSize().Height))
renderer.widget.connectionbar.Move(fyne.NewPos(0, size.Height-renderer.widget.connectionbar.MinSize().Height))
renderer.widget.connectionbar.Resize(fyne.NewSize(size.Width, renderer.widget.connectionbar.MinSize().Height))
renderer.widget.sidebar.Move(fyne.NewPos(0, 0))
renderer.widget.sidebar.Resize(fyne.NewSize(fyne.Max(size.Width/7, renderer.widget.sidebar.MinSize().Width), size.Height))
renderer.main.Resize(fyne.NewSize(size.Width-fyne.Max(size.Width/7, renderer.widget.sidebar.MinSize().Width), size.Height))
renderer.widget.sidebar.Resize(fyne.NewSize(fyne.Max(size.Width/7, renderer.widget.sidebar.MinSize().Width), size.Height-renderer.widget.connectionbar.MinSize().Height))
renderer.main.Resize(fyne.NewSize(size.Width-fyne.Max(size.Width/7, renderer.widget.sidebar.MinSize().Width), size.Height-renderer.widget.connectionbar.MinSize().Height))
renderer.main.Move(fyne.NewPos(fyne.Max(size.Width/7, renderer.widget.sidebar.MinSize().Width), 0))
renderer.widget.statusbar.Resize(fyne.NewSize(renderer.main.Size().Width/2, 40))
renderer.widget.statusbar.Move(fyne.NewPos(size.Width-theme.InnerPadding()-renderer.widget.statusbar.Size().Width, size.Height-theme.InnerPadding()-renderer.widget.statusbar.Size().Height))
}

func (renderer *lantyRenderer) MinSize() fyne.Size {
size := fyne.NewSize(0, 0)
size.Height = fyne.Max(renderer.widget.sidebar.MinSize().Height, renderer.main.MinSize().Height)
size.Height = fyne.Max(renderer.widget.sidebar.MinSize().Height, renderer.main.MinSize().Height) + renderer.widget.connectionbar.MinSize().Height
size.Width = renderer.widget.gamebrowser.MinSize().Width + fyne.Max(renderer.widget.gamebrowser.MinSize().Width/6, renderer.widget.sidebar.MinSize().Width)
return size
}
Expand All @@ -301,6 +306,7 @@ func (renderer *lantyRenderer) Refresh() {
//Needed for statusbar to be drawn correctly
//renderer.Layout(renderer.widget.Size())
renderer.main.Refresh()
renderer.widget.connectionbar.Refresh()
renderer.widget.sidebar.Refresh()
renderer.widget.statusbar.Refresh()
renderer.widget.defaultusernamebrowser.Refresh()
Expand Down
10 changes: 0 additions & 10 deletions pkg/widget/sidebar.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fyne.io/fyne/v2/canvas"
fynetheme "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/seternate/go-lanty-client/pkg/setting"
"github.com/seternate/go-lanty-client/pkg/theme"
)

Expand Down Expand Up @@ -75,7 +74,6 @@ type sidebarRenderer struct {
widget *Sidebar
background *canvas.Rectangle
text *canvas.Text
version *canvas.Text
objects []fyne.CanvasObject
}

Expand All @@ -84,12 +82,10 @@ func newSidebarRenderer(widget *Sidebar) *sidebarRenderer {
widget: widget,
background: canvas.NewRectangle(fynetheme.InputBorderColor()),
text: canvas.NewText(widget.text, theme.ForegroundColor()),
version: canvas.NewText(setting.VERSION, theme.ForegroundColor()),
}
renderer.objects = []fyne.CanvasObject{
renderer.background,
renderer.text,
renderer.version,
}
for _, button := range renderer.widget.buttons {
renderer.objects = append(renderer.objects, button)
Expand Down Expand Up @@ -122,9 +118,6 @@ func (renderer *sidebarRenderer) Layout(size fyne.Size) {
button.Move(fyne.NewPos(theme.InnerPadding(), textsize.Height*1.5+(button.MinSize().Height+theme.InnerPadding())*float32(index)))
index++
}

textsize = fyne.MeasureText(renderer.version.Text, renderer.version.TextSize, renderer.version.TextStyle)
renderer.version.Move(fyne.NewPos(theme.InnerPadding(), size.Height-theme.InnerPadding()-textsize.Height))
}

func (renderer *sidebarRenderer) MinSize() fyne.Size {
Expand All @@ -136,8 +129,6 @@ func (renderer *sidebarRenderer) MinSize() fyne.Size {
minHeight += button.MinSize().Height + theme.InnerPadding()
minWidth = fyne.Max(minWidth, button.MinSize().Width+2*theme.InnerPadding())
}
textsize = fyne.MeasureText(renderer.version.Text, renderer.version.TextSize, renderer.version.TextStyle)
minHeight += textsize.Height + theme.InnerPadding()

return fyne.NewSize(minWidth, minHeight)
}
Expand All @@ -146,7 +137,6 @@ func (renderer *sidebarRenderer) Refresh() {
renderer.text.Text = renderer.widget.text
renderer.background.Refresh()
renderer.text.Refresh()
renderer.version.Refresh()
for _, button := range renderer.widget.buttons {
button.Refresh()
}
Expand Down

0 comments on commit 642e716

Please sign in to comment.