diff --git a/cmd/gtk/main_window.go b/cmd/gtk/main_window.go index ab0b689c7..b3322ee82 100644 --- a/cmd/gtk/main_window.go +++ b/cmd/gtk/main_window.go @@ -7,7 +7,6 @@ import ( "github.com/gotk3/gotk3/gtk" "github.com/pactus-project/pactus/crypto" - "github.com/pactus-project/pactus/util" ) //go:embed assets/ui/main_window.ui @@ -84,19 +83,19 @@ func (mw *mainWindow) OnTransactionTransfer() { } func (mw *mainWindow) onMenuItemActivateWebsite(_ *gtk.MenuItem) { - if err := util.OpenURLInBrowser("https://pactus.org/"); err != nil { + if err := openURLInBrowser("https://pactus.org/"); err != nil { fatalErrorCheck(err) } } func (mw *mainWindow) onMenuItemActivateExplorer(_ *gtk.MenuItem) { - if err := util.OpenURLInBrowser("https://pactusscan.com/"); err != nil { + if err := openURLInBrowser("https://pactusscan.com/"); err != nil { fatalErrorCheck(err) } } func (mw *mainWindow) onMenuItemActivateLearn(_ *gtk.MenuItem) { - if err := util.OpenURLInBrowser("https://pactus.org/learn/"); err != nil { + if err := openURLInBrowser("https://pactus.org/learn/"); err != nil { fatalErrorCheck(err) } } diff --git a/cmd/gtk/startup_assistant.go b/cmd/gtk/startup_assistant.go index ae89518f4..4c34e383e 100644 --- a/cmd/gtk/startup_assistant.go +++ b/cmd/gtk/startup_assistant.go @@ -15,6 +15,9 @@ import ( "github.com/pactus-project/pactus/wallet" ) +type assistantFunc func(assistant *gtk.Assistant, content gtk.IWidget, name, + title, subject, desc string) *gtk.Widget + func setMargin(widget gtk.IWidget, top, bottom, start, end int) { widget.ToWidget().SetMarginTop(top) widget.ToWidget().SetMarginBottom(bottom) @@ -24,8 +27,202 @@ func setMargin(widget gtk.IWidget, top, bottom, start, end int) { func startupAssistant(workingDir string, chain genesis.ChainType) bool { successful := false - createPage := func(assistant *gtk.Assistant, content gtk.IWidget, name, - title, subject, desc string) *gtk.Widget { + assistant, err := gtk.AssistantNew() + fatalErrorCheck(err) + + assistant.SetDefaultSize(600, 400) + assistant.SetTitle("Pactus - Init Wizard") + + assistFunc := pageAssistant() + + // --- page_mode + mode, restoreRadio, pageModeName := pageMode(assistant, assistFunc) + + // --- page_seed_generate + seedGenerate, textViewSeed, pageSeedGenerateName := pageSeedGenerate(assistant, assistFunc) + + // --- page_seed_confirm + seedConfirm, pageSeedConfirmName := pageSeedConfirm(assistant, assistFunc, textViewSeed) + + // -- page_seed_restore + seedRestore, textViewRestoreSeed, pageSeedRestoreName := pageSeedRestore(assistant, assistFunc) + + // --- page_password + password, entryPassword, pagePasswordName := pagePassword(assistant, assistFunc) + + // --- page_num_validators + numValidators, lsNumValidators, comboNumValidators, pageNumValidatorsName := pageNumValidators(assistant, assistFunc) + + // --- page_final + final, textViewNodeInfo, pageFinalName := pageFinal(assistant, assistFunc) + + assistant.Connect("cancel", func() { + assistant.Close() + assistant.Destroy() + gtk.MainQuit() + }) + assistant.Connect("close", func() { + assistant.Close() + assistant.Destroy() + gtk.MainQuit() + }) + + assistant.SetPageType(mode, gtk.ASSISTANT_PAGE_INTRO) // page 0 + assistant.SetPageType(seedGenerate, gtk.ASSISTANT_PAGE_CONTENT) // page 1 + assistant.SetPageType(seedConfirm, gtk.ASSISTANT_PAGE_CONTENT) // page 2 + assistant.SetPageType(seedRestore, gtk.ASSISTANT_PAGE_CONTENT) // page 3 + assistant.SetPageType(password, gtk.ASSISTANT_PAGE_CONTENT) // page 4 + assistant.SetPageType(numValidators, gtk.ASSISTANT_PAGE_CONTENT) // page 5 + assistant.SetPageType(final, gtk.ASSISTANT_PAGE_SUMMARY) // page 6 + + mnemonic := "" + prevPageIndex := -1 + prevPageAdjust := 0 + assistant.Connect("prepare", func(assistant *gtk.Assistant, page *gtk.Widget) { + isRestoreMode := restoreRadio.GetActive() + curPageName, err := page.GetName() + curPageIndex := assistant.GetCurrentPage() + fatalErrorCheck(err) + + isForward := true + if curPageIndex > 0 && curPageIndex < prevPageIndex { + isForward = false + } + + log.Printf("%v (restore: %v, prev: %v, cur: %v)\n", + curPageName, isRestoreMode, prevPageIndex, curPageIndex) + switch curPageName { + case pageModeName: + { + assistantPageComplete(assistant, mode, true) + } + + case pageSeedGenerateName: + { + if isRestoreMode { + if isForward { + // forward + log.Printf("jumping forward from seedGenerate page") + assistant.NextPage() + prevPageAdjust = 1 + } else { + // backward + log.Printf("jumping backward from seedGenerate page") + assistant.PreviousPage() + prevPageAdjust = -1 + } + assistantPageComplete(assistant, seedGenerate, false) + } else { + mnemonic = wallet.GenerateMnemonic(128) + setTextViewContent(textViewSeed, mnemonic) + assistantPageComplete(assistant, seedGenerate, true) + } + } + case pageSeedConfirmName: + { + if isRestoreMode { + if isForward { + // forward + log.Printf("jumping forward from seedConfirm page") + assistant.NextPage() + prevPageAdjust = 1 + } else { + // backward + log.Printf("jumping backward from seedConfirm page") + assistant.PreviousPage() + prevPageAdjust = -1 + } + assistantPageComplete(assistant, seedConfirm, false) + } else { + assistantPageComplete(assistant, seedConfirm, false) + } + } + case pageSeedRestoreName: + { + if !isRestoreMode { + if isForward { + // forward + log.Printf("jumping forward from seedRestore page") + assistant.NextPage() + prevPageAdjust = 1 + } else { + // backward + log.Printf("jumping backward from seedRestore page") + assistant.PreviousPage() + prevPageAdjust = -1 + } + assistantPageComplete(assistant, seedConfirm, false) + } else { + assistantPageComplete(assistant, seedRestore, true) + } + } + case pagePasswordName: + { + if isRestoreMode { + mnemonic = getTextViewContent(textViewRestoreSeed) + + if err := wallet.CheckMnemonic(mnemonic); err != nil { + showErrorDialog(assistant, "mnemonic is invalid") + assistant.PreviousPage() + } + } + assistantPageComplete(assistant, password, true) + } + case pageNumValidatorsName: + { + assistantPageComplete(assistant, numValidators, true) + } + + case pageFinalName: + { + iter, err := comboNumValidators.GetActiveIter() + fatalErrorCheck(err) + + val, err := lsNumValidators.GetValue(iter, 0) + fatalErrorCheck(err) + + valueInterface, err := val.GoValue() + fatalErrorCheck(err) + + numValidators := valueInterface.(int) + + fmt.Println("number of validators:", numValidators) + + walletPassword, err := entryPassword.GetText() + fatalErrorCheck(err) + + validatorAddrs, rewardAddrs, err := cmd.CreateNode(numValidators, chain, workingDir, mnemonic, walletPassword) + fatalErrorCheck(err) + + // Done! showing the node information + successful = true + nodeInfo := fmt.Sprintf("Working directory: %s\n", workingDir) + nodeInfo += fmt.Sprintf("Network: %s\n", chain.String()) + nodeInfo += "\nValidator addresses:\n" + for i, addr := range validatorAddrs { + nodeInfo += fmt.Sprintf("%v- %s\n", i+1, addr) + } + + nodeInfo += "\nReward addresses:\n" + for i, addr := range rewardAddrs { + nodeInfo += fmt.Sprintf("%v- %s\n", i+1, addr) + } + + setTextViewContent(textViewNodeInfo, nodeInfo) + } + } + prevPageIndex = curPageIndex + prevPageAdjust + }) + + assistant.SetModal(true) + assistant.ShowAll() + + gtk.Main() + return successful +} + +func pageAssistant() assistantFunc { + return func(assistant *gtk.Assistant, content gtk.IWidget, name, title, subject, desc string) *gtk.Widget { page, err := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 20) fatalErrorCheck(err) @@ -53,58 +250,47 @@ func startupAssistant(workingDir string, chain genesis.ChainType) bool { box.Add(frame) box.Add(labelDesc) page.Add(box) - page.SetName(name) assistant.AppendPage(page) assistant.SetPageTitle(page, title) return page.ToWidget() } +} - assistant, err := gtk.AssistantNew() - fatalErrorCheck(err) - - assistant.SetDefaultSize(600, 400) - assistant.SetTitle("Pactus - Init Wizard") - - var pageMode *gtk.Widget - var pagePassword *gtk.Widget - var pageSeed *gtk.Widget - var pageSeedConfirm *gtk.Widget - var pageNumValidators *gtk.Widget - var pageFinal *gtk.Widget - - // --- PageMode +func pageMode(assistant *gtk.Assistant, assistFunc assistantFunc) (*gtk.Widget, *gtk.RadioButton, string) { + var mode *gtk.Widget newWalletRadio, err := gtk.RadioButtonNewWithLabel(nil, "Create a new wallet from the scratch") fatalErrorCheck(err) - recoverWalletRadio, err := gtk.RadioButtonNewWithLabelFromWidget(newWalletRadio, + restoreWalletRadio, err := gtk.RadioButtonNewWithLabelFromWidget(newWalletRadio, "Restore a wallet from the seed phrase") fatalErrorCheck(err) - recoverWalletRadio.SetSensitive(false) - radioBox, err := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) fatalErrorCheck(err) radioBox.Add(newWalletRadio) setMargin(newWalletRadio, 6, 6, 6, 6) - radioBox.Add(recoverWalletRadio) - setMargin(recoverWalletRadio, 6, 6, 6, 6) + radioBox.Add(restoreWalletRadio) + setMargin(restoreWalletRadio, 6, 6, 6, 6) pageModeName := "page_mode" pageModeTitle := "Initialize mode" pageModeSubject := "How to create your wallet?" pageModeDesc := "If you are running the node for the first time, choose the first option." - pageMode = createPage( + mode = assistFunc( assistant, radioBox, pageModeName, pageModeTitle, pageModeSubject, pageModeDesc) + return mode, restoreWalletRadio, pageModeName +} - // --- pageSeed +func pageSeedGenerate(assistant *gtk.Assistant, assistFunc assistantFunc) (*gtk.Widget, *gtk.TextView, string) { + var pageWidget *gtk.Widget textViewSeed, err := gtk.TextViewNew() fatalErrorCheck(err) @@ -114,7 +300,7 @@ func startupAssistant(workingDir string, chain genesis.ChainType) bool { textViewSeed.SetMonospace(true) textViewSeed.SetSizeRequest(0, 80) - pageSeedName := "page_seed" + pageSeedName := "page_seed_generate" pageSeedTitle := "Wallet seed" pageSeedSubject := "Your wallet generation seed is:" pageSeedDesc := `Please write these 12 words on paper. @@ -124,15 +310,45 @@ This seed will allow you to recover your wallet in case of computer failure. - Never type it on a website. - Do not store it electronically.` - pageSeed = createPage( + pageWidget = assistFunc( assistant, textViewSeed, pageSeedName, pageSeedTitle, pageSeedSubject, pageSeedDesc) + return pageWidget, textViewSeed, pageSeedName +} + +func pageSeedRestore(assistant *gtk.Assistant, assistFunc assistantFunc) (*gtk.Widget, *gtk.TextView, string) { + var pageWidget *gtk.Widget + textViewRestoreSeed, err := gtk.TextViewNew() + fatalErrorCheck(err) + + setMargin(textViewRestoreSeed, 6, 6, 6, 6) + textViewRestoreSeed.SetWrapMode(gtk.WRAP_WORD) + textViewRestoreSeed.SetEditable(true) + textViewRestoreSeed.SetMonospace(true) + textViewRestoreSeed.SetSizeRequest(0, 80) + + pageSeedName := "page_seed_restore" + pageSeedTitle := "Wallet seed restore" + pageSeedSubject := "Enter your wallet seed:" + pageSeedDesc := "Please enter your 12 words mnemonics backup to restore your wallet." + + pageWidget = assistFunc( + assistant, + textViewRestoreSeed, + pageSeedName, + pageSeedTitle, + pageSeedSubject, + pageSeedDesc) + return pageWidget, textViewRestoreSeed, pageSeedName +} - // --- pageSeedConfirm +func pageSeedConfirm(assistant *gtk.Assistant, assistFunc assistantFunc, + textViewSeed *gtk.TextView) (*gtk.Widget, string) { + pageWidget := new(gtk.Widget) textViewConfirmSeed, err := gtk.TextViewNew() fatalErrorCheck(err) @@ -157,9 +373,9 @@ This seed will allow you to recover your wallet in case of computer failure. mnemonic2 = space.ReplaceAllString(mnemonic2, " ") mnemonic2 = strings.TrimSpace(mnemonic2) if mnemonic1 == mnemonic2 { - assistant.SetPageComplete(pageSeedConfirm, true) + assistantPageComplete(assistant, pageWidget, true) } else { - assistant.SetPageComplete(pageSeedConfirm, false) + assistantPageComplete(assistant, pageWidget, false) } }) @@ -169,15 +385,18 @@ This seed will allow you to recover your wallet in case of computer failure. pageSeedConfirmDesc := `Your seed is important! To make sure that you have properly saved your seed, please retype it here.` - pageSeedConfirm = createPage( + pageWidget = assistFunc( assistant, textViewConfirmSeed, pageSeedConfirmName, pageSeedConfirmTitle, pageSeedConfirmSubject, pageSeedConfirmDesc) + return pageWidget, pageSeedConfirmName +} - // --- PagePassword +func pagePassword(assistant *gtk.Assistant, assistFunc assistantFunc) (*gtk.Widget, *gtk.Entry, string) { + pageWidget := new(gtk.Widget) entryPassword, err := gtk.EntryNew() fatalErrorCheck(err) @@ -216,9 +435,9 @@ To make sure that you have properly saved your seed, please retype it here.` fatalErrorCheck(err) if pass1 == pass2 { - assistant.SetPageComplete(pagePassword, true) + assistantPageComplete(assistant, pageWidget, true) } else { - assistant.SetPageComplete(pagePassword, false) + assistantPageComplete(assistant, pageWidget, false) } } entryPassword.Connect("changed", func(entry *gtk.Entry) { @@ -234,15 +453,19 @@ To make sure that you have properly saved your seed, please retype it here.` pagePasswordSubject := "Enter password for your wallet:" pagePsswrdDesc := "Please choose a strong password for your wallet." - pagePassword = createPage( + pageWidget = assistFunc( assistant, grid, pagePasswordName, pagePasswordTitle, pagePasswordSubject, pagePsswrdDesc) + return pageWidget, entryPassword, pagePasswordName +} - // --- pageNumValidators +func pageNumValidators(assistant *gtk.Assistant, + assistFunc assistantFunc) (*gtk.Widget, *gtk.ListStore, *gtk.ComboBox, string) { + var pageWidget *gtk.Widget lsNumValidators, err := gtk.ListStoreNew(glib.TYPE_INT) fatalErrorCheck(err) @@ -270,7 +493,7 @@ To make sure that you have properly saved your seed, please retype it here.` setMargin(labelNumValidators, 6, 6, 6, 6) setMargin(comboNumValidators, 6, 6, 6, 6) - grid, err = gtk.GridNew() + grid, err := gtk.GridNew() fatalErrorCheck(err) grid.Add(labelNumValidators) @@ -283,15 +506,18 @@ To make sure that you have properly saved your seed, please retype it here.` You can define validators based on the amount of coins you want to stake. For more information, look here` - pageNumValidators = createPage( + pageWidget = assistFunc( assistant, grid, pageNumValidatorsName, pageNumValidatorsTitle, pageNumValidatorsSubject, pageNumValidatorsDesc) + return pageWidget, lsNumValidators, comboNumValidators, pageNumValidatorsName +} - // --- pageFinal +func pageFinal(assistant *gtk.Assistant, assistFunc assistantFunc) (*gtk.Widget, *gtk.TextView, string) { + var pageWidget *gtk.Widget textViewNodeInfo, err := gtk.TextViewNew() fatalErrorCheck(err) @@ -312,109 +538,17 @@ For more information, look