347 lines
8.7 KiB
Go
347 lines
8.7 KiB
Go
package gui
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/p9c/p9/pkg/amt"
|
|
|
|
"github.com/atotto/clipboard"
|
|
|
|
l "github.com/p9c/p9/pkg/gel/gio/layout"
|
|
"github.com/p9c/p9/pkg/gel/gio/text"
|
|
|
|
"github.com/p9c/p9/pkg/gel"
|
|
)
|
|
|
|
const Break1 = 48
|
|
|
|
type ReceivePage struct {
|
|
wg *WalletGUI
|
|
inputWidth, break1 float32
|
|
sm, md, lg, xl l.Widget
|
|
urn string
|
|
}
|
|
|
|
func (wg *WalletGUI) GetReceivePage() (rp *ReceivePage) {
|
|
rp = &ReceivePage{
|
|
wg: wg,
|
|
inputWidth: 17,
|
|
break1: 48,
|
|
}
|
|
rp.sm = rp.SmallList
|
|
return
|
|
}
|
|
|
|
func (rp *ReceivePage) Fn(gtx l.Context) l.Dimensions {
|
|
wg := rp.wg
|
|
return wg.Responsive(
|
|
wg.Size.Load(), gel.Widgets{
|
|
{
|
|
Widget: rp.SmallList,
|
|
},
|
|
{
|
|
Size: rp.break1,
|
|
Widget: rp.MediumList,
|
|
},
|
|
},
|
|
).Fn(gtx)
|
|
}
|
|
|
|
func (rp *ReceivePage) SmallList(gtx l.Context) l.Dimensions {
|
|
wg := rp.wg
|
|
smallWidgets := []l.Widget{
|
|
wg.Direction().Center().Embed(rp.QRButton()).Fn,
|
|
rp.InputMessage(),
|
|
rp.AmountInput(),
|
|
rp.MessageInput(),
|
|
rp.RegenerateButton(),
|
|
rp.AddressbookHeader(),
|
|
}
|
|
smallWidgets = append(smallWidgets, rp.GetAddressbookHistoryCards("DocBg")...)
|
|
le := func(gtx l.Context, index int) l.Dimensions {
|
|
return wg.Inset(0.25, smallWidgets[index]).Fn(gtx)
|
|
}
|
|
return wg.VFlex().AlignStart().
|
|
Flexed(
|
|
1,
|
|
wg.lists["receive"].
|
|
Vertical().Start().
|
|
Length(len(smallWidgets)).
|
|
ListElement(le).Fn,
|
|
).Fn(gtx)
|
|
}
|
|
|
|
func (rp *ReceivePage) InputMessage() l.Widget {
|
|
return rp.wg.Body2("Input details to request a payment").Alignment(text.Middle).Fn
|
|
}
|
|
|
|
func (rp *ReceivePage) MediumList(gtx l.Context) l.Dimensions {
|
|
wg := rp.wg
|
|
qrWidget := []l.Widget{
|
|
wg.Direction().Center().Embed(rp.QRButton()).Fn,
|
|
rp.InputMessage(),
|
|
rp.AmountInput(),
|
|
rp.MessageInput(),
|
|
rp.RegenerateButton(),
|
|
// rp.AddressbookHeader(),
|
|
}
|
|
qrLE := func(gtx l.Context, index int) l.Dimensions {
|
|
return wg.Inset(0.25, qrWidget[index]).Fn(gtx)
|
|
}
|
|
var historyWidget []l.Widget
|
|
|
|
historyWidget = append(historyWidget, rp.GetAddressbookHistoryCards("DocBg")...)
|
|
historyLE := func(gtx l.Context, index int) l.Dimensions {
|
|
return wg.Inset(
|
|
0.25,
|
|
historyWidget[index],
|
|
).Fn(gtx)
|
|
}
|
|
return wg.Flex().AlignStart().
|
|
Rigid(
|
|
func(gtx l.Context) l.Dimensions {
|
|
gtx.Constraints.Max.X, gtx.Constraints.Min.X = int(wg.TextSize.V*rp.inputWidth),
|
|
int(wg.TextSize.V*rp.inputWidth)
|
|
return wg.VFlex().
|
|
Rigid(
|
|
wg.lists["receiveMedium"].
|
|
Vertical().
|
|
Length(len(qrWidget)).
|
|
ListElement(qrLE).Fn,
|
|
).Fn(gtx)
|
|
},
|
|
).
|
|
Rigid(
|
|
wg.VFlex().AlignStart().
|
|
Rigid(
|
|
rp.AddressbookHeader(),
|
|
).
|
|
Rigid(
|
|
wg.lists["receiveAddresses"].
|
|
Vertical().
|
|
Length(len(historyWidget)).
|
|
ListElement(historyLE).Fn,
|
|
).
|
|
Fn,
|
|
).Fn(gtx)
|
|
}
|
|
|
|
func (rp *ReceivePage) Spacer() l.Widget {
|
|
return rp.wg.Flex().AlignMiddle().Flexed(1, rp.wg.Inset(0.25, gel.EmptySpace(0, 0)).Fn).Fn
|
|
}
|
|
|
|
func (rp *ReceivePage) GetAddressbookHistoryCards(bg string) (widgets []l.Widget) {
|
|
wg := rp.wg
|
|
avail := len(wg.receiveAddressbookClickables)
|
|
req := len(wg.State.receiveAddresses)
|
|
if req > avail {
|
|
for i := 0; i < req-avail; i++ {
|
|
wg.receiveAddressbookClickables = append(wg.receiveAddressbookClickables, wg.WidgetPool.GetClickable())
|
|
}
|
|
}
|
|
for x := range wg.State.receiveAddresses {
|
|
j := x
|
|
i := len(wg.State.receiveAddresses) - 1 - x
|
|
widgets = append(
|
|
widgets, func(gtx l.Context) l.Dimensions {
|
|
return wg.ButtonLayout(
|
|
wg.receiveAddressbookClickables[i].SetClick(
|
|
func() {
|
|
msg := wg.State.receiveAddresses[i].Message
|
|
if len(msg) > 64 {
|
|
msg = msg[:64]
|
|
}
|
|
qrText := fmt.Sprintf(
|
|
"parallelcoin:%s?amount=%8.8f&message=%s",
|
|
wg.State.receiveAddresses[i].Address,
|
|
wg.State.receiveAddresses[i].Amount.ToDUO(),
|
|
msg,
|
|
)
|
|
D.Ln("clicked receive address list item", j)
|
|
if e := clipboard.WriteAll(qrText); E.Chk(e) {
|
|
}
|
|
wg.GetNewReceivingQRCode(qrText)
|
|
rp.urn = qrText
|
|
},
|
|
),
|
|
).
|
|
Background(bg).
|
|
Embed(
|
|
wg.Inset(
|
|
0.25,
|
|
wg.VFlex().AlignStart().
|
|
Rigid(
|
|
wg.Flex().AlignBaseline().
|
|
Rigid(
|
|
wg.Caption(wg.State.receiveAddresses[i].Address).
|
|
Font("go regular").Fn,
|
|
).
|
|
Flexed(
|
|
1,
|
|
wg.Body1(wg.State.receiveAddresses[i].Amount.String()).
|
|
Alignment(text.End).Fn,
|
|
).
|
|
Fn,
|
|
).
|
|
Rigid(
|
|
wg.Caption(wg.State.receiveAddresses[i].Message).MaxLines(1).Fn,
|
|
).
|
|
Fn,
|
|
).
|
|
Fn,
|
|
).Fn(gtx)
|
|
},
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (rp *ReceivePage) QRMessage() l.Widget {
|
|
return rp.wg.Body2("Scan to send or click to copy").Alignment(text.Middle).Fn
|
|
}
|
|
|
|
func (rp *ReceivePage) GetQRText() string {
|
|
wg := rp.wg
|
|
msg := wg.inputs["receiveMessage"].GetText()
|
|
if len(msg) > 64 {
|
|
msg = msg[:64]
|
|
}
|
|
return fmt.Sprintf(
|
|
"parallelcoin:%s?amount=%s&message=%s",
|
|
wg.State.currentReceivingAddress.Load().EncodeAddress(),
|
|
wg.inputs["receiveAmount"].GetText(),
|
|
msg,
|
|
)
|
|
}
|
|
|
|
func (rp *ReceivePage) QRButton() l.Widget {
|
|
wg := rp.wg
|
|
if !wg.WalletAndClientRunning() || wg.currentReceiveQRCode == nil {
|
|
return func(gtx l.Context) l.Dimensions {
|
|
return l.Dimensions{}
|
|
}
|
|
}
|
|
return wg.VFlex().
|
|
Rigid(
|
|
wg.ButtonLayout(
|
|
wg.currentReceiveCopyClickable.SetClick(
|
|
func() {
|
|
D.Ln("clicked qr code copy clicker")
|
|
if e := clipboard.WriteAll(rp.urn); E.Chk(e) {
|
|
}
|
|
},
|
|
),
|
|
).
|
|
Background("white").
|
|
Embed(
|
|
wg.Inset(
|
|
0.125,
|
|
wg.Image().Src(*wg.currentReceiveQRCode).Scale(1).Fn,
|
|
).Fn,
|
|
).Fn,
|
|
).Rigid(
|
|
rp.QRMessage(),
|
|
).Fn
|
|
}
|
|
|
|
func (rp *ReceivePage) AddressbookHeader() l.Widget {
|
|
wg := rp.wg
|
|
return wg.Flex().
|
|
Rigid(
|
|
wg.Inset(
|
|
0.25,
|
|
wg.H5("Receive Address History").Alignment(text.Middle).Fn,
|
|
).Fn,
|
|
).Fn
|
|
}
|
|
|
|
func (rp *ReceivePage) AmountInput() l.Widget {
|
|
return func(gtx l.Context) l.Dimensions {
|
|
wg := rp.wg
|
|
// gtx.Constraints.Max.X, gtx.Constraints.Min.X = int(wg.TextSize.True*rp.inputWidth), int(wg.TextSize.True*rp.inputWidth)
|
|
return wg.inputs["receiveAmount"].Fn(gtx)
|
|
}
|
|
}
|
|
|
|
func (rp *ReceivePage) MessageInput() l.Widget {
|
|
return func(gtx l.Context) l.Dimensions {
|
|
wg := rp.wg
|
|
// gtx.Constraints.Max.X, gtx.Constraints.Min.X = int(wg.TextSize.True*rp.inputWidth), int(wg.TextSize.True*rp.inputWidth)
|
|
return wg.inputs["receiveMessage"].Fn(gtx)
|
|
}
|
|
}
|
|
|
|
func (rp *ReceivePage) RegenerateButton() l.Widget {
|
|
return func(gtx l.Context) l.Dimensions {
|
|
wg := rp.wg
|
|
if wg.inputs["receiveAmount"].GetText() == "" || wg.inputs["receiveMessage"].GetText() == "" {
|
|
gtx.Queue = nil
|
|
}
|
|
// gtx.Constraints.Max.X, gtx.Constraints.Min.X = int(wg.TextSize.True*rp.inputWidth), int(wg.TextSize.True*rp.inputWidth)
|
|
return wg.ButtonLayout(
|
|
wg.currentReceiveRegenClickable.
|
|
SetClick(
|
|
func() {
|
|
D.Ln("clicked regenerate button")
|
|
var amount float64
|
|
var am amt.Amount
|
|
var e error
|
|
if amount, e = strconv.ParseFloat(
|
|
wg.inputs["receiveAmount"].GetText(),
|
|
64,
|
|
); !E.Chk(e) {
|
|
if am, e = amt.NewAmount(amount); E.Chk(e) {
|
|
}
|
|
}
|
|
msg := wg.inputs["receiveMessage"].GetText()
|
|
if am == 0 || msg == "" {
|
|
// never store an entry without both fields filled
|
|
return
|
|
}
|
|
if len(wg.State.receiveAddresses) > 0 &&
|
|
(wg.State.receiveAddresses[len(wg.State.receiveAddresses)-1].Amount == 0 ||
|
|
wg.State.receiveAddresses[len(wg.State.receiveAddresses)-1].Message == "") {
|
|
// the first entry has neither of these, and newly generated items without them are assumed to
|
|
// not be intentional or used addresses so we don't generate a new entry for this case
|
|
wg.State.receiveAddresses[len(wg.State.receiveAddresses)-1].Amount = am
|
|
wg.State.receiveAddresses[len(wg.State.receiveAddresses)-1].Message = msg
|
|
} else {
|
|
// go func() {
|
|
wg.GetNewReceivingAddress()
|
|
msg := wg.inputs["receiveMessage"].GetText()
|
|
if len(msg) > 64 {
|
|
msg = msg[:64]
|
|
// enforce the field length limit
|
|
wg.inputs["receiveMessage"].SetText(msg)
|
|
}
|
|
qrText := fmt.Sprintf(
|
|
"parallelcoin:%s?amount=%f&message=%s",
|
|
wg.State.currentReceivingAddress.Load().EncodeAddress(),
|
|
am.ToDUO(),
|
|
msg,
|
|
)
|
|
rp.urn = qrText
|
|
wg.GetNewReceivingQRCode(rp.urn)
|
|
// }()
|
|
}
|
|
// force user to fill fields again after regenerate to stop duplicate entries especially from
|
|
// accidental double clicks/taps
|
|
wg.inputs["receiveAmount"].SetText("")
|
|
wg.inputs["receiveMessage"].SetText("")
|
|
wg.Invalidate()
|
|
},
|
|
),
|
|
).
|
|
Background("Primary").
|
|
Embed(
|
|
wg.Inset(
|
|
0.5,
|
|
wg.H6("regenerate").Color("Light").Fn,
|
|
).
|
|
Fn,
|
|
).
|
|
Fn(gtx)
|
|
}
|
|
}
|