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