~whereswaldon/pointstar

34ed55e88241a57720971478602a61ea20080dea — Chris Waldon 1 year, 8 months ago af39b3f
feat: improve client UI responsiveness
3 files changed, 64 insertions(+), 28 deletions(-)

M client/main.go
M client/skin.go
M client/uistate.go
M client/main.go => client/main.go +1 -0
@@ 100,6 100,7 @@ func eventLoop(w *app.Window) error {
				case *gamestate.GameState:
					log.Println("game state updated")
					game = message
					ui.Update(game)
				case protocol.ErrorMessage:
					log.Printf("server sent error: %s", message.Message)
				default:

M client/skin.go => client/skin.go +52 -28
@@ 3,6 3,7 @@ package main
import (
	"fmt"
	"image/color"
	"strconv"

	"gioui.org/layout"
	"gioui.org/text"


@@ 147,9 148,9 @@ func (s *Skin) LayoutTable(g *gamestate.GameState, u *UIState, gtx *layout.Conte
	var children []layout.FlexChild
	// populate the slice with functions to lay out each player's hand
	for i := range g.Players {
		player := g.Players[i]
		playerNum := i
		children = append(children, layout.Rigid(func() {
			s.LayoutPlayed(player, u, gtx)
			s.LayoutPlayed(g, playerNum, u, gtx)
		}))
		children = append(children, layout.Flexed(.25, func() {}))
	}


@@ 163,33 164,51 @@ func (s *Skin) LayoutTable(g *gamestate.GameState, u *UIState, gtx *layout.Conte

// LayoutPlayed arranges a row of information about a player and the cards
// that they have played during the current battle
func (s *Skin) LayoutPlayed(player gamestate.Player, u *UIState, gtx *layout.Context) {
func (s *Skin) LayoutPlayed(g *gamestate.GameState, playerNum int, u *UIState, gtx *layout.Context) {
	player := g.Players[playerNum]
	var children []layout.FlexChild
	// prepend player info
	hand := player.Played
	children = append(children, layout.Rigid(func() {
		layout.Flex{Axis: layout.Vertical}.Layout(gtx,
			layout.Rigid(func() {
				s.Theme.H3(player.Name).Layout(gtx)
			}),
			layout.Rigid(func() {
				format := "Strength: %d"
				if player.IsPassing {
					format += " Passed"
				}
				s.Theme.H5(fmt.Sprintf(format, hand.Score())).Layout(gtx)
			}),
			layout.Rigid(func() {
				s.Theme.H6(fmt.Sprintf("Victories: %d", player.Victories)).Layout(gtx)
			}),
			layout.Rigid(func() {
				s.Theme.H6(fmt.Sprintf("Hand: %d", len(player.Hand))).Layout(gtx)
			}),
		)
		layout.Inset{Left: unit.Dp(8)}.Layout(gtx, func() {
			layout.Flex{Axis: layout.Vertical}.Layout(gtx,
				layout.Rigid(func() {
					playerName := s.Theme.H3(player.Name)
					if g.Turn == playerNum {
						playerName.Color = color.RGBA{R: 51, G: 204, B: 51, A: 255}
					}
					playerName.Layout(gtx)
				}),
				layout.Rigid(func() {
					s.Theme.H6(fmt.Sprintf("Victories: %d", player.Victories)).Layout(gtx)
				}),
				layout.Rigid(func() {
					s.Theme.H6(fmt.Sprintf("Hand: %d", len(player.Hand))).Layout(gtx)
				}),
			)
		})
	}))
	children = append(children, layout.Flexed(1, func() {
		u.PlayedLists[playerNum].Layout(gtx, len(player.Played), func(index int) {
			s.LayoutCardPadded(player.Played[index], gtx)
		})
	}))
	children = append(children, layout.Rigid(func() {
		layout.Inset{Right: unit.Dp(8)}.Layout(gtx, func() {
			layout.Flex{Axis: layout.Vertical}.Layout(gtx,
				layout.Rigid(func() {
					if player.IsPassing {
						s.H6("Passed:").Layout(gtx)
					} else {
						s.H6("Strength:").Layout(gtx)
					}
				}),
				layout.Rigid(func() {
					s.H3(strconv.Itoa(hand.Score())).Layout(gtx)
				}),
			)
		})
	}))
	children = append(children, layout.Flexed(.5, func() {}))
	children = append(children, s.CardListAsFlexChildren(hand, gtx)...)
	children = append(children, layout.Flexed(.5, func() {}))
	layout.Flex{Axis: layout.Horizontal}.Layout(gtx, children...)
}



@@ 202,7 221,9 @@ func (s *Skin) LayoutHand(g *gamestate.GameState, u *UIState, gtx *layout.Contex
	layout.Flex{Axis: layout.Vertical}.Layout(gtx,
		layout.Rigid(func() {
			layout.SW.Layout(gtx, func() {
				s.H6("Your hand:").Layout(gtx)
				layout.Inset{Left: unit.Dp(8)}.Layout(gtx, func() {
					s.H6("Your hand:").Layout(gtx)
				})
			})
		}),
		layout.Rigid(func() {


@@ 241,6 262,11 @@ func (s *Skin) LayoutHand(g *gamestate.GameState, u *UIState, gtx *layout.Contex
	)
}

func (s *Skin) LayoutCardPadded(c gamestate.Card, gtx *layout.Context) {
	layout.UniformInset(unit.Dp(8)).Layout(gtx, func() {
		s.LayoutCard(c, gtx)
	})
}
func (s *Skin) LayoutCard(c gamestate.Card, gtx *layout.Context) {
	textColor := color.RGBA{A: 255}
	if gamestate.CardTypes[c] == gamestate.Special {


@@ 265,9 291,7 @@ func (s *Skin) CardListAsFlexChildren(h gamestate.CardList, gtx *layout.Context)
	for i := range h {
		card := h[i]
		children = append(children, layout.Rigid(func() {
			layout.UniformInset(unit.Dp(8)).Layout(gtx, func() {
				s.LayoutCard(card, gtx)
			})
			s.LayoutCardPadded(card, gtx)
		}))
	}
	return children

M client/uistate.go => client/uistate.go +11 -0
@@ 17,5 17,16 @@ type UIState struct {

	HandList layout.List

	PlayedLists []layout.List

	Worker *WSWorker
}

// Update processes a new gamestate and carries out any necessary bookkeeping
// such as allocating structures for storing the UI state associated with a
// new player
func (u *UIState) Update(g *gamestate.GameState) {
	if len(u.PlayedLists) < len(g.Players) {
		u.PlayedLists = make([]layout.List, len(g.Players))
	}
}