createform.go raw
1 package gui
2
3 import (
4 "encoding/hex"
5 "strings"
6
7 l "github.com/p9c/p9/pkg/gel/gio/layout"
8 "github.com/p9c/p9/pkg/gel/gio/text"
9 "github.com/tyler-smith/go-bip39"
10 "golang.org/x/exp/shiny/materialdesign/icons"
11
12 "github.com/p9c/p9/pkg/gel"
13 "github.com/p9c/p9/pkg/p9icons"
14 )
15
16 func (wg *WalletGUI) centered(w l.Widget) l.Widget {
17 return wg.Flex().
18 Flexed(0.5, gel.EmptyMaxWidth()).
19 Rigid(
20 wg.VFlex().
21 AlignMiddle().
22 Rigid(
23 w,
24 ).
25 Fn,
26 ).
27 Flexed(0.5, gel.EmptyMaxWidth()).
28 Fn
29 }
30
31 func (wg *WalletGUI) cwfLogoHeader() l.Widget {
32 return wg.centered(
33 wg.Icon().
34 Scale(gel.Scales["H2"]).
35 Color("DocText").
36 Src(&p9icons.ParallelCoin).Fn,
37 )
38 }
39
40 func (wg *WalletGUI) cwfHeader() l.Widget {
41 return wg.centered(
42 wg.H4("create new wallet").
43 Color("PanelText").
44 Fn,
45 )
46 }
47
48 func (wg *WalletGUI) cwfPasswordHeader() l.Widget {
49 return wg.H5("password").
50 Color("PanelText").
51 Fn
52 }
53
54 func (wg *WalletGUI) cwfShuffleButton() l.Widget {
55 return wg.ButtonLayout(
56 wg.clickables["createShuffle"].SetClick(
57 func() {
58 wg.ShuffleSeed()
59 wg.inputs["walletWords"].SetText("") // wg.createWords)
60 wg.inputs["walletWords"].SetText("") // wg.createWords)
61 wg.restoring = false
62 wg.createVerifying = false
63 },
64 ),
65 ).
66 CornerRadius(0).
67 Corners(0).
68 Background("Primary").
69 Embed(
70 wg.Inset(
71 0.25,
72 wg.Flex().AlignMiddle().
73 Rigid(
74 wg.Icon().
75 Scale(
76 gel.Scales["H6"],
77 ).
78 Color("DocText").
79 Src(
80 &icons.NavigationRefresh,
81 ).Fn,
82 ).
83 Rigid(
84 wg.Body1("new").Color("DocText").Fn,
85 ).
86 Fn,
87 ).Fn,
88 ).Fn
89 }
90
91 func (wg *WalletGUI) cwfRestoreButton() l.Widget {
92 return wg.ButtonLayout(
93 wg.clickables["createRestore"].SetClick(
94 func() {
95 D.Ln("clicked restore button")
96 if !wg.restoring {
97 wg.inputs["walletRestore"].SetText("")
98 wg.createMatch = ""
99 wg.restoring = true
100 wg.createVerifying = false
101 } else {
102 wg.createMatch = ""
103 wg.restoring = false
104 wg.createVerifying = false
105 }
106 },
107 ),
108 ).
109 CornerRadius(0).
110 Corners(0).
111 Background("Primary").
112 Embed(
113 wg.Inset(
114 0.25,
115 wg.Flex().AlignMiddle().
116 Rigid(
117 wg.Icon().
118 Scale(
119 gel.Scales["H6"],
120 ).
121 Color("DocText").
122 Src(
123 &icons.ActionRestore,
124 ).Fn,
125 ).
126 Rigid(
127 wg.Body1("restore").Color("DocText").Fn,
128 ).
129 Fn,
130 ).Fn,
131 ).Fn
132 }
133
134 func (wg *WalletGUI) cwfSetGenesis() l.Widget {
135 return func(gtx l.Context) l.Dimensions {
136 if !wg.bools["testnet"].GetValue() {
137 return l.Dimensions{}
138 } else {
139 return wg.ButtonLayout(
140 wg.clickables["genesis"].SetClick(
141 func() {
142 seedString := "f4d2c4c542bb52512ed9e6bbfa2d000e576a0c8b4ebd1acafd7efa37247366bc"
143 var e error
144 if wg.createSeed, e = hex.DecodeString(seedString); F.Chk(e) {
145 panic(e)
146 }
147 var wk string
148 if wk, e = bip39.NewMnemonic(wg.createSeed); E.Chk(e) {
149 panic(e)
150 }
151 wks := strings.Split(wk, " ")
152 var out string
153 for i := 0; i < 24; i += 4 {
154 out += strings.Join(wks[i:i+4], " ")
155 if i+4 < 24 {
156 out += "\n"
157 }
158 }
159 wg.showWords = out
160 wg.createWords = wk
161 wg.createMatch = wk
162 wg.inputs["walletWords"].SetText(wk)
163 wg.createVerifying = true
164 },
165 ),
166 ).
167 CornerRadius(0).
168 Corners(0).
169 Background("Primary").
170 Embed(
171 wg.Inset(
172 0.25,
173 wg.Flex().AlignMiddle().
174 Rigid(
175 wg.Icon().
176 Scale(
177 gel.Scales["H6"],
178 ).
179 Color("DocText").
180 Src(
181 &icons.ActionOpenInNew,
182 ).Fn,
183 ).
184 Rigid(
185 wg.Body1("genesis").Color("DocText").Fn,
186 ).
187 Fn,
188 ).Fn,
189 ).Fn(gtx)
190 }
191 }
192 }
193
194 func (wg *WalletGUI) cwfSetAutofill() l.Widget {
195 return func(gtx l.Context) l.Dimensions {
196 if !wg.bools["testnet"].GetValue() {
197 return l.Dimensions{}
198 } else {
199 return wg.ButtonLayout(
200 wg.clickables["autofill"].SetClick(
201 func() {
202 wk := wg.createWords
203 wg.createMatch = wk
204 wg.inputs["walletWords"].SetText(wk)
205 wg.createVerifying = true
206 },
207 ),
208 ).
209 CornerRadius(0).
210 Corners(0).
211 Background("Primary").
212 Embed(
213 wg.Inset(
214 0.25,
215 wg.Flex().AlignMiddle().
216 Rigid(
217 wg.Icon().
218 Scale(
219 gel.Scales["H6"],
220 ).
221 Color("DocText").
222 Src(
223 &icons.ActionOpenInNew,
224 ).Fn,
225 ).
226 Rigid(
227 wg.Body1("autofill").Color("DocText").Fn,
228 ).
229 Fn,
230 ).Fn,
231 ).Fn(gtx)
232 }
233 }
234 }
235
236 func (wg *WalletGUI) cwfSeedHeader() l.Widget {
237 return wg.Flex(). //AlignMiddle().
238 Rigid(
239 wg.Inset(
240 0.25,
241 wg.H5("seed").
242 Color("PanelText").
243 Fn,
244 ).Fn,
245 ).
246 Rigid(wg.Inset(0.25, gel.EmptySpace(0, 0)).Fn).
247 Rigid(wg.cwfShuffleButton()).
248 Rigid(wg.Inset(0.25, gel.EmptySpace(0, 0)).Fn).
249 Rigid(wg.cwfRestoreButton()).
250 Rigid(wg.Inset(0.25, gel.EmptySpace(0, 0)).Fn).
251 Rigid(wg.cwfSetGenesis()).
252 Rigid(wg.Inset(0.25, gel.EmptySpace(0, 0)).Fn).
253 Rigid(wg.cwfSetAutofill()).
254 Fn
255 }
256
257 func (wg *WalletGUI) cfwWords() (w l.Widget) {
258 if !wg.createVerifying {
259 col := "DocText"
260 if wg.createWords == wg.createMatch {
261 col = "Success"
262 }
263 return wg.Flex().
264 Rigid(
265 wg.ButtonLayout(
266 wg.clickables["createVerify"].SetClick(
267 func() {
268 wg.createVerifying = true
269 },
270 ),
271 ).Background("Transparent").Embed(
272 wg.VFlex().
273 Rigid(
274 wg.Caption("Write the following words down, then click to re-enter and verify transcription").
275 Color("PanelText").
276 Fn,
277 ).
278 Rigid(
279 wg.Flex().Flexed(
280 1,
281 wg.Body1(wg.showWords).Alignment(text.Middle).Color(col).Fn,
282 ).Fn,
283 ).Fn,
284 ).Fn,
285 ).
286 Fn
287 }
288 return nil
289 }
290
291 func (wg *WalletGUI) cfwWordsVerify() (w l.Widget) {
292 if wg.createVerifying {
293 verifyState := wg.Button(
294 wg.clickables["createVerify"].SetClick(
295 func() {
296 wg.createVerifying = false
297 },
298 ),
299 ).Text("back").Fn
300 if wg.createWords == wg.createMatch {
301 verifyState = wg.Inset(0.25, wg.Body1("match").Color("Success").Fn).Fn
302 }
303 return wg.Flex().
304 Rigid(
305 verifyState,
306 ).
307 Rigid(
308 wg.inputs["walletWords"].Fn,
309 ).
310 Fn
311 }
312 return nil
313 }
314
315 func (wg *WalletGUI) cfwRestore() (w l.Widget) {
316 w = func(l.Context) l.Dimensions {
317 return l.Dimensions{}
318 }
319 if wg.restoring {
320 // restoreState := wg.Button(
321 // wg.clickables["createRestore"].SetClick(
322 // func() {
323 // wg.restoring = false
324 // },
325 // ),
326 // ).Text("back").Fn
327 if wg.createWords == wg.createMatch {
328 w = wg.Flex().AlignMiddle().
329 Rigid(
330 wg.Inset(0.25, wg.H5("valid").Color("Success").Fn).Fn,
331 ).Fn
332 }
333 return wg.Flex().
334 Rigid(
335 w,
336 ).
337 Rigid(
338 wg.inputs["walletRestore"].Fn,
339 ).
340 Fn
341 }
342 return
343 }
344
345 func (wg *WalletGUI) cwfTestnetSettings() (out l.Widget) {
346 return wg.Flex().
347 Rigid(
348 func(gtx l.Context) l.Dimensions {
349 return wg.CheckBox(
350 wg.bools["testnet"].SetOnChange(
351 func(b bool) {
352 if !b {
353 wg.bools["solo"].Value(false)
354 wg.bools["lan"].Value(false)
355 // wg.cx.Config.MulticastPass.Set("pa55word")
356 wg.cx.Config.Solo.F()
357 wg.cx.Config.LAN.F()
358 wg.ShuffleSeed()
359 wg.createVerifying = false
360 wg.inputs["walletWords"].SetText("")
361 wg.Invalidate()
362 }
363 wg.createWalletTestnetToggle(b)
364 },
365 ),
366 ).
367 IconColor("Primary").
368 TextColor("DocText").
369 Text("Use Testnet").
370 Fn(gtx)
371 },
372 ).
373 Rigid(
374 func(gtx l.Context) l.Dimensions {
375 checkColor, textColor := "Primary", "DocText"
376 if !wg.bools["testnet"].GetValue() {
377 gtx = gtx.Disabled()
378 checkColor, textColor = "scrim", "scrim"
379 }
380 return wg.CheckBox(
381 wg.bools["lan"].SetOnChange(
382 func(b bool) {
383 D.Ln("lan now set to", b)
384 wg.cx.Config.LAN.Set(b)
385 if b && wg.cx.Config.Solo.True() {
386 wg.cx.Config.Solo.F()
387 wg.cx.Config.DisableDNSSeed.T()
388 wg.cx.Config.AutoListen.F()
389 wg.bools["solo"].Value(false)
390 // wg.cx.Config.MulticastPass.Set("pa55word")
391 wg.Invalidate()
392 } else {
393 wg.cx.Config.Solo.F()
394 wg.cx.Config.DisableDNSSeed.F()
395 // wg.cx.Config.MulticastPass.Set("pa55word")
396 wg.cx.Config.AutoListen.T()
397 }
398 _ = wg.cx.Config.WriteToFile(wg.cx.Config.ConfigFile.V())
399 },
400 ),
401 ).
402 IconColor(checkColor).
403 TextColor(textColor).
404 Text("LAN only").
405 Fn(gtx)
406 },
407 ).
408 Rigid(
409 func(gtx l.Context) l.Dimensions {
410 checkColor, textColor := "Primary", "DocText"
411 if !wg.bools["testnet"].GetValue() {
412 gtx = gtx.Disabled()
413 checkColor, textColor = "scrim", "scrim"
414 }
415 return wg.CheckBox(
416 wg.bools["solo"].SetOnChange(
417 func(b bool) {
418 D.Ln("solo now set to", b)
419 wg.cx.Config.Solo.Set(b)
420 if b && wg.cx.Config.LAN.True() {
421 wg.cx.Config.LAN.F()
422 wg.cx.Config.DisableDNSSeed.T()
423 wg.cx.Config.AutoListen.F()
424 // wg.cx.Config.MulticastPass.Set("pa55word")
425 wg.bools["lan"].Value(false)
426 wg.Invalidate()
427 } else {
428 wg.cx.Config.LAN.F()
429 wg.cx.Config.DisableDNSSeed.F()
430 // wg.cx.Config.MulticastPass.Set("pa55word")
431 wg.cx.Config.AutoListen.T()
432 }
433 _ = wg.cx.Config.WriteToFile(wg.cx.Config.ConfigFile.V())
434 },
435 ),
436 ).
437 IconColor(checkColor).
438 TextColor(textColor).
439 Text("Solo (mine without peers)").
440 Fn(gtx)
441 },
442 ).
443 Fn
444 }
445
446 func (wg *WalletGUI) cwfConfirmation() (out l.Widget) {
447 return wg.CheckBox(
448 wg.bools["ihaveread"].SetOnChange(
449 func(b bool) {
450 D.Ln("confirmed read", b)
451 // if the password has been entered, we need to copy it to the variable
452 if wg.createWalletPasswordsMatch() {
453 wg.cx.Config.WalletPass.Set(wg.passwords["confirmPassEditor"].GetPassword())
454 }
455 },
456 ),
457 ).
458 IconColor("Primary").
459 TextColor("DocText").
460 Text(
461 "I have stored the seed and password safely " +
462 "and understand it cannot be recovered",
463 ).
464 Fn
465 }
466
467 func (wg *WalletGUI) createWalletFormWidgets() (out []l.Widget) {
468 out = append(
469 out,
470 wg.cwfLogoHeader(),
471 wg.cwfHeader(),
472 wg.cwfPasswordHeader(),
473 wg.passwords["passEditor"].
474 Fn,
475 wg.passwords["confirmPassEditor"].
476 Fn,
477 wg.cwfSeedHeader(),
478 )
479 if wg.createVerifying {
480 out = append(
481 out, wg.cfwWordsVerify(),
482 )
483 } else if wg.restoring {
484 out = append(out, wg.cfwRestore())
485 } else {
486 out = append(out, wg.cfwWords())
487 }
488 out = append(
489 out,
490 wg.cwfTestnetSettings(),
491 wg.cwfConfirmation(),
492 )
493 return
494 }
495