package gui import ( "fmt" "io/ioutil" "os" "os/exec" "path/filepath" uberatomic "go.uber.org/atomic" "golang.org/x/exp/shiny/materialdesign/icons" l "github.com/p9c/p9/pkg/gel/gio/layout" "github.com/p9c/p9/pkg/gel/gio/text" "github.com/p9c/p9/pkg/gel" "github.com/p9c/p9/cmd/gui/cfg" "github.com/p9c/p9/pkg/p9icons" ) func (wg *WalletGUI) GetAppWidget() (a *gel.App) { a = wg.App(wg.Window.Width, uberatomic.NewString("home"), Break1). SetMainDirection(l.W). SetLogo(&p9icons.ParallelCoin). SetAppTitleText("Parallelcoin Wallet") wg.MainApp = a wg.config = cfg.New(wg.Window, wg.quit) wg.configs = wg.config.Config() a.Pages( map[string]l.Widget{ "home": wg.Page( "home", gel.Widgets{ // p9.WidgetSize{Widget: p9.EmptyMaxHeight()}, gel.WidgetSize{Widget: wg.OverviewPage()}, }, ), "send": wg.Page( "send", gel.Widgets{ // p9.WidgetSize{Widget: p9.EmptyMaxHeight()}, gel.WidgetSize{Widget: wg.SendPage.Fn}, }, ), "receive": wg.Page( "receive", gel.Widgets{ // p9.WidgetSize{Widget: p9.EmptyMaxHeight()}, gel.WidgetSize{Widget: wg.ReceivePage.Fn}, }, ), "history": wg.Page( "history", gel.Widgets{ // p9.WidgetSize{Widget: p9.EmptyMaxHeight()}, gel.WidgetSize{Widget: wg.HistoryPage()}, }, ), "settings": wg.Page( "settings", gel.Widgets{ // p9.WidgetSize{Widget: p9.EmptyMaxHeight()}, gel.WidgetSize{ Widget: func(gtx l.Context) l.Dimensions { return wg.configs.Widget(wg.config)(gtx) }, }, }, ), "console": wg.Page( "console", gel.Widgets{ // p9.WidgetSize{Widget: p9.EmptyMaxHeight()}, gel.WidgetSize{Widget: wg.console.Fn}, }, ), "help": wg.Page( "help", gel.Widgets{ gel.WidgetSize{Widget: wg.HelpPage()}, }, ), "log": wg.Page( "log", gel.Widgets{ gel.WidgetSize{Widget: a.Placeholder("log")}, }, ), "quit": wg.Page( "quit", gel.Widgets{ gel.WidgetSize{ Widget: func(gtx l.Context) l.Dimensions { return wg.VFlex(). SpaceEvenly(). AlignMiddle(). Rigid( wg.H4("are you sure?").Color(wg.MainApp.BodyColorGet()).Alignment(text.Middle).Fn, ). Rigid( wg.Flex(). // SpaceEvenly(). Flexed(0.5, gel.EmptyMaxWidth()). Rigid( wg.Button( wg.clickables["quit"].SetClick( func() { // interrupt.Request() wg.gracefulShutdown() // close(wg.quit) }, ), ).Color("Light").TextScale(5).Text( "yes!!!", ).Fn, ). Flexed(0.5, gel.EmptyMaxWidth()). Fn, ). Fn(gtx) }, }, }, ), // "goroutines": wg.Page( // "log", p9.Widgets{ // // p9.WidgetSize{Widget: p9.EmptyMaxHeight()}, // // p9.WidgetSize{ // Widget: func(gtx l.Context) l.Dimensions { // le := func(gtx l.Context, index int) l.Dimensions { // return wg.State.goroutines[index](gtx) // } // return func(gtx l.Context) l.Dimensions { // return wg.ButtonInset( // 0.25, // wg.Fill( // "DocBg", // wg.lists["recent"]. // Vertical(). // // Background("DocBg").Color("DocText").Active("Primary"). // Length(len(wg.State.goroutines)). // ListElement(le). // Fn, // ).Fn, // ). // Fn(gtx) // }(gtx) // // wg.NodeRunCommandChan <- "stop" // // consume.Kill(wg.Worker) // // consume.Kill(wg.cx.StateCfg.Miner) // // close(wg.cx.NodeKill) // // close(wg.cx.KillAll) // // time.Sleep(time.Second*3) // // interrupt.Request() // // os.Exit(0) // // return l.Dimensions{} // }, // }, // }, // ), "mining": wg.Page( "mining", gel.Widgets{ gel.WidgetSize{ Widget: a.Placeholder("mining"), }, }, ), "explorer": wg.Page( "explorer", gel.Widgets{ gel.WidgetSize{ Widget: a.Placeholder("explorer"), }, }, ), }, ) a.SideBar( []l.Widget{ // wg.SideBarButton(" ", " ", 11), wg.SideBarButton("home", "home", 0), wg.SideBarButton("send", "send", 1), wg.SideBarButton("receive", "receive", 2), wg.SideBarButton("history", "history", 3), // wg.SideBarButton("explorer", "explorer", 6), // wg.SideBarButton("mining", "mining", 7), wg.SideBarButton("console", "console", 9), wg.SideBarButton("settings", "settings", 5), // wg.SideBarButton("log", "log", 10), wg.SideBarButton("help", "help", 8), // wg.SideBarButton(" ", " ", 11), // wg.SideBarButton("quit", "quit", 11), }, ) a.ButtonBar( []l.Widget{ // gel.EmptyMaxWidth(), // wg.PageTopBarButton( // "goroutines", 0, &icons.ActionBugReport, func(name string) { // wg.App.ActivePage(name) // }, a, "", // ), wg.PageTopBarButton( "help", 1, &icons.ActionHelp, func(name string) { wg.MainApp.ActivePage(name) }, a, "", ), wg.PageTopBarButton( "home", 4, &icons.ActionLockOpen, func(name string) { wg.unlockPassword.Wipe() wg.unlockPassword.Focus() wg.WalletWatcher.Q() // if wg.WalletClient != nil { // wg.WalletClient.Disconnect() // wg.WalletClient = nil // } // wg.wallet.Stop() // wg.node.Stop() wg.State.SetActivePage("home") wg.unlockPage.ActivePage("home") wg.stateLoaded.Store(false) wg.ready.Store(false) }, a, "green", ), // wg.Flex().Rigid(wg.Inset(0.5, gel.EmptySpace(0, 0)).Fn).Fn, // wg.PageTopBarButton( // "quit", 3, &icons.ActionExitToApp, func(name string) { // wg.MainApp.ActivePage(name) // }, a, "", // ), }, ) a.StatusBar( []l.Widget{ // func(gtx l.Context) l.Dimensions { return wg.RunStatusPanel(gtx) }, // wg.Inset(0.5, gel.EmptySpace(0, 0)).Fn, // wg.Inset(0.5, gel.EmptySpace(0, 0)).Fn, wg.RunStatusPanel, }, []l.Widget{ // gel.EmptyMaxWidth(), wg.StatusBarButton( "console", 3, &p9icons.Terminal, func(name string) { wg.MainApp.ActivePage(name) }, a, ), wg.StatusBarButton( "log", 4, &icons.ActionList, func(name string) { D.Ln("click on button", name) if wg.MainApp.MenuOpen { wg.MainApp.MenuOpen = false } wg.MainApp.ActivePage(name) }, a, ), wg.StatusBarButton( "settings", 5, &icons.ActionSettings, func(name string) { D.Ln("click on button", name) if wg.MainApp.MenuOpen { wg.MainApp.MenuOpen = false } wg.MainApp.ActivePage(name) }, a, ), // wg.Inset(0.5, gel.EmptySpace(0, 0)).Fn, }, ) // a.PushOverlay(wg.toasts.DrawToasts()) // a.PushOverlay(wg.dialog.DrawDialog()) return } func (wg *WalletGUI) Page(title string, widget gel.Widgets) func(gtx l.Context) l.Dimensions { return func(gtx l.Context) l.Dimensions { return wg.VFlex(). // SpaceEvenly(). Rigid( wg.Responsive( wg.Size.Load(), gel.Widgets{ // p9.WidgetSize{ // Widget: a.ButtonInset(0.25, a.H5(title).Color(wg.App.BodyColorGet()).Fn).Fn, // }, gel.WidgetSize{ // Size: 800, Widget: gel.EmptySpace(0, 0), // a.ButtonInset(0.25, a.Caption(title).Color(wg.BodyColorGet()).Fn).Fn, }, }, ).Fn, ). Flexed( 1, wg.Inset( 0.25, wg.Responsive(wg.Size.Load(), widget).Fn, ).Fn, ).Fn(gtx) } } func (wg *WalletGUI) SideBarButton(title, page string, index int) func(gtx l.Context) l.Dimensions { return func(gtx l.Context) l.Dimensions { var scale float32 scale = gel.Scales["H6"] var color string background := "Transparent" color = "DocText" var ins float32 = 0.5 // var hl = false if wg.MainApp.ActivePageGet() == page || wg.MainApp.PreRendering { background = "PanelBg" scale = gel.Scales["H6"] color = "DocText" // ins = 0.5 // hl = true } if title == " " { scale = gel.Scales["H6"] / 2 } max := int(wg.MainApp.SideBarSize) if max > 0 { gtx.Constraints.Max.X = max gtx.Constraints.Min.X = max } // D.Ln("sideMAXXXXXX!!", max) return wg.Direction().E().Embed( wg.ButtonLayout(wg.sidebarButtons[index]). CornerRadius(scale).Corners(0). Background(background). Embed( wg.Inset( ins, func(gtx l.Context) l.Dimensions { return wg.H5(title). Color(color). Alignment(text.End). Fn(gtx) }, ).Fn, ). SetClick( func() { if wg.MainApp.MenuOpen { wg.MainApp.MenuOpen = false } wg.MainApp.ActivePage(page) }, ). Fn, ). Fn(gtx) } } func (wg *WalletGUI) PageTopBarButton( name string, index int, ico *[]byte, onClick func(string), app *gel.App, highlightColor string, ) func(gtx l.Context) l.Dimensions { return func(gtx l.Context) l.Dimensions { background := "Transparent" // background := app.TitleBarBackgroundGet() color := app.MenuColorGet() if app.ActivePageGet() == name { color = "PanelText" // background = "scrim" background = "PanelBg" } // if name == "home" { // background = "scrim" // } if highlightColor != "" { color = highlightColor } ic := wg.Icon(). Scale(gel.Scales["H5"]). Color(color). Src(ico). Fn return wg.Flex().Rigid( // wg.ButtonInset(0.25, wg.ButtonLayout(wg.buttonBarButtons[index]). CornerRadius(0). Embed( wg.Inset( 0.375, ic, ).Fn, ). Background(background). SetClick(func() { onClick(name) }). Fn, // ).Fn, ).Fn(gtx) } } func (wg *WalletGUI) StatusBarButton( name string, index int, ico *[]byte, onClick func(string), app *gel.App, ) func(gtx l.Context) l.Dimensions { return func(gtx l.Context) l.Dimensions { background := app.StatusBarBackgroundGet() color := app.StatusBarColorGet() if app.ActivePageGet() == name { // background, color = color, background background = "PanelBg" // color = "Danger" } ic := wg.Icon(). Scale(gel.Scales["H5"]). Color(color). Src(ico). Fn return wg.Flex(). Rigid( wg.ButtonLayout(wg.statusBarButtons[index]). CornerRadius(0). Embed( wg.Inset(0.25, ic).Fn, ). Background(background). SetClick(func() { onClick(name) }). Fn, ).Fn(gtx) } } func (wg *WalletGUI) SetNodeRunState(b bool) { go func() { D.Ln("node run state is now", b) if b { wg.node.Start() } else { wg.node.Stop() } }() } func (wg *WalletGUI) SetWalletRunState(b bool) { go func() { D.Ln("node run state is now", b) if b { wg.wallet.Start() } else { wg.wallet.Stop() } }() } func (wg *WalletGUI) RunStatusPanel(gtx l.Context) l.Dimensions { return func(gtx l.Context) l.Dimensions { t, f := &p9icons.Link, &p9icons.LinkOff var runningIcon *[]byte if wg.node.Running() { runningIcon = t } else { runningIcon = f } miningIcon := &p9icons.Mine if !wg.miner.Running() { miningIcon = &p9icons.NoMine } controllerIcon := &icons.NotificationSyncDisabled if wg.cx.Config.Controller.True() { controllerIcon = &icons.NotificationSync } discoverColor := "DocText" discoverIcon := &icons.DeviceWiFiTethering if wg.cx.Config.Discovery.False() { discoverIcon = &icons.CommunicationPortableWiFiOff discoverColor = "scrim" } clr := "scrim" if wg.cx.Config.Controller.True() { clr = "DocText" } clr2 := "DocText" if wg.cx.Config.GenThreads.V() == 0 { clr2 = "scrim" } // background := wg.App.StatusBarBackgroundGet() color := wg.MainApp.StatusBarColorGet() ic := wg.Icon(). Scale(gel.Scales["H5"]). Color(color). Src(&icons.NavigationRefresh). Fn return wg.Flex().AlignMiddle(). Rigid( wg.ButtonLayout(wg.statusBarButtons[0]). CornerRadius(0). Embed( wg.Inset( 0.25, wg.Icon(). Scale(gel.Scales["H5"]). Color("DocText"). Src(runningIcon). Fn, ).Fn, ). Background(wg.MainApp.StatusBarBackgroundGet()). SetClick( func() { go func() { D.Ln("clicked node run control button", wg.node.Running()) // wg.toggleNode() wg.unlockPassword.Wipe() wg.unlockPassword.Focus() if wg.node.Running() { if wg.wallet.Running() { wg.WalletWatcher.Q() } wg.node.Stop() wg.ready.Store(false) wg.stateLoaded.Store(false) wg.State.SetActivePage("home") } else { wg.node.Start() // wg.ready.Store(true) // wg.stateLoaded.Store(true) } }() }, ). Fn, ). Rigid( wg.Inset( 0.33, wg.Body1(fmt.Sprintf("%d", wg.State.bestBlockHeight.Load())). Font("go regular").TextScale(gel.Scales["Caption"]). Color("DocText"). Fn, ).Fn, ). Rigid( wg.ButtonLayout(wg.statusBarButtons[6]). CornerRadius(0). Embed( wg.Inset( 0.25, wg.Icon(). Scale(gel.Scales["H5"]). Color(discoverColor). Src(discoverIcon). Fn, ).Fn, ). Background(wg.MainApp.StatusBarBackgroundGet()). SetClick( func() { go func() { wg.cx.Config.Discovery.Flip() _ = wg.cx.Config.WriteToFile(wg.cx.Config.ConfigFile.V()) I.Ln("discover enabled:", wg.cx.Config.Discovery.True()) }() }, ). Fn, ). Rigid( wg.Inset( 0.33, wg.Caption(fmt.Sprintf("%d LAN %d", len(wg.otherNodes), wg.peerCount.Load())). Font("go regular"). Color("DocText"). Fn, ).Fn, ). Rigid( wg.ButtonLayout(wg.statusBarButtons[7]). CornerRadius(0). Embed( wg. Inset( 0.25, wg. Icon(). Scale(gel.Scales["H5"]). Color(clr). Src(controllerIcon).Fn, ).Fn, ). Background(wg.MainApp.StatusBarBackgroundGet()). SetClick( func() { if wg.ChainClient != nil && !wg.ChainClient.Disconnected() { wg.cx.Config.Controller.Flip() I.Ln("controller running:", wg.cx.Config.Controller.True()) var e error if e = wg.ChainClient.SetGenerate( wg.cx.Config.Controller.True(), wg.cx.Config.GenThreads.V(), ); !E.Chk(e) { } } // // wg.toggleMiner() // go func() { // if wg.miner.Running() { // *wg.cx.Config.Generate = false // wg.miner.Stop() // } else { // wg.miner.Start() // *wg.cx.Config.Generate = true // } // save.Save(wg.cx.Config) // }() }, ). Fn, ). Rigid( wg.ButtonLayout(wg.statusBarButtons[1]). CornerRadius(0). Embed( wg.Inset( 0.25, wg. Icon(). Scale(gel.Scales["H5"]). Color(clr2). Src(miningIcon).Fn, ).Fn, ). Background(wg.MainApp.StatusBarBackgroundGet()). SetClick( func() { // wg.toggleMiner() go func() { if wg.cx.Config.GenThreads.V() != 0 { if wg.miner.Running() { wg.cx.Config.Generate.F() wg.miner.Stop() } else { wg.miner.Start() wg.cx.Config.Generate.T() } _ = wg.cx.Config.WriteToFile(wg.cx.Config.ConfigFile.V()) } }() }, ). Fn, ). Rigid( func(gtx l.Context) l.Dimensions { return wg.incdecs["generatethreads"]. // Color("DocText"). // Background(wg.MainApp.StatusBarBackgroundGet()). Fn(gtx) }, ). Rigid( func(gtx l.Context) l.Dimensions { if !wg.wallet.Running() { return l.Dimensions{} } return wg.Flex(). Rigid( wg.ButtonLayout(wg.statusBarButtons[2]). CornerRadius(0). Embed( wg.Inset(0.25, ic).Fn, ). Background(wg.MainApp.StatusBarBackgroundGet()). SetClick( func() { D.Ln("clicked reset wallet button") go func() { var e error wasRunning := wg.wallet.Running() D.Ln("was running", wasRunning) if wasRunning { wg.wallet.Stop() } args := []string{ os.Args[0], "DD"+ wg.cx.Config.DataDir.V(), "pipelog", "walletpass"+ wg.cx.Config.WalletPass.V(), "wallet", "drophistory", } runner := exec.Command(args[0], args[1:]...) runner.Stderr = os.Stderr runner.Stdout = os.Stderr if e = wg.writeWalletCookie(); E.Chk(e) { } if e = runner.Run(); E.Chk(e) { } if wasRunning { wg.wallet.Start() } }() }, ). Fn, ).Fn(gtx) }, ). Fn(gtx) }(gtx) } func (wg *WalletGUI) writeWalletCookie() (e error) { // for security with apps launching the wallet, the public password can be set with a file that is deleted after walletPassPath := filepath.Join(wg.cx.Config.DataDir.V(), wg.cx.ActiveNet.Name, "wp.txt") D.Ln("runner", walletPassPath) b := wg.cx.Config.WalletPass.Bytes() if e = ioutil.WriteFile(walletPassPath, b, 0700); E.Chk(e) { } D.Ln("created password cookie") return } // // func (wg *WalletGUI) toggleNode() { // if wg.node.Running() { // wg.node.Stop() // *wg.cx.Config.NodeOff = true // } else { // wg.node.Start() // *wg.cx.Config.NodeOff = false // } // save.Save(wg.cx.Config) // } // // func (wg *WalletGUI) startNode() { // if !wg.node.Running() { // wg.node.Start() // } // D.Ln("startNode") // } // // func (wg *WalletGUI) stopNode() { // if wg.wallet.Running() { // wg.stopWallet() // wg.unlockPassword.Wipe() // // wg.walletLocked.Store(true) // } // if wg.node.Running() { // wg.node.Stop() // } // D.Ln("stopNode") // } // // func (wg *WalletGUI) toggleMiner() { // if wg.miner.Running() { // wg.miner.Stop() // *wg.cx.Config.Generate = false // } // if !wg.miner.Running() && *wg.cx.Config.GenThreads > 0 { // wg.miner.Start() // *wg.cx.Config.Generate = true // } // save.Save(wg.cx.Config) // } // // func (wg *WalletGUI) startMiner() { // if *wg.cx.Config.GenThreads == 0 && wg.miner.Running() { // wg.stopMiner() // D.Ln("was zero threads") // } else { // wg.miner.Start() // D.Ln("startMiner") // } // } // // func (wg *WalletGUI) stopMiner() { // if wg.miner.Running() { // wg.miner.Stop() // } // D.Ln("stopMiner") // } // // func (wg *WalletGUI) toggleWallet() { // if wg.wallet.Running() { // wg.stopWallet() // *wg.cx.Config.WalletOff = true // } else { // wg.startWallet() // *wg.cx.Config.WalletOff = false // } // save.Save(wg.cx.Config) // } // // func (wg *WalletGUI) startWallet() { // if !wg.node.Running() { // wg.startNode() // } // if !wg.wallet.Running() { // wg.wallet.Start() // wg.unlockPassword.Wipe() // // wg.walletLocked.Store(false) // } // D.Ln("startWallet") // } // // func (wg *WalletGUI) stopWallet() { // if wg.wallet.Running() { // wg.wallet.Stop() // // wg.unlockPassword.Wipe() // // wg.walletLocked.Store(true) // } // wg.unlockPassword.Wipe() // D.Ln("stopWallet") // }