~f4814n/frost

b5ab5be115e6724ab9ee4af9887229e8fbb83c29 — Fabian Geiselhart 1 year, 3 months ago d1f5fd3
Make login page more visually appealing
2 files changed, 120 insertions(+), 82 deletions(-)

A login_page.go
M main.go
A login_page.go => login_page.go +117 -0
@@ 0,0 1,117 @@
package main

import (
	"fmt"
	"image"

	"gioui.org/layout"
	"gioui.org/unit"
	"gioui.org/widget"
	"gioui.org/widget/material"
	log "github.com/sirupsen/logrus"
)

type LoginPage struct {
	rx, tx chan Event

	usernameEditor *widget.Editor
	passwordEditor *widget.Editor
	loginButton    *widget.Clickable

	errorMessage string

	loginInProcess bool
}

type LoginStartEvent struct {
	Username, Password string
}

type LoginErrorEvent struct {
	Err error
}

func NewLoginPage() *LoginPage {
	return &LoginPage{
		loginInProcess: false,
		usernameEditor: &widget.Editor{Submit: true, SingleLine: true},
		passwordEditor: &widget.Editor{Submit: true, SingleLine: true},
		loginButton:    new(widget.Clickable),
	}
}

func (l *LoginPage) Start(rx, tx chan Event) {
	l.rx, l.tx = rx, tx
}

func (l *LoginPage) update() {
	if l.loginButton.Clicked() {
		l.loginInProcess = true

		username := l.usernameEditor.Text()
		password := l.passwordEditor.Text()

		l.tx <- LoginStartEvent{Username: username, Password: password}
	}

	for {
		select {
		case e := <-l.rx:
			switch e := e.(type) {
			case LoginErrorEvent:
				l.loginInProcess = false
				l.errorMessage = fmt.Sprintf("%#v", e.Err)
			default:
				log.Warnf("%#v", e)
			}
		default:
			return
		}
	}
}

func (l *LoginPage) Layout(gtx Gtx) {
	l.update()

	if l.loginInProcess {
		gtx = gtx.Disabled()
	}

	center(gtx, image.Point{X: gtx.Px(unit.Dp(280)), Y: gtx.Px(unit.Dp(480))}, func(gtx Gtx) Dims {
		gtx.Constraints.Min = gtx.Constraints.Max
		return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
			layout.Rigid(material.Editor(theme, l.usernameEditor, "username").Layout),
			layout.Rigid(material.Editor(theme, l.passwordEditor, "password").Layout),
			layout.Rigid(func(gtx Gtx) Dims {
				in := layout.Inset{}

				if l.errorMessage != "" {
					in = layout.Inset{
						Top:    unit.Dp(2),
						Bottom: unit.Dp(2),
					}
				}

				lbl := material.Caption(theme, l.errorMessage)
				lbl.Color = rgb(0xff0000)
				return in.Layout(gtx, lbl.Layout)
			}),
			layout.Rigid(material.Button(theme, l.loginButton, "Login").Layout),
		)
	})
}

func (l *LoginPage) Stop() {
}

func center(gtx Gtx, max image.Point, widget layout.Widget) Dims {
	horizontal := layout.Flex{Alignment: layout.Middle, Spacing: layout.SpaceSides, Axis: layout.Horizontal}
	vertical := layout.Flex{Alignment: layout.Middle, Spacing: layout.SpaceSides, Axis: layout.Vertical}

	return horizontal.Layout(gtx,
		layout.Rigid(func(gtx Gtx) Dims {
			gtx.Constraints.Max = max
			return vertical.Layout(gtx, layout.Rigid(widget))
		}),
	)
}

M main.go => main.go +3 -82
@@ 16,7 16,6 @@ import (
	"gioui.org/op"
	"gioui.org/text"
	"gioui.org/unit"
	"gioui.org/widget"
	"gioui.org/widget/material"
	"git.sr.ht/~f4814n/matrix"
	memorybackend "git.sr.ht/~f4814n/matrix/backend/memory"


@@ 110,83 109,6 @@ func (a *App) Layout(gtx Gtx) {

type InvalidationEvent struct{}

type LoginPage struct {
	rx, tx chan Event

	usernameEditor *widget.Editor
	passwordEditor *widget.Editor
	loginButton    *widget.Clickable

	errorMessage string

	loginInProcess bool
}

type LoginStartEvent struct {
	Username, Password string
}

type LoginErrorEvent struct {
	Err error
}

func NewLoginPage() *LoginPage {
	return &LoginPage{
		loginInProcess: false,
		usernameEditor: &widget.Editor{Submit: true},
		passwordEditor: &widget.Editor{Submit: true},
		loginButton:    new(widget.Clickable),
	}
}

func (l *LoginPage) Start(rx, tx chan Event) {
	l.rx, l.tx = rx, tx
}

func (l *LoginPage) update() {
	if l.loginButton.Clicked() {
		l.loginInProcess = true

		username := l.usernameEditor.Text()
		password := l.passwordEditor.Text()

		l.tx <- LoginStartEvent{Username: username, Password: password}
	}

	for {
		select {
		case e := <-l.rx:
			switch e := e.(type) {
			case LoginErrorEvent:
				l.loginInProcess = false
				l.errorMessage = fmt.Sprintf("%#v", e.Err)
			default:
				log.Warnf("%#v", e)
			}
		default:
			return
		}
	}
}

func (l *LoginPage) Layout(gtx Gtx) {
	l.update()

	if l.loginInProcess {
		gtx = gtx.Disabled()
	}

	layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle, Spacing: layout.SpaceSides}.Layout(gtx,
		layout.Rigid(material.Editor(theme, l.usernameEditor, "username").Layout),
		layout.Rigid(material.Editor(theme, l.passwordEditor, "password").Layout),
		layout.Rigid(material.Caption(theme, l.errorMessage).Layout),
		layout.Rigid(material.Button(theme, l.loginButton, "Login").Layout),
	)
}

func (l *LoginPage) Stop() {
}

type ViewRoomEvent struct {
	Room matrix.Room
}


@@ 225,6 147,7 @@ func (o *OverviewPage) Start(rx, tx chan Event) {

	go func() {
		c := make(chan matrix.Event, 100)
		o.cli.Notify(c)
		for range c {
			o.tx <- InvalidationEvent{}
		}


@@ 266,8 189,8 @@ func (o *OverviewPage) Stop() {

// RoomList is a widget that displays a list of rooms
type RoomList struct {
	list   *layout.List
	rooms  []roomListElement
	list  *layout.List
	rooms []roomListElement
}

func NewRoomList() *RoomList {


@@ 297,8 220,6 @@ func (w *RoomList) NewEvent(event matrix.Event) {
	}

	w.rooms = moveToFront(roomListElement{room: room, lastEvent: event}, w.rooms)

	log.Infof("%+v", w.rooms)
}

func moveToFront(needle roomListElement, haystack []roomListElement) []roomListElement {