Skip to content

Commit

Permalink
signin page.
Browse files Browse the repository at this point in the history
  • Loading branch information
schwarzlichtbezirk committed Nov 18, 2024
1 parent cc8a413 commit aa4f20f
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: '1.23'

Expand Down
2 changes: 1 addition & 1 deletion api/logic.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var (
func (p Props) Expired() bool {
const lag = 20 * time.Millisecond // for refresh synchronization
var d = time.Since(p.last)
return d < Cfg.PropUpdateTick-lag
return d > Cfg.PropUpdateTick-lag
}

func (u *User) GetProps(cid uint64) (p Props, ok bool) {
Expand Down
133 changes: 75 additions & 58 deletions ui/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/data/validation"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/widget"
"github.com/slotopol/balance/api"
cfg "github.com/slotopol/balance/config"
Expand All @@ -27,63 +29,6 @@ var (
Cfg = cfg.Cfg // shortcut
)

// Label compatible with ToolbarItem interface to insert into Toolbar.
type ToolbarLabel struct {
widget.Label
}

func NewToolbarLabel(text string) *ToolbarLabel {
var l = &ToolbarLabel{
Label: widget.Label{
Text: text,
Alignment: fyne.TextAlignLeading,
TextStyle: fyne.TextStyle{},
},
}
l.ExtendBaseWidget(l)
return l
}

func (tl *ToolbarLabel) ToolbarObject() fyne.CanvasObject {
tl.Label.Importance = widget.LowImportance
return tl
}

// Layout that fits the images to whole space and cuts edges if it needs.
type FitLayout struct {
}

func (l FitLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
var ratiofit = size.Width / size.Height
for _, child := range objects {
var newsize = size
var pos = fyne.NewPos(0, 0)
if img, ok := child.(*canvas.Image); ok {
var ratioimg = img.Aspect()
if ratiofit > ratioimg {
newsize.Height = size.Width / ratioimg
pos.Y = (size.Height - newsize.Height) / 2
} else {
newsize.Width = size.Height * ratioimg
pos.Y = (size.Width - newsize.Width) / 2
}
}
child.Resize(newsize)
child.Move(pos)
}
}

func (l FitLayout) MinSize(objects []fyne.CanvasObject) fyne.Size {
var minSize = fyne.NewSize(0, 0)
for _, child := range objects {
if !child.Visible() {
continue
}
minSize = minSize.Max(child.MinSize())
}
return minSize
}

func GetProp(cid uint64, user *api.User) (p api.Props, err error) {
if p, _ = user.GetProps(curcid); !p.Expired() {
return // return cached
Expand Down Expand Up @@ -117,9 +62,81 @@ func FormatAL(al api.AL) string {

type Frame struct {
fyne.Window
SigninPage
MainPage
}

type SigninPage struct {
// Backgroud image
underlay *canvas.Image

// Form widgets
host *widget.Entry
email *widget.Entry
secret *widget.Entry
form *widget.Form
errmsg *widget.Label

// Page frame
signinPage *fyne.Container
}

const descrmd = `# SLOTOPOL credentials
To be able to view and change balance of users, the account must have the administrator access permission for working with *users*. To be able to view and change contents of the club bank, deposit and jackpot fund, the access permission for working with the *club* is required.
`

const (
hostRx = `^((http|https|ftp):\/\/)?(\w[\w_\-]*(\.\w[\w_\-]*)*)(:\d+)?$`
emailRx = `^\w[\w_\-\.]*@\w+\.\w{1,4}$`
)

func (p *SigninPage) Create() {
// Backgroud image
p.underlay = &canvas.Image{
Resource: AnyUnderlay(),
FillMode: canvas.ImageFillContain,
Translucency: 0.85,
}

// Description
var descr = widget.NewRichTextFromMarkdown(descrmd)
descr.Wrapping = fyne.TextWrapWord

// Form widgets
p.host = widget.NewEntry()
p.host.SetPlaceHolder("http://example.com:8080")
p.host.Validator = validation.NewRegexp(hostRx, "not a valid host")
p.host.Text = cfg.Credentials.Addr
p.email = widget.NewEntry()
p.email.SetPlaceHolder("[email protected]")
p.email.Validator = validation.NewRegexp(emailRx, "not a valid email")
p.email.Text = cfg.Credentials.Email
p.secret = widget.NewPasswordEntry()
p.secret.SetPlaceHolder("password")
p.secret.Text = cfg.Credentials.Secret
p.errmsg = widget.NewLabel("")
p.errmsg.Wrapping = fyne.TextWrapWord
p.form = &widget.Form{
Items: []*widget.FormItem{
{Text: "Host", Widget: p.host, HintText: "Host address of server"},
{Text: "Email", Widget: p.email, HintText: "A valid registered email address"},
{Text: "Secret", Widget: p.secret, HintText: "Password for authorization"},
},
}

p.signinPage = container.NewStack(
NewImageFit(p.underlay),
container.NewVBox(
layout.NewSpacer(),
descr,
p.form,
layout.NewSpacer(),
p.errmsg,
),
)
}

type MainPage struct {
// Backgroud image
underlay *canvas.Image
Expand Down Expand Up @@ -244,7 +261,7 @@ func (p *MainPage) Create() {

// Main page
p.mainPage = container.NewStack(
container.New(FitLayout{}, p.underlay),
NewImageFit(p.underlay),
container.NewBorder(
container.NewVBox(p.toolbar, p.clubTabs),
nil, nil, nil,
Expand Down
51 changes: 34 additions & 17 deletions ui/startup.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,6 @@ import (
cfg "github.com/slotopol/balance/config"
)

func (f *Frame) MakeSignIn() (err error) {
if err = cfg.ReadCredentials(); err != nil {
log.Printf("failure on reading credentials, using default: %s\n", err.Error())
err = nil // skip this error
return
}
if api.Admin, err = api.ReqSignIn(cfg.Credentials.Email, cfg.Credentials.Secret); err != nil {
return
}
f.loginTxt.SetText(fmt.Sprintf(cfg.Credentials.Email))
log.Printf("signed as '%s'", cfg.Credentials.Email)
return
}

func (f *Frame) MakeClubList() (err error) {
var cl api.RetClubList
if cl, err = api.ReqClubList(); err != nil {
Expand Down Expand Up @@ -113,7 +99,6 @@ func WaitToken() (err error) {

func (f *Frame) StartupChain() {
var chain = [](func() error){
f.MakeSignIn,
f.MakeClubList,
f.MakeUserList,
}
Expand All @@ -126,19 +111,51 @@ func (f *Frame) StartupChain() {
}

func (f *Frame) CreateWindow(a fyne.App) {
var errCred error
if errCred = cfg.ReadCredentials(); errCred != nil {
log.Printf("failure on reading credentials, using default: %s\n", errCred.Error())
return
}

f.MainPage.Create()
f.SigninPage.Create()

go f.StartupChain()
go WaitToken()

var w = a.NewWindow("Balance")
w.Resize(fyne.NewSize(540, 640))
w.SetContent(f.mainPage)
w.SetContent(f.signinPage)
f.Window = w

var submit = func() {
f.loginTxt.SetText(cfg.Credentials.Email)
w.SetContent(f.mainPage)
go f.StartupChain()
f.SigninPage.form.OnCancel = func() {
w.SetContent(f.mainPage)
}
f.SigninPage.form.Refresh()
}
f.SigninPage.form.OnSubmit = func() {
var err error
if api.Admin, err = api.ReqSignIn(f.email.Text, f.secret.Text); err != nil {
f.errmsg.SetText(fmt.Sprintf("can not sign in with given credentials, %s", err.Error()))
return
}
cfg.Credentials.Addr = f.host.Text
cfg.Credentials.Email = f.email.Text
cfg.Credentials.Secret = f.secret.Text
log.Printf("signed as '%s'", cfg.Credentials.Email)
submit()
}
f.SigninPage.form.Refresh()
f.userTable.SetColumnWidth(0, 180) // email
f.userTable.SetColumnWidth(1, 100) // wallet
f.userTable.SetColumnWidth(2, 50) // mtrp
f.userTable.SetColumnWidth(3, 150) // access
f.userTable.ExtendBaseWidget(f.userTable)

if cfg.Credentials.Addr != "" && cfg.Credentials.Email != "" {
//submit()
}
}
72 changes: 72 additions & 0 deletions ui/widgets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package ui

import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)

// Label compatible with ToolbarItem interface to insert into Toolbar.
type ToolbarLabel struct {
widget.Label
}

func NewToolbarLabel(text string) *ToolbarLabel {
var l = &ToolbarLabel{
Label: widget.Label{
Text: text,
Alignment: fyne.TextAlignLeading,
TextStyle: fyne.TextStyle{},
},
}
l.ExtendBaseWidget(l)
return l
}

func (tl *ToolbarLabel) ToolbarObject() fyne.CanvasObject {
tl.Label.Importance = widget.LowImportance
return tl
}

type CenterVBoxLayout struct {
}

// Layout that fits the images to whole space and cuts edges if it needs.
type ImageFitLayout struct {
}

func NewImageFit(objects ...fyne.CanvasObject) *fyne.Container {
return container.New(ImageFitLayout{}, objects...)
}

func (l ImageFitLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
var ratiofit = size.Width / size.Height
for _, child := range objects {
var newsize = size
var pos = fyne.NewPos(0, 0)
if img, ok := child.(*canvas.Image); ok {
var ratioimg = img.Aspect()
if ratiofit > ratioimg {
newsize.Height = size.Width / ratioimg
pos.Y = (size.Height - newsize.Height) / 2
} else {
newsize.Width = size.Height * ratioimg
pos.Y = (size.Width - newsize.Width) / 2
}
}
child.Resize(newsize)
child.Move(pos)
}
}

func (l ImageFitLayout) MinSize(objects []fyne.CanvasObject) fyne.Size {
var minSize = fyne.NewSize(0, 0)
for _, child := range objects {
if !child.Visible() {
continue
}
minSize = minSize.Max(child.MinSize())
}
return minSize
}

0 comments on commit aa4f20f

Please sign in to comment.