blob: 8f35a3b3ca469c2d2bf551c6fd7e4b9cfac5b453 [file] [log] [blame]
package main
import (
"image"
"image/color"
"gioui.org/layout"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
)
type (
C = layout.Context
D = layout.Dimensions
)
type DeviceCapabilities struct {
HasCamera bool
}
type UI struct {
th *material.Theme
cap DeviceCapabilities
invite struct {
open widget.Clickable
show bool
qr image.Image
}
approve struct {
open widget.Clickable
show bool
}
join struct {
open widget.Clickable
show bool
qr image.Image
}
}
func NewUI(th *material.Theme, cap DeviceCapabilities) *UI {
return &UI{th: th, cap: cap}
}
func (ui *UI) InviteQRGenerated(img image.Image) {
ui.invite.qr = img
}
func (ui *UI) JoinQRGenerated(img image.Image) {
ui.join.qr = img
}
func (ui *UI) OnBack() bool {
if ui.invite.show {
ui.invite.show = false
return true
} else if ui.approve.show {
ui.approve.show = false
return true
} else if ui.join.show {
ui.join.show = false
return true
}
return false
}
func (ui *UI) Layout(gtx C) []UIEvent {
var events []UIEvent
if ui.invite.open.Clicked() {
ui.invite.show = true
ui.approve.show = false
ui.join.show = false
ui.invite.qr = nil
events = append(events, EventGetInviteQRCode{})
} else if ui.approve.open.Clicked() {
events = append(events, EventApproveOther{})
} else if ui.join.open.Clicked() {
if ui.cap.HasCamera {
events = append(events, EventScanBarcode{})
} else {
ui.invite.show = false
ui.approve.show = false
ui.join.show = true
events = append(events, EventGetJoinQRCode{})
}
}
if ui.invite.show {
ui.layout(gtx, ui.layoutInvite)
} else if ui.join.show {
ui.layout(gtx, ui.layoutJoin)
} else {
ui.layout(gtx, ui.layoutMain)
}
return events
}
func (ui *UI) layout(gtx C, mainPanel layout.Widget) D {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Flexed(10, func(gtx C) D {
return mainPanel(gtx)
}),
layout.Flexed(1, func(gtx C) D {
return ui.layoutActions(gtx)
}),
)
}
func ColorBox(gtx layout.Context, size image.Point, color color.NRGBA) layout.Dimensions {
defer clip.Rect{Max: size}.Push(gtx.Ops).Pop()
paint.ColorOp{Color: color}.Add(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
return layout.Dimensions{Size: size}
}
func (ui *UI) layoutMain(gtx C) D {
return ColorBox(gtx, gtx.Constraints.Min, color.NRGBA{B: 255, A: 255})
}
func (ui *UI) layoutActions(gtx C) D {
return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceAround, WeightSum: 3.2}.Layout(gtx,
layout.Flexed(1, func(gtx C) D {
b := material.Button(ui.th, &ui.invite.open, "Invite")
b.CornerRadius = unit.Px(20)
return b.Layout(gtx)
}),
layout.Flexed(1, func(gtx C) D {
b := material.Button(ui.th, &ui.approve.open, "Approve")
b.CornerRadius = unit.Px(20)
return b.Layout(gtx)
}),
layout.Flexed(1, func(gtx C) D {
b := material.Button(ui.th, &ui.join.open, "Join")
b.CornerRadius = unit.Px(20)
return b.Layout(gtx)
}),
)
}
func layoutQR(gtx C, qr image.Image) D {
if qr == nil {
return ColorBox(gtx, gtx.Constraints.Max, color.NRGBA{})
}
d := qr.Bounds().Max.Sub(qr.Bounds().Min)
return layout.Inset{
Left: unit.Px(0.5 * float32(gtx.Constraints.Max.X-d.X)),
Top: unit.Px(0.5 * float32(gtx.Constraints.Max.Y-d.Y)),
}.Layout(gtx, func(gtx C) D {
paint.NewImageOp(qr).Add(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
return D{Size: gtx.Constraints.Max}
})
}
func (ui *UI) layoutInvite(gtx C) D {
return layoutQR(gtx, ui.invite.qr)
}
func (ui *UI) layoutJoin(gtx C) D {
return layoutQR(gtx, ui.join.qr)
}