diff --git a/go.mod b/go.mod index 1cf1c8cc4..c6f473b0e 100644 --- a/go.mod +++ b/go.mod @@ -25,4 +25,7 @@ require ( golang.org/x/text v0.3.3 ) -replace github.com/decred/dcrdata/txhelpers/v4 => github.com/decred/dcrdata/txhelpers/v4 v4.0.0-20200108145420-f82113e7e212 +replace ( + github.com/decred/dcrdata/txhelpers/v4 => github.com/decred/dcrdata/txhelpers/v4 v4.0.0-20200108145420-f82113e7e212 + github.com/planetdecred/dcrlibwallet => github.com/planetdecred/dcrlibwallet v1.6.1-0.20210618124747-f776ef63322f +) diff --git a/go.sum b/go.sum index eef220745..bb80cadd7 100644 --- a/go.sum +++ b/go.sum @@ -711,6 +711,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/planetdecred/dcrlibwallet v1.6.0 h1:Bn5es2IKoQkXSYSg1cD2h2Z3ndWkf7IiaU7aTqtvOcU= github.com/planetdecred/dcrlibwallet v1.6.0/go.mod h1:gM1g2wCXwmLxICoV26M3rtCiyat7/YiIok+C2apx3pY= +github.com/planetdecred/dcrlibwallet v1.6.1-0.20210618124747-f776ef63322f h1:lgVy3wX3Y6dkEFZ4YjVyibegW/B7Rnn0W4m8lpTsOkA= +github.com/planetdecred/dcrlibwallet v1.6.1-0.20210618124747-f776ef63322f/go.mod h1:gM1g2wCXwmLxICoV26M3rtCiyat7/YiIok+C2apx3pY= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/ui/about_page.go b/ui/about_page.go index 09d828be0..3ac4bed45 100644 --- a/ui/about_page.go +++ b/ui/about_page.go @@ -51,6 +51,10 @@ func AboutPage(common *pageCommon) Page { return pg } +func (pg *aboutPage) OnResume() { + +} + func (pg *aboutPage) Layout(gtx layout.Context) layout.Dimensions { body := func(gtx C) D { page := SubPage{ diff --git a/ui/account_details_page.go b/ui/account_details_page.go index 79aebe856..142b26164 100644 --- a/ui/account_details_page.go +++ b/ui/account_details_page.go @@ -47,6 +47,10 @@ func AcctDetailsPage(common *pageCommon) Page { return pg } +func (pg *acctDetailsPage) OnResume() { + +} + func (pg *acctDetailsPage) Layout(gtx layout.Context) layout.Dimensions { common := pg.common diff --git a/ui/components.go b/ui/components.go index 25d5384f5..9b67fc5df 100644 --- a/ui/components.go +++ b/ui/components.go @@ -30,7 +30,7 @@ const ( type ( TransactionRow struct { - transaction wallet.Transaction + transaction dcrlibwallet.Transaction index int showBadge bool } @@ -82,11 +82,13 @@ func transactionRow(gtx layout.Context, common *pageCommon, row TransactionRow) directionIconTopMargin = values.MarginPadding0 } + wal := common.multiWallet.WalletWithID(row.transaction.WalletID) + return layout.Inset{Top: values.MarginPadding16}.Layout(gtx, func(gtx C) D { return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, layout.Rigid(func(gtx C) D { icon := common.icons.receiveIcon - if row.transaction.Txn.Direction == dcrlibwallet.TxDirectionSent { + if row.transaction.Direction == dcrlibwallet.TxDirectionSent { icon = common.icons.sendIcon } icon.Scale = 1.0 @@ -128,11 +130,11 @@ func transactionRow(gtx layout.Context, common *pageCommon, row TransactionRow) return layout.Inset{Left: values.MarginPadding16}.Layout(gtx, func(gtx C) D { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { - return common.layoutBalance(gtx, row.transaction.Balance, true) + return common.layoutBalance(gtx, dcrutil.Amount(row.transaction.Amount).String(), true) }), layout.Rigid(func(gtx C) D { if row.showBadge { - return walletLabel(gtx, common, row.transaction.WalletName) + return walletLabel(gtx, common, wal.Name) } return layout.Dimensions{} }), @@ -144,15 +146,12 @@ func transactionRow(gtx layout.Context, common *pageCommon, row TransactionRow) layout.Rigid(func(gtx C) D { return layout.Inset{Right: values.MarginPadding8}.Layout(gtx, func(gtx C) D { - s := formatDateOrTime(row.transaction.Txn.Timestamp) - if row.transaction.Status != "confirmed" { - s = row.transaction.Status - } - status := common.theme.Body1(s) - if row.transaction.Status != "confirmed" { + status := common.theme.Body1("pending") + if txConfirmations(common, row.transaction) <= 1 { status.Color = common.theme.Color.Gray5 } else { status.Color = common.theme.Color.Gray4 + status.Text = formatDateOrTime(row.transaction.Timestamp) } status.Alignment = text.Middle return status.Layout(gtx) @@ -161,7 +160,7 @@ func transactionRow(gtx layout.Context, common *pageCommon, row TransactionRow) layout.Rigid(func(gtx C) D { return layout.Inset{Right: values.MarginPadding16}.Layout(gtx, func(gtx C) D { statusIcon := common.icons.confirmIcon - if row.transaction.Status != "confirmed" { + if txConfirmations(common, row.transaction) <= 1 { statusIcon = common.icons.pendingIcon } statusIcon.Scale = 1.0 @@ -179,6 +178,15 @@ func transactionRow(gtx layout.Context, common *pageCommon, row TransactionRow) }) } +func txConfirmations(common *pageCommon, transaction dcrlibwallet.Transaction) int32 { + if transaction.BlockHeight != -1 { + // TODO + return (common.multiWallet.WalletWithID(transaction.WalletID).GetBestBlock() - transaction.BlockHeight) + 1 + } + + return 0 +} + // walletLabel displays the wallet which a transaction belongs to. It is only displayed on the overview page when there // are transactions from multiple wallets func walletLabel(gtx layout.Context, c *pageCommon, walletName string) D { @@ -967,26 +975,16 @@ func (page *pageCommon) handleToast() { // createOrUpdateWalletDropDown check for len of wallets to create dropDown, // also update the list when create, update, delete a wallet. -func (page *pageCommon) createOrUpdateWalletDropDown(dwn **decredmaterial.DropDown) { - init := func() { - var walletDropDownItems []decredmaterial.DropDownItem - for i := range page.info.Wallets { - item := decredmaterial.DropDownItem{ - Text: page.info.Wallets[i].Name, - Icon: page.icons.walletIcon, - } - walletDropDownItems = append(walletDropDownItems, item) +func (page *pageCommon) createOrUpdateWalletDropDown(dwn **decredmaterial.DropDown, wallets []*dcrlibwallet.Wallet) { + var walletDropDownItems []decredmaterial.DropDownItem + for _, wal := range wallets { + item := decredmaterial.DropDownItem{ + Text: wal.Name, + Icon: page.icons.walletIcon, } - *dwn = page.theme.DropDown(walletDropDownItems, 2) - } - - if *dwn == nil && len(page.info.Wallets) > 0 { - init() - return - } - if (*dwn).Len() != len(page.info.Wallets) { - init() + walletDropDownItems = append(walletDropDownItems, item) } + *dwn = page.theme.DropDown(walletDropDownItems, 2) } func createOrderDropDown(c *pageCommon) *decredmaterial.DropDown { diff --git a/ui/create_restore_page.go b/ui/create_restore_page.go index 88c04d354..ffb7b90af 100644 --- a/ui/create_restore_page.go +++ b/ui/create_restore_page.go @@ -150,6 +150,10 @@ func CreateRestorePage(common *pageCommon) Page { return pg } +func (pg *createRestore) OnResume() { + +} + func (pg *createRestore) Layout(gtx layout.Context) layout.Dimensions { pd := values.MarginPadding15 dims := layout.Flex{Axis: layout.Vertical, Spacing: layout.SpaceBetween}.Layout(gtx, diff --git a/ui/debug_page.go b/ui/debug_page.go index a63cc29ca..ba2e0dc7d 100644 --- a/ui/debug_page.go +++ b/ui/debug_page.go @@ -45,6 +45,10 @@ func DebugPage(common *pageCommon) Page { return pg } +func (pg *debugPage) OnResume() { + +} + func (pg *debugPage) handle() { for i := range pg.debugItems { for pg.debugItems[i].clickable.Clicked() { diff --git a/ui/decredmaterial/dropdown.go b/ui/decredmaterial/dropdown.go index 8ed90da37..f0b183463 100644 --- a/ui/decredmaterial/dropdown.go +++ b/ui/decredmaterial/dropdown.go @@ -105,6 +105,9 @@ func (c *DropDown) Changed() bool { if index != 0 { for c.items[index].button.Button.Clicked() { if c.items[0].label.Text != c.items[index].Text { + c.selectedIndex = index + c.items[0].label.Text = c.items[index].Text + c.isOpen = false return true } } diff --git a/ui/help_page.go b/ui/help_page.go index 6046147de..3e5d52a25 100644 --- a/ui/help_page.go +++ b/ui/help_page.go @@ -28,6 +28,10 @@ func HelpPage(common *pageCommon) Page { return pg } +func (pg *helpPage) OnResume() { + +} + // main settings layout func (pg *helpPage) Layout(gtx layout.Context) layout.Dimensions { body := func(gtx C) D { diff --git a/ui/listeners.go b/ui/listeners.go index 6a3df2d17..308387a29 100644 --- a/ui/listeners.go +++ b/ui/listeners.go @@ -1,6 +1,8 @@ package ui import ( + "encoding/json" + "github.com/planetdecred/dcrlibwallet" "github.com/planetdecred/godcr/wallet" ) @@ -11,10 +13,21 @@ func (mp *mainPage) OnTransaction(transaction string) { mp.updateBalance() // beeep send notification + + var tx dcrlibwallet.Transaction + err := json.Unmarshal([]byte(transaction), &tx) + if err == nil { + mp.notificationsUpdate <- wallet.NewTransaction{ + Transaction: &tx, + } + } } func (mp *mainPage) OnBlockAttached(walletID int, blockHeight int32) { mp.updateBalance() + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ + Stage: wallet.BlockAttached, + } } func (mp *mainPage) OnTransactionConfirmed(walletID int, hash string, blockHeight int32) { @@ -35,27 +48,27 @@ func (mp *mainPage) OnProposalVoteFinished(proposal *dcrlibwallet.Proposal) {} // Sync notifications func (mp *mainPage) OnSyncStarted(wasRestarted bool) { - mp.syncStatusUpdate <- wallet.SyncStatusUpdate{ + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ Stage: wallet.SyncStarted, } } func (mp *mainPage) OnPeerConnectedOrDisconnected(numberOfConnectedPeers int32) { - mp.syncStatusUpdate <- wallet.SyncStatusUpdate{ + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ Stage: wallet.PeersConnected, ConnectedPeers: numberOfConnectedPeers, } } func (mp *mainPage) OnCFiltersFetchProgress(cfiltersFetchProgress *dcrlibwallet.CFiltersFetchProgressReport) { - mp.syncStatusUpdate <- wallet.SyncStatusUpdate{ + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ Stage: wallet.CfiltersFetchProgress, ProgressReport: cfiltersFetchProgress, } } func (mp *mainPage) OnHeadersFetchProgress(headersFetchProgress *dcrlibwallet.HeadersFetchProgressReport) { - mp.syncStatusUpdate <- wallet.SyncStatusUpdate{ + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ Stage: wallet.HeadersFetchProgress, ProgressReport: wallet.SyncHeadersFetchProgress{ Progress: headersFetchProgress, @@ -63,7 +76,7 @@ func (mp *mainPage) OnHeadersFetchProgress(headersFetchProgress *dcrlibwallet.He } } func (mp *mainPage) OnAddressDiscoveryProgress(addressDiscoveryProgress *dcrlibwallet.AddressDiscoveryProgressReport) { - mp.syncStatusUpdate <- wallet.SyncStatusUpdate{ + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ Stage: wallet.AddressDiscoveryProgress, ProgressReport: wallet.SyncAddressDiscoveryProgress{ Progress: addressDiscoveryProgress, @@ -72,7 +85,7 @@ func (mp *mainPage) OnAddressDiscoveryProgress(addressDiscoveryProgress *dcrlibw } func (mp *mainPage) OnHeadersRescanProgress(headersRescanProgress *dcrlibwallet.HeadersRescanProgressReport) { - mp.syncStatusUpdate <- wallet.SyncStatusUpdate{ + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ Stage: wallet.HeadersRescanProgress, ProgressReport: wallet.SyncHeadersRescanProgress{ Progress: headersRescanProgress, @@ -81,13 +94,13 @@ func (mp *mainPage) OnHeadersRescanProgress(headersRescanProgress *dcrlibwallet. } func (mp *mainPage) OnSyncCompleted() { mp.updateBalance() - mp.syncStatusUpdate <- wallet.SyncStatusUpdate{ + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ Stage: wallet.SyncCompleted, } } func (mp *mainPage) OnSyncCanceled(willRestart bool) { - mp.syncStatusUpdate <- wallet.SyncStatusUpdate{ + mp.notificationsUpdate <- wallet.SyncStatusUpdate{ Stage: wallet.SyncCanceled, } } diff --git a/ui/log_page.go b/ui/log_page.go index ebdff6102..bceec6a78 100644 --- a/ui/log_page.go +++ b/ui/log_page.go @@ -46,6 +46,10 @@ func LogPage(common *pageCommon) Page { return pg } +func (pg *logPage) OnResume() { + +} + func (pg *logPage) copyLogEntries(gtx C) { go func() { pg.entriesLock.Lock() diff --git a/ui/main_page.go b/ui/main_page.go index 5d01c9f32..68cd812db 100644 --- a/ui/main_page.go +++ b/ui/main_page.go @@ -23,6 +23,8 @@ type mainPage struct { minimizeNavDrawerButton decredmaterial.IconButton maximizeNavDrawerButton decredmaterial.IconButton + autoSync bool + current, previous string pages map[string]Page @@ -37,18 +39,26 @@ func newMainPage(common *pageCommon) *mainPage { mp := &mainPage{ pageCommon: common, + autoSync: true, pages: common.loadPages(), - current: PageOverview, minimizeNavDrawerButton: common.theme.PlainIconButton(new(widget.Clickable), common.icons.navigationArrowBack), maximizeNavDrawerButton: common.theme.PlainIconButton(new(widget.Clickable), common.icons.navigationArrowForward), } // init shared page functions + common.changeFragment = mp.changeFragment common.changePage = mp.changePage common.setReturnPage = mp.setReturnPage common.returnPage = &mp.previous common.page = &mp.current + common.toggleSync = func() { + if mp.multiWallet.IsConnectedToDecredNetwork() { + mp.multiWallet.CancelSync() + } else { + mp.startSyncing() + } + } iconColor := common.theme.Color.Gray3 mp.minimizeNavDrawerButton.Color, mp.maximizeNavDrawerButton.Color = iconColor, iconColor @@ -116,12 +126,19 @@ func (mp *mainPage) initNavItems() { func (mp *mainPage) OnResume() { // register for notifications - mp.multiWallet.SetAccountMixerNotification(mp) + mp.multiWallet.AddAccountMixerNotificationListener(mp, PageMain) mp.multiWallet.Politeia.AddNotificationListener(mp, PageMain) mp.multiWallet.AddTxAndBlockNotificationListener(mp, PageMain) mp.multiWallet.AddSyncProgressListener(mp, PageMain) mp.updateBalance() + + mp.changeFragment(OverviewPage(mp.pageCommon), PageOverview) + + if mp.autoSync { + mp.autoSync = false + mp.startSyncing() + } } func (mp *mainPage) updateBalance() { @@ -159,6 +176,47 @@ func (mp *mainPage) calculateTotalWalletsBalance() (dcrutil.Amount, error) { return dcrutil.Amount(totalBalance), nil } +func (mp *mainPage) startSyncing() { + for _, wal := range mp.multiWallet.AllWallets() { + if !wal.HasDiscoveredAccounts && wal.IsLocked() { + mp.unlockWalletForSyncing(wal) + return + } + } + + err := mp.multiWallet.SpvSync() + if err != nil { + // show error dialog + log.Info("Error starting sync:", err) + } +} + +func (mp *mainPage) unlockWalletForSyncing(wal *dcrlibwallet.Wallet) { + newPasswordModal(mp.pageCommon). + title(values.String(values.StrResumeAccountDiscoveryTitle)). + hint(wal.Name+" Spending password"). + negativeButton(values.String(values.StrCancel), func() {}). + positiveButton(values.String(values.StrUnlock), func(password string, pm *passwordModal) bool { + go func() { + err := mp.multiWallet.UnlockWallet(wal.ID, []byte(password)) + if err != nil { + errText := err.Error() + if err.Error() == "invalid_passphrase" { + errText = "Invalid passphrase" + } + pm.setError(errText) + pm.setLoading(false) + return + } + pm.Dismiss() + mp.startSyncing() + }() + + return false + }).Show() + +} + func (mp *mainPage) handle() { // TODO: This function should be only called when @@ -182,20 +240,41 @@ func (mp *mainPage) handle() { for i := range mp.drawerNavItems { for mp.drawerNavItems[i].clickable.Clicked() { - mp.changePage(mp.drawerNavItems[i].page) + if i == 0 { + mp.changeFragment(OverviewPage(mp.pageCommon), PageOverview) + } else if i == 1 { + mp.changeFragment(TransactionsPage(mp.pageCommon), PageTransactions) + } else { + mp.changePage(mp.drawerNavItems[i].page) + } } } } func (mp *mainPage) onClose() { + if pg, ok := mp.pages[mp.current]; ok { + pg.onClose() + } + mp.multiWallet.RemoveAccountMixerNotificationListener(PageMain) mp.multiWallet.Politeia.RemoveNotificationListener(PageMain) mp.multiWallet.RemoveTxAndBlockNotificationListener(PageMain) mp.multiWallet.RemoveSyncProgressListener(PageMain) } +func (mp *mainPage) changeFragment(page Page, id string) { + mp.pages[id] = page + mp.changePage(id) +} + func (mp *mainPage) changePage(page string) { - mp.pages[mp.current].onClose() - mp.current = page + if pg, ok := mp.pages[mp.current]; ok { + pg.onClose() + } + + if pg, ok := mp.pages[page]; ok { + pg.OnResume() + mp.current = page + } } func (mp *mainPage) setReturnPage(from string) { diff --git a/ui/more_page.go b/ui/more_page.go index f09143bd7..a36846519 100644 --- a/ui/more_page.go +++ b/ui/more_page.go @@ -64,6 +64,10 @@ func MorePage(common *pageCommon) Page { return pg } +func (pg *morePage) OnResume() { + +} + func (pg *morePage) handleClickEvents(common *pageCommon) { for i := range pg.morePageListItems { for pg.morePageListItems[i].clickable.Clicked() { diff --git a/ui/overview_page.go b/ui/overview_page.go index 19a654108..6cc1bbd68 100644 --- a/ui/overview_page.go +++ b/ui/overview_page.go @@ -4,14 +4,15 @@ import ( "fmt" "image" "image/color" + "time" "gioui.org/gesture" "gioui.org/io/event" "gioui.org/io/pointer" "gioui.org/layout" "gioui.org/widget" - "github.com/planetdecred/dcrlibwallet" + "github.com/planetdecred/dcrlibwallet" "github.com/planetdecred/godcr/ui/decredmaterial" "github.com/planetdecred/godcr/ui/values" "github.com/planetdecred/godcr/wallet" @@ -29,31 +30,39 @@ type walletSyncDetails struct { } type overviewPage struct { - common *pageCommon + *pageCommon + pageClosing chan bool listContainer, walletSyncList, transactionsList *layout.List theme *decredmaterial.Theme tab *decredmaterial.Tabs - wallet **wallet.Wallet - walletInfo *wallet.MultiWalletInfo - walletSyncStatus *wallet.SyncStatus - walletTransactions **wallet.Transactions - walletTransaction **wallet.Transaction - toTransactions decredmaterial.TextAndIconButton - sync decredmaterial.Button - toggleSyncDetails decredmaterial.Button + allWallets []*dcrlibwallet.Wallet + transactions []dcrlibwallet.Transaction + + toTransactions decredmaterial.TextAndIconButton + sync decredmaterial.Button + toggleSyncDetails decredmaterial.Button syncedIcon, notSyncedIcon, walletStatusIcon, cachedIcon *widget.Icon syncingIcon *widget.Image toTransactionDetails []*gesture.Click - autoSyncWallet bool + walletSyncing bool + walletSynced bool + isConnnected bool + + bestBlock *dcrlibwallet.BlockInfo + connectedPeers int32 + remainingSyncTime string + headersToFetchOrScan int32 + headerFetchProgress int32 + syncProgress int + syncStep int syncButtonHeight int moreButtonWidth int moreButtonHeight int - isCheckingLockWL bool syncDetailsVisibility bool txnRowHeight int queue event.Queue @@ -61,26 +70,23 @@ type overviewPage struct { func OverviewPage(c *pageCommon) Page { pg := &overviewPage{ - theme: c.theme, - common: c, - tab: c.navTab, - - wallet: &c.wallet, - walletInfo: c.info, - walletSyncStatus: c.walletSyncStatus, - walletTransactions: c.walletTransactions, - walletTransaction: c.walletTransaction, - listContainer: &layout.List{Axis: layout.Vertical}, - walletSyncList: &layout.List{Axis: layout.Vertical}, - transactionsList: &layout.List{Axis: layout.Vertical}, + pageCommon: c, + pageClosing: make(chan bool, 1), + theme: c.theme, + tab: c.navTab, + + allWallets: c.multiWallet.AllWallets(), + + listContainer: &layout.List{Axis: layout.Vertical}, + walletSyncList: &layout.List{Axis: layout.Vertical}, + transactionsList: &layout.List{Axis: layout.Vertical}, + + bestBlock: c.multiWallet.GetBestBlock(), syncButtonHeight: 50, moreButtonWidth: 115, moreButtonHeight: 70, txnRowHeight: 56, - - isCheckingLockWL: false, - autoSyncWallet: true, } pg.toTransactions = c.theme.TextAndIconButton(new(widget.Clickable), values.String(values.StrSeeAll), c.icons.navigationArrowForward) @@ -113,10 +119,31 @@ func OverviewPage(c *pageCommon) Page { return pg } +func (pg *overviewPage) OnResume() { + pg.walletSyncing = pg.multiWallet.IsSyncing() + pg.walletSynced = pg.multiWallet.IsSynced() + pg.isConnnected = pg.multiWallet.IsConnectedToDecredNetwork() + pg.connectedPeers = pg.multiWallet.ConnectedPeers() + pg.bestBlock = pg.multiWallet.GetBestBlock() + + pg.loadTransactions() + pg.listenForSyncNotifications() +} + +func (pg *overviewPage) loadTransactions() { + transactions, err := pg.multiWallet.GetTransactionsRaw(0, 5, dcrlibwallet.TxFilterAll, true) + if err != nil { + log.Error("Error getting transactions:", err) + return + } + + pg.transactions = transactions +} + // Layout lays out the entire content for overview pg. func (pg *overviewPage) Layout(gtx layout.Context) layout.Dimensions { pg.queue = gtx - c := pg.common + c := pg.pageCommon if c.info.LoadedWallets == 0 { return c.UniformPadding(gtx, func(gtx C) D { return layout.Center.Layout(gtx, func(gtx C) D { @@ -153,12 +180,9 @@ func (pg *overviewPage) syncDetail(name, status, headersFetched, progress string // recentTransactionsSection lays out the list of recent transactions. func (pg *overviewPage) recentTransactionsSection(gtx layout.Context, common *pageCommon) layout.Dimensions { - var recentTransactions []wallet.Transaction - if len((*pg.walletTransactions).Txs) > 0 { - recentTransactions = (*pg.walletTransactions).Recent - if len(recentTransactions) != len(pg.toTransactionDetails) { - pg.toTransactionDetails = createClickGestures(len(recentTransactions)) - } + + if len(pg.transactions) != len(pg.toTransactionDetails) { + pg.toTransactionDetails = createClickGestures(len(pg.transactions)) } return pg.theme.Card().Layout(gtx, func(gtx layout.Context) layout.Dimensions { @@ -174,7 +198,7 @@ func (pg *overviewPage) recentTransactionsSection(gtx layout.Context, common *pa return layout.Inset{Left: values.MarginPadding16}.Layout(gtx, pg.theme.Separator().Layout) }), layout.Rigid(func(gtx C) D { - if len((*pg.walletTransactions).Txs) == 0 { + if len(pg.transactions) == 0 { message := pg.theme.Body1(values.String(values.StrNoTransactionsYet)) message.Color = pg.theme.Color.Gray2 return Container{layout.Inset{ @@ -184,14 +208,14 @@ func (pg *overviewPage) recentTransactionsSection(gtx layout.Context, common *pa }}.Layout(gtx, message.Layout) } - return pg.transactionsList.Layout(gtx, len(recentTransactions), func(gtx C, i int) D { + return pg.transactionsList.Layout(gtx, len(pg.transactions), func(gtx C, i int) D { click := pg.toTransactionDetails[i] pointer.Rect(image.Rectangle{Max: gtx.Constraints.Max}).Add(gtx.Ops) click.Add(gtx.Ops) var row = TransactionRow{ - transaction: recentTransactions[i], + transaction: pg.transactions[i], index: i, - showBadge: showLabel(recentTransactions), + showBadge: len(pg.allWallets) > 1, } return layout.Inset{Left: values.MarginPadding16}.Layout(gtx, func(gtx C) D { return transactionRow(gtx, common, row) @@ -230,19 +254,19 @@ func (pg *overviewPage) syncStatusSection(gtx layout.Context) layout.Dimensions return pg.syncStatusTextRow(gtx, uniform) }), layout.Rigid(func(gtx C) D { - if !pg.walletInfo.Syncing { + if !pg.walletSyncing { return pg.syncDormantContent(gtx, uniform) } return layout.Dimensions{} }), layout.Rigid(func(gtx C) D { - if pg.walletInfo.Syncing { + if pg.walletSyncing { return pg.progressBarRow(gtx, uniform) } return layout.Dimensions{} }), layout.Rigid(func(gtx C) D { - if pg.walletInfo.Syncing { + if pg.walletSyncing { return pg.progressStatusRow(gtx, uniform) } return layout.Dimensions{} @@ -253,13 +277,13 @@ func (pg *overviewPage) syncStatusSection(gtx layout.Context) layout.Dimensions }) }), layout.Rigid(func(gtx C) D { - if pg.walletInfo.Syncing { + if pg.walletSyncing { return pg.theme.Separator().Layout(gtx) } return layout.Dimensions{} }), layout.Rigid(func(gtx C) D { - if pg.walletInfo.Syncing && pg.syncDetailsVisibility { + if pg.walletSyncing && pg.syncDetailsVisibility { return Container{layout.UniformInset(values.MarginPadding16)}.Layout(gtx, func(gtx C) D { return pg.walletSyncRow(gtx, uniform) }) @@ -267,13 +291,13 @@ func (pg *overviewPage) syncStatusSection(gtx layout.Context) layout.Dimensions return layout.Dimensions{} }), layout.Rigid(func(gtx C) D { - if pg.walletInfo.Syncing && pg.syncDetailsVisibility { + if pg.walletSyncing && pg.syncDetailsVisibility { return pg.theme.Separator().Layout(gtx) } return layout.Dimensions{} }), layout.Rigid(func(gtx C) D { - if pg.walletInfo.Syncing { + if pg.walletSyncing { gtx.Constraints.Min.X = gtx.Constraints.Max.X return layout.Inset{Top: values.MarginPadding14}.Layout(gtx, func(gtx C) D { return pg.toggleSyncDetails.Layout(gtx) @@ -313,7 +337,7 @@ func (pg *overviewPage) syncDormantContent(gtx layout.Context, uniform layout.In return layout.Inset{Bottom: values.MarginPadding12}.Layout(gtx, pg.blockInfoRow) }), layout.Rigid(func(gtx C) D { - if pg.walletInfo.Synced { + if pg.walletSynced { return pg.connectionPeer(gtx) } latestBlockTitleLabel := pg.theme.Body1(values.String(values.StrNoConnectedPeer)) @@ -335,7 +359,7 @@ func (pg *overviewPage) blockInfoRow(gtx layout.Context) layout.Dimensions { return layout.Inset{ Left: values.MarginPadding5, Right: values.MarginPadding5, - }.Layout(gtx, pg.theme.Body1(fmt.Sprintf("%v", pg.walletInfo.BestBlockHeight)).Layout) + }.Layout(gtx, pg.theme.Body1(fmt.Sprintf("%d", pg.bestBlock.Height)).Layout) }), layout.Rigid(func(gtx C) D { pg.walletStatusIcon.Color = pg.theme.Color.Gray @@ -344,7 +368,8 @@ func (pg *overviewPage) blockInfoRow(gtx layout.Context) layout.Dimensions { }) }), layout.Rigid(func(gtx C) D { - return layout.Inset{Right: values.MarginPadding5}.Layout(gtx, pg.theme.Body1(fmt.Sprintf("%v", pg.walletInfo.LastSyncTime)).Layout) + currentSeconds := time.Now().UnixNano() / int64(time.Second) + return layout.Inset{Right: values.MarginPadding5}.Layout(gtx, pg.theme.Body1(wallet.SecondsToDays(currentSeconds-pg.bestBlock.Timestamp)).Layout) }), layout.Rigid(func(gtx C) D { lastSyncedLabel := pg.theme.Body1(values.String(values.StrAgo)) @@ -362,7 +387,7 @@ func (pg *overviewPage) connectionPeer(gtx layout.Context) layout.Dimensions { return connectedPeersInfoLabel.Layout(gtx) }), layout.Rigid(func(gtx C) D { - return layout.Inset{Left: values.MarginPadding5, Right: values.MarginPadding5}.Layout(gtx, pg.theme.Body1(fmt.Sprintf("%d", pg.walletSyncStatus.ConnectedPeers)).Layout) + return layout.Inset{Left: values.MarginPadding5, Right: values.MarginPadding5}.Layout(gtx, pg.theme.Body1(fmt.Sprintf("%d", pg.connectedPeers)).Layout) }), layout.Rigid(func(gtx C) D { peersLabel := pg.theme.Body1("peers") @@ -378,7 +403,7 @@ func (pg *overviewPage) syncBoxTitleRow(gtx layout.Context) layout.Dimensions { title.Color = pg.theme.Color.Gray3 statusLabel := pg.theme.Body1(values.String(values.StrOffline)) pg.walletStatusIcon.Color = pg.theme.Color.Danger - if pg.walletInfo.Synced || pg.walletInfo.Syncing { + if pg.isConnnected { statusLabel.Text = values.String(values.StrOnline) pg.walletStatusIcon.Color = pg.theme.Color.Success } @@ -401,9 +426,9 @@ func (pg *overviewPage) syncBoxTitleRow(gtx layout.Context) layout.Dimensions { // syncStatusTextRow lays out sync status text and sync button. func (pg *overviewPage) syncStatusTextRow(gtx layout.Context, inset layout.Inset) layout.Dimensions { syncStatusLabel := pg.theme.H6(values.String(values.StrWalletNotSynced)) - if pg.walletInfo.Syncing { + if pg.walletSyncing { syncStatusLabel.Text = values.String(values.StrSyncingState) - } else if pg.walletInfo.Synced { + } else if pg.walletSynced { syncStatusLabel.Text = values.String(values.StrSynced) } @@ -423,8 +448,10 @@ func (pg *overviewPage) syncStatusTextRow(gtx layout.Context, inset layout.Inset Right: values.MarginPadding10, } pg.sync.CornerRadius = values.MarginPadding10 - - if pg.sync.Text == values.String(values.StrReconnect) { + if pg.isConnnected { + pg.sync.Text = values.String(values.StrDisconnect) + } else { + pg.sync.Text = values.String(values.StrReconnect) pg.sync.Inset.Left = values.MarginPadding25 layout.Inset{Top: values.MarginPadding4, Left: values.MarginPadding7}.Layout(gtx, func(gtx C) D { pg.cachedIcon.Color = pg.theme.Color.Gray @@ -442,11 +469,11 @@ func (pg *overviewPage) syncStatusTextRow(gtx layout.Context, inset layout.Inset func (pg *overviewPage) syncStatusIcon(gtx layout.Context) layout.Dimensions { syncStatusIcon := pg.notSyncedIcon - if pg.walletInfo.Synced { + if pg.walletSynced { syncStatusIcon = pg.syncedIcon } i := layout.Inset{Right: values.MarginPadding16, Top: values.MarginPadding9} - if pg.walletInfo.Syncing { + if pg.walletSyncing { return i.Layout(gtx, pg.syncingIcon.Layout) } return i.Layout(gtx, func(gtx C) D { @@ -457,8 +484,7 @@ func (pg *overviewPage) syncStatusIcon(gtx layout.Context) layout.Dimensions { // progressBarRow lays out the progress bar. func (pg *overviewPage) progressBarRow(gtx layout.Context, inset layout.Inset) layout.Dimensions { return inset.Layout(gtx, func(gtx C) D { - progress := pg.walletSyncStatus.Progress - p := pg.theme.ProgressBar(int(progress)) + p := pg.theme.ProgressBar(pg.syncProgress) p.Height = values.MarginPadding8 p.Radius = values.MarginPadding4 p.Color = pg.theme.Color.Success @@ -468,12 +494,12 @@ func (pg *overviewPage) progressBarRow(gtx layout.Context, inset layout.Inset) l // progressStatusRow lays out the progress status when the wallet is syncing. func (pg *overviewPage) progressStatusRow(gtx layout.Context, inset layout.Inset) layout.Dimensions { - timeLeft := pg.walletSyncStatus.RemainingTime + timeLeft := pg.remainingSyncTime if timeLeft == "" { timeLeft = "0s" } - percentageLabel := pg.theme.Body1(fmt.Sprintf("%v%%", pg.walletSyncStatus.Progress)) + percentageLabel := pg.theme.Body1(fmt.Sprintf("%v%%", pg.syncProgress)) timeLeftLabel := pg.theme.Body1(fmt.Sprintf("%v Left", timeLeft)) return inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions { return endToEndRow(gtx, percentageLabel.Layout, timeLeftLabel.Layout) @@ -486,9 +512,9 @@ func (pg *overviewPage) walletSyncRow(gtx layout.Context, inset layout.Inset) la return layout.Inset{Top: values.MarginPadding10}.Layout(gtx, func(gtx C) D { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { - completedSteps := pg.theme.Body2(values.StringF(values.StrSyncSteps, pg.walletSyncStatus.Steps)) + completedSteps := pg.theme.Body2(values.StringF(values.StrSyncSteps, pg.syncStep)) completedSteps.Color = pg.theme.Color.Gray - headersFetched := pg.theme.Body1(values.StringF(values.StrFetchingBlockHeaders, pg.walletSyncStatus.HeadersFetchProgress)) + headersFetched := pg.theme.Body1(values.StringF(values.StrFetchingBlockHeaders, pg.headerFetchProgress)) return inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions { return endToEndRow(gtx, completedSteps.Layout, headersFetched.Layout) }) @@ -496,26 +522,26 @@ func (pg *overviewPage) walletSyncRow(gtx layout.Context, inset layout.Inset) la layout.Rigid(func(gtx C) D { connectedPeersTitleLabel := pg.theme.Body2(values.String(values.StrConnectedPeersCount)) connectedPeersTitleLabel.Color = pg.theme.Color.Gray - connectedPeersLabel := pg.theme.Body1(fmt.Sprintf("%d", pg.walletSyncStatus.ConnectedPeers)) + connectedPeersLabel := pg.theme.Body1(fmt.Sprintf("%d", pg.connectedPeers)) return inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions { return endToEndRow(gtx, connectedPeersTitleLabel.Layout, connectedPeersLabel.Layout) }) }), layout.Rigid(func(gtx C) D { - var overallBlockHeight int32 var walletSyncBoxes []layout.Widget - if pg.walletSyncStatus != nil { - overallBlockHeight = pg.walletSyncStatus.HeadersToFetch - } + currentSeconds := time.Now().UnixNano() / int64(time.Second) + for i := 0; i < len(pg.allWallets); i++ { + w := pg.allWallets[i] - for i := 0; i < len(pg.walletInfo.Wallets); i++ { - w := pg.walletInfo.Wallets[i] - if w.BestBlockHeight > overallBlockHeight { - overallBlockHeight = w.BestBlockHeight + status := "syncing..." + if w.IsWaiting() { + status = "waiting..." } - blockHeightProgress := values.StringF(values.StrBlockHeaderFetchedCount, w.BestBlockHeight, overallBlockHeight) - details := pg.syncDetail(w.Name, w.Status, blockHeightProgress, w.DaysBehind) + + blockHeightProgress := values.StringF(values.StrBlockHeaderFetchedCount, w.GetBestBlock(), pg.headersToFetchOrScan) + daysBehind := wallet.SecondsToDays(currentSeconds - w.GetBestBlockTimeStamp()) + details := pg.syncDetail(w.Name, status, blockHeightProgress, daysBehind) uniform := layout.UniformInset(values.MarginPadding5) walletSyncBoxes = append(walletSyncBoxes, func(gtx C) D { @@ -569,59 +595,22 @@ func (pg *overviewPage) walletSyncBox(gtx layout.Context, inset layout.Inset, de func (pg *overviewPage) handle() { eq := pg.queue - c := pg.common - - wal := *pg.wallet - if wal != nil { - isDarkModeOn := wal.ReadBoolConfigValueForKey("isDarkModeOn") - if isDarkModeOn != pg.theme.DarkMode { - pg.theme.SwitchDarkMode(isDarkModeOn) - } - } - - if pg.walletInfo.Synced { - pg.sync.Text = values.String(values.StrDisconnect) - } - - if pg.autoSyncWallet && !pg.walletInfo.Synced { - walletsLocked := getLockedWallets(c.wallet.AllWallets()) - if len(walletsLocked) == 0 { - log.Info("Starting sync") - c.wallet.StartSync() - pg.sync.Text = values.String(values.StrCancel) - pg.autoSyncWallet = false - } - } - - if !pg.isCheckingLockWL { - if lockedWallets := getLockedWallets(c.wallet.AllWallets()); len(lockedWallets) > 0 { - showWalletUnlockModal(c, lockedWallets) - } - pg.isCheckingLockWL = true - } if pg.sync.Button.Clicked() { - if pg.walletInfo.Synced || pg.walletInfo.Syncing { - c.wallet.CancelSync() - pg.sync.Text = values.String(values.StrReconnect) - } else { - c.wallet.StartSync() - pg.sync.Text = values.String(values.StrCancel) - } + go pg.toggleSync() } if pg.toTransactions.Button.Clicked() { - c.changePage(PageTransactions) + pg.changeFragment(TransactionsPage(pg.pageCommon), PageTransactions) } for index, click := range pg.toTransactionDetails { for _, e := range click.Events(eq) { if e.Type == gesture.TypeClick { - txn := (*pg.walletTransactions).Recent[index] - *pg.walletTransaction = &txn + txn := pg.transactions[index] - c.setReturnPage(PageOverview) - c.changePage(PageTransactionDetails) + pg.setReturnPage(PageOverview) + pg.changeFragment(TransactionDetailsPage(pg.pageCommon, &txn), "txdetails") return } } @@ -637,29 +626,62 @@ func (pg *overviewPage) handle() { } } -func (pg *overviewPage) onClose() {} - -func showWalletUnlockModal(c *pageCommon, lockedWallets []*dcrlibwallet.Wallet) { - newPasswordModal(c). - title(values.String(values.StrResumeAccountDiscoveryTitle)). - hint("Spending password"). - negativeButton(values.String(values.StrCancel), func() {}). - positiveButton(values.String(values.StrUnlock), func(password string, pm *passwordModal) bool { - go func() { - err := c.wallet.UnlockWallet(lockedWallets[0].ID, []byte(password)) - if err != nil { - errText := err.Error() - if err.Error() == "invalid_passphrase" { - errText = "Invalid passphrase" - } - pm.setError(errText) - pm.setLoading(false) - return +func (pg *overviewPage) listenForSyncNotifications() { + go func() { + for { + var notification interface{} + + select { + case notification = <-pg.notificationsUpdate: + case <-pg.pageClosing: + return + } + + switch n := notification.(type) { + case wallet.NewTransaction: + pg.loadTransactions() + case wallet.SyncStatusUpdate: + switch t := n.ProgressReport.(type) { + case wallet.SyncHeadersFetchProgress: + pg.headerFetchProgress = t.Progress.HeadersFetchProgress + pg.headersToFetchOrScan = t.Progress.TotalHeadersToFetch + pg.syncProgress = int(t.Progress.TotalSyncProgress) + pg.remainingSyncTime = wallet.SecondsToDays(t.Progress.TotalTimeRemainingSeconds) + pg.syncStep = wallet.FetchHeadersSteps + case wallet.SyncAddressDiscoveryProgress: + pg.syncProgress = int(t.Progress.TotalSyncProgress) + pg.remainingSyncTime = wallet.SecondsToDays(t.Progress.TotalTimeRemainingSeconds) + pg.syncStep = wallet.AddressDiscoveryStep + case wallet.SyncHeadersRescanProgress: + pg.headersToFetchOrScan = t.Progress.TotalHeadersToScan + pg.syncProgress = int(t.Progress.TotalSyncProgress) + pg.remainingSyncTime = wallet.SecondsToDays(t.Progress.TotalTimeRemainingSeconds) + pg.syncStep = wallet.RescanHeadersStep } - pm.Dismiss() - }() - return false - }).Show() + switch n.Stage { + case wallet.PeersConnected: + pg.connectedPeers = n.ConnectedPeers + case wallet.SyncStarted: + fallthrough + case wallet.SyncCanceled: + fallthrough + case wallet.SyncCompleted: + pg.loadTransactions() + pg.walletSyncing = pg.multiWallet.IsSyncing() + pg.walletSynced = pg.multiWallet.IsSynced() + pg.isConnnected = pg.multiWallet.IsConnectedToDecredNetwork() + case wallet.BlockAttached: + pg.bestBlock = pg.multiWallet.GetBestBlock() + } + } + + pg.refreshWindow() + + } + }() +} +func (pg *overviewPage) onClose() { + pg.pageClosing <- true } diff --git a/ui/page.go b/ui/page.go index d5317bfc8..a9c1cc340 100644 --- a/ui/page.go +++ b/ui/page.go @@ -50,6 +50,7 @@ type pageIcons struct { } type Page interface { + OnResume() // called when a page is starting or resuming from a paused state. Layout(layout.Context) layout.Dimensions handle() onClose() @@ -104,39 +105,39 @@ type walletAccountSelector struct { } type pageCommon struct { - printer *message.Printer - multiWallet *dcrlibwallet.MultiWallet - syncStatusUpdate chan wallet.SyncStatusUpdate - wallet *wallet.Wallet - walletAccount **wallet.Account - info *wallet.MultiWalletInfo - selectedWallet *int - selectedAccount *int - theme *decredmaterial.Theme - icons pageIcons - page *string - returnPage *string - dcrUsdtBittrex DCRUSDTBittrex - navTab *decredmaterial.Tabs - keyEvents chan *key.Event - toast **toast - states *states - internalLog *chan string - walletSyncStatus *wallet.SyncStatus - walletTransactions **wallet.Transactions - walletTransaction **wallet.Transaction - acctMixerStatus *chan *wallet.AccountMixer - selectedProposal **dcrlibwallet.Proposal - proposals **wallet.Proposals - syncedProposal chan *wallet.Proposal - txAuthor *dcrlibwallet.TxAuthor - broadcastResult *wallet.Broadcast - signatureResult **wallet.Signature - walletTickets **wallet.Tickets - vspInfo **wallet.VSP - unspentOutputs **wallet.UnspentOutputs - showModal func(Modal) - dismissModal func(Modal) + printer *message.Printer + multiWallet *dcrlibwallet.MultiWallet + notificationsUpdate chan interface{} + wallet *wallet.Wallet + walletAccount **wallet.Account + info *wallet.MultiWalletInfo + selectedWallet *int + selectedAccount *int + theme *decredmaterial.Theme + icons pageIcons + page *string + returnPage *string + dcrUsdtBittrex DCRUSDTBittrex + navTab *decredmaterial.Tabs + keyEvents chan *key.Event + toast **toast + states *states + internalLog *chan string + walletSyncStatus *wallet.SyncStatus + walletTransactions **wallet.Transactions + acctMixerStatus *chan *wallet.AccountMixer + selectedProposal **dcrlibwallet.Proposal + proposals **wallet.Proposals + syncedProposal chan *wallet.Proposal + txAuthor *dcrlibwallet.TxAuthor + broadcastResult *wallet.Broadcast + signatureResult **wallet.Signature + walletTickets **wallet.Tickets + vspInfo **wallet.VSP + unspentOutputs **wallet.UnspentOutputs + showModal func(Modal) + dismissModal func(Modal) + toggleSync func() testButton decredmaterial.Button @@ -145,9 +146,11 @@ type pageCommon struct { subPageBackButton decredmaterial.IconButton subPageInfoButton decredmaterial.IconButton + refreshWindow func() changeWindowPage func(Page) changePage func(string) setReturnPage func(string) + changeFragment func(Page, string) wallAcctSelector *walletAccountSelector } @@ -235,34 +238,35 @@ func (win *Window) newPageCommon(decredIcons map[string]image.Image) *pageCommon } common := &pageCommon{ - printer: message.NewPrinter(language.English), - multiWallet: win.wallet.GetMultiWallet(), - syncStatusUpdate: make(chan wallet.SyncStatusUpdate, 10), - wallet: win.wallet, - walletAccount: &win.walletAccount, - info: win.walletInfo, - selectedWallet: &win.selected, - selectedAccount: &win.selectedAccount, - theme: win.theme, - keyEvents: win.keyEvents, - states: &win.states, - icons: ic, - walletSyncStatus: win.walletSyncStatus, - walletTransactions: &win.walletTransactions, - walletTransaction: &win.walletTransaction, - acctMixerStatus: &win.walletAcctMixerStatus, - selectedProposal: &win.selectedProposal, - proposals: &win.proposals, - syncedProposal: win.proposal, - txAuthor: &win.txAuthor, - broadcastResult: &win.broadcastResult, - signatureResult: &win.signatureResult, - walletTickets: &win.walletTickets, - vspInfo: &win.vspInfo, - unspentOutputs: &win.walletUnspentOutputs, - showModal: win.showModal, - dismissModal: win.dismissModal, - changeWindowPage: win.changePage, + printer: message.NewPrinter(language.English), + multiWallet: win.wallet.GetMultiWallet(), + notificationsUpdate: make(chan interface{}, 10), + wallet: win.wallet, + walletAccount: &win.walletAccount, + info: win.walletInfo, + selectedWallet: &win.selected, + selectedAccount: &win.selectedAccount, + theme: win.theme, + keyEvents: win.keyEvents, + states: &win.states, + icons: ic, + walletSyncStatus: win.walletSyncStatus, + walletTransactions: &win.walletTransactions, + // walletTransaction: &win.walletTransaction, + acctMixerStatus: &win.walletAcctMixerStatus, + selectedProposal: &win.selectedProposal, + proposals: &win.proposals, + syncedProposal: win.proposal, + txAuthor: &win.txAuthor, + broadcastResult: &win.broadcastResult, + signatureResult: &win.signatureResult, + walletTickets: &win.walletTickets, + vspInfo: &win.vspInfo, + unspentOutputs: &win.walletUnspentOutputs, + showModal: win.showModal, + dismissModal: win.dismissModal, + changeWindowPage: win.changePage, + refreshWindow: win.refreshWindow, selectedUTXO: make(map[int]map[int32]map[string]*wallet.UnspentOutput), toast: &win.toast, @@ -320,13 +324,10 @@ func (common *pageCommon) loadPages() map[string]Page { pages := make(map[string]Page) pages[PageWallet] = WalletPage(common) - pages[PageOverview] = OverviewPage(common) - pages[PageTransactions] = TransactionsPage(common) pages[PageMore] = MorePage(common) pages[PageCreateRestore] = CreateRestorePage(common) pages[PageReceive] = ReceivePage(common) pages[PageSend] = SendPage(common) - pages[PageTransactionDetails] = TransactionDetailsPage(common) pages[PageSignMessage] = SignMessagePage(common) pages[PageVerifyMessage] = VerifyMessagePage(common) pages[PageSeedBackup] = BackupPage(common) diff --git a/ui/privacy_page.go b/ui/privacy_page.go index abc4b7d98..d5bd88911 100644 --- a/ui/privacy_page.go +++ b/ui/privacy_page.go @@ -50,6 +50,10 @@ func PrivacyPage(common *pageCommon) Page { return pg } +func (pg *privacyPage) OnResume() { + +} + func (pg *privacyPage) Layout(gtx layout.Context) layout.Dimensions { c := pg.common d := func(gtx C) D { diff --git a/ui/proposal_details_page.go b/ui/proposal_details_page.go index 922d0a25c..2015c50b3 100644 --- a/ui/proposal_details_page.go +++ b/ui/proposal_details_page.go @@ -74,6 +74,10 @@ func ProposalDetailsPage(common *pageCommon) Page { return pg } +func (pg *proposalDetails) OnResume() { + +} + func (pg *proposalDetails) handle() { for token := range pg.proposalItems { for location, clickable := range pg.proposalItems[token].clickables { diff --git a/ui/proposals_page.go b/ui/proposals_page.go index 34e55e10f..b80658a3b 100644 --- a/ui/proposals_page.go +++ b/ui/proposals_page.go @@ -124,6 +124,10 @@ func ProposalsPage(common *pageCommon) Page { return pg } +func (pg *proposalsPage) OnResume() { + +} + func (pg *proposalsPage) handle() { common := pg.common for i := range pg.tabs.tabs { diff --git a/ui/receive_page.go b/ui/receive_page.go index a2aba5a8b..6f8face84 100644 --- a/ui/receive_page.go +++ b/ui/receive_page.go @@ -78,6 +78,10 @@ func ReceivePage(common *pageCommon) Page { return page } +func (pg *receivePage) OnResume() { + +} + func (pg *receivePage) Layout(gtx layout.Context) layout.Dimensions { common := pg.common if pg.gtx == nil { diff --git a/ui/security_tools_page.go b/ui/security_tools_page.go index 7bb77230c..89193d786 100644 --- a/ui/security_tools_page.go +++ b/ui/security_tools_page.go @@ -30,6 +30,10 @@ func SecurityToolsPage(common *pageCommon) Page { return pg } +func (pg *securityToolsPage) OnResume() { + +} + // main settings layout func (pg *securityToolsPage) Layout(gtx layout.Context) layout.Dimensions { common := pg.common diff --git a/ui/seed_backup_page.go b/ui/seed_backup_page.go index a31377f56..729206f6a 100644 --- a/ui/seed_backup_page.go +++ b/ui/seed_backup_page.go @@ -145,6 +145,10 @@ func BackupPage(c *pageCommon) Page { return b } +func (pg *backupPage) OnResume() { + +} + func (pg *backupPage) activeButton() { pg.action.Background = pg.theme.Color.Primary pg.action.Color = pg.theme.Color.InvText diff --git a/ui/send_page.go b/ui/send_page.go index c8e19d343..d4032e34c 100644 --- a/ui/send_page.go +++ b/ui/send_page.go @@ -219,6 +219,10 @@ func SendPage(common *pageCommon) Page { return pg } +func (pg *sendPage) OnResume() { + +} + func (pg *sendPage) Layout(gtx layout.Context) layout.Dimensions { common := pg.common pageContent := []func(gtx C) D{ diff --git a/ui/settings_page.go b/ui/settings_page.go index edcdcb715..cd6ffab46 100644 --- a/ui/settings_page.go +++ b/ui/settings_page.go @@ -122,6 +122,10 @@ func SettingsPage(common *pageCommon) Page { return pg } +func (pg *settingsPage) OnResume() { + +} + func (pg *settingsPage) Layout(gtx layout.Context) layout.Dimensions { common := pg.common pg.updateSettingOptions() diff --git a/ui/sign_message_page.go b/ui/sign_message_page.go index 2a857a59f..fbcb907f9 100644 --- a/ui/sign_message_page.go +++ b/ui/sign_message_page.go @@ -71,6 +71,10 @@ func SignMessagePage(common *pageCommon) Page { return pg } +func (pg *signMessagePage) OnResume() { + +} + func (pg *signMessagePage) Layout(gtx layout.Context) layout.Dimensions { if pg.gtx == nil { pg.gtx = >x diff --git a/ui/statistics_page.go b/ui/statistics_page.go index c4dc10dea..0dcea1c0f 100644 --- a/ui/statistics_page.go +++ b/ui/statistics_page.go @@ -45,6 +45,10 @@ func StatPage(common *pageCommon) Page { return pg } +func (pg *statPage) OnResume() { + +} + func (pg *statPage) layoutStats(gtx C) D { background := pg.common.theme.Color.Surface card := pg.common.theme.Card() diff --git a/ui/tickets_activity_page.go b/ui/tickets_activity_page.go index 53cf0110c..bca59b3eb 100644 --- a/ui/tickets_activity_page.go +++ b/ui/tickets_activity_page.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/planetdecred/dcrlibwallet" "github.com/planetdecred/godcr/wallet" "gioui.org/layout" @@ -25,6 +26,8 @@ type ticketsActivityPage struct { ticketTypeDropDown *decredmaterial.DropDown walletDropDown *decredmaterial.DropDown common *pageCommon + + wallets []*dcrlibwallet.Wallet } func TicketActivityPage(c *pageCommon) Page { @@ -33,6 +36,7 @@ func TicketActivityPage(c *pageCommon) Page { common: c, tickets: c.walletTickets, ticketsList: layout.List{Axis: layout.Vertical}, + wallets: c.multiWallet.AllWallets(), } pg.orderDropDown = createOrderDropDown(c) pg.ticketTypeDropDown = c.theme.DropDown([]decredmaterial.DropDownItem{ @@ -49,9 +53,13 @@ func TicketActivityPage(c *pageCommon) Page { return pg } +func (pg *ticketsActivityPage) OnResume() { + +} + func (pg *ticketsActivityPage) Layout(gtx layout.Context) layout.Dimensions { c := pg.common - c.createOrUpdateWalletDropDown(&pg.walletDropDown) + c.createOrUpdateWalletDropDown(&pg.walletDropDown, pg.wallets) body := func(gtx C) D { page := SubPage{ title: "Ticket activity", @@ -59,7 +67,7 @@ func (pg *ticketsActivityPage) Layout(gtx layout.Context) layout.Dimensions { c.changePage(PageTickets) }, body: func(gtx C) D { - walletID := c.info.Wallets[pg.walletDropDown.SelectedIndex()].ID + walletID := pg.wallets[pg.walletDropDown.SelectedIndex()].ID tickets := (*pg.tickets).Confirmed[walletID] return layout.Stack{Alignment: layout.N}.Layout(gtx, layout.Expanded(func(gtx C) D { @@ -136,13 +144,12 @@ func filterTickets(tickets []wallet.Ticket, f func(string) bool) []wallet.Ticket } func (pg *ticketsActivityPage) handle() { - c := pg.common sortSelection := pg.orderDropDown.SelectedIndex() if pg.filterSorter != sortSelection { pg.filterSorter = sortSelection newestFirst := pg.filterSorter == 0 - for _, wal := range c.info.Wallets { + for _, wal := range pg.wallets { tickets := (*pg.tickets).Confirmed[wal.ID] sort.SliceStable(tickets, func(i, j int) bool { backTime := time.Unix(tickets[j].Info.Ticket.Timestamp, 0) diff --git a/ui/tickets_list_page.go b/ui/tickets_list_page.go index 6858f83b3..c47c1da28 100644 --- a/ui/tickets_list_page.go +++ b/ui/tickets_list_page.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/planetdecred/dcrlibwallet" "github.com/planetdecred/godcr/wallet" "gioui.org/layout" @@ -30,6 +31,8 @@ type ticketPageList struct { isGridView bool common *pageCommon statusTooltips []*decredmaterial.Tooltip + + wallets []*dcrlibwallet.Wallet } func TicketPageList(c *pageCommon) Page { @@ -40,6 +43,8 @@ func TicketPageList(c *pageCommon) Page { ticketsList: layout.List{Axis: layout.Vertical}, toggleViewType: new(widget.Clickable), isGridView: true, + + wallets: c.multiWallet.AllWallets(), } pg.orderDropDown = createOrderDropDown(c) pg.ticketTypeDropDown = c.theme.DropDown([]decredmaterial.DropDownItem{ @@ -56,9 +61,13 @@ func TicketPageList(c *pageCommon) Page { return pg } +func (pg *ticketPageList) OnResume() { + +} + func (pg *ticketPageList) Layout(gtx layout.Context) layout.Dimensions { c := pg.common - c.createOrUpdateWalletDropDown(&pg.walletDropDown) + c.createOrUpdateWalletDropDown(&pg.walletDropDown, pg.wallets) pg.initTicketTooltips(*c) body := func(gtx C) D { @@ -68,7 +77,7 @@ func (pg *ticketPageList) Layout(gtx layout.Context) layout.Dimensions { c.changePage(PageTickets) }, body: func(gtx C) D { - walletID := c.info.Wallets[pg.walletDropDown.SelectedIndex()].ID + walletID := pg.wallets[pg.walletDropDown.SelectedIndex()].ID tickets := (*pg.tickets).Confirmed[walletID] return layout.Stack{Alignment: layout.N}.Layout(gtx, layout.Expanded(func(gtx C) D { @@ -295,7 +304,7 @@ func (pg *ticketPageList) ticketListGridLayout(gtx layout.Context, c *pageCommon } func (pg *ticketPageList) initTicketTooltips(common pageCommon) { - walletID := common.info.Wallets[pg.walletDropDown.SelectedIndex()].ID + walletID := pg.wallets[pg.walletDropDown.SelectedIndex()].ID tickets := (*pg.tickets).Confirmed[walletID] for range tickets { @@ -304,7 +313,6 @@ func (pg *ticketPageList) initTicketTooltips(common pageCommon) { } func (pg *ticketPageList) handle() { - c := pg.common if pg.toggleViewType.Clicked() { pg.isGridView = !pg.isGridView @@ -314,7 +322,7 @@ func (pg *ticketPageList) handle() { if pg.filterSorter != sortSelection { pg.filterSorter = sortSelection newestFirst := pg.filterSorter == 0 - for _, wal := range c.info.Wallets { + for _, wal := range pg.wallets { tickets := (*pg.tickets).Confirmed[wal.ID] sort.SliceStable(tickets, func(i, j int) bool { backTime := time.Unix(tickets[j].Info.Ticket.Timestamp, 0) diff --git a/ui/tickets_page.go b/ui/tickets_page.go index 2c3ab5979..bad1fda16 100644 --- a/ui/tickets_page.go +++ b/ui/tickets_page.go @@ -27,7 +27,7 @@ const PageTickets = "Tickets" type ticketPage struct { th *decredmaterial.Theme wal *wallet.Wallet - vspd *dcrlibwallet.VSPD + vspd *dcrlibwallet.VSP common *pageCommon ticketPageContainer layout.List @@ -119,6 +119,10 @@ func TicketPage(c *pageCommon) Page { return pg } +func (pg *ticketPage) OnResume() { + +} + func (pg *ticketPage) Layout(gtx layout.Context) layout.Dimensions { c := pg.common dims := c.UniformPadding(gtx, func(gtx layout.Context) layout.Dimensions { diff --git a/ui/transaction_details_page.go b/ui/transaction_details_page.go index 2409a6f20..97445cf1a 100644 --- a/ui/transaction_details_page.go +++ b/ui/transaction_details_page.go @@ -13,7 +13,6 @@ import ( "github.com/planetdecred/dcrlibwallet" "github.com/planetdecred/godcr/ui/decredmaterial" "github.com/planetdecred/godcr/ui/values" - "github.com/planetdecred/godcr/wallet" ) const PageTransactionDetails = "TransactionDetails" @@ -24,17 +23,23 @@ type transactionDetailsPage struct { transactionDetailsPageContainer layout.List transactionInputsContainer layout.List transactionOutputsContainer layout.List - txnInfo **wallet.Transaction - hashBtn decredmaterial.Button + hashClickable *widget.Clickable + destAddressClickable *widget.Clickable copyTextBtn []decredmaterial.Button dot *widget.Icon toDcrdata *widget.Clickable outputsCollapsible *decredmaterial.Collapsible inputsCollapsible *decredmaterial.Collapsible gtx *layout.Context + + transaction *dcrlibwallet.Transaction + wallet *dcrlibwallet.Wallet + + txSourceAccount string + txDestinationAddress string } -func TransactionDetailsPage(common *pageCommon) Page { +func TransactionDetailsPage(common *pageCommon, transaction *dcrlibwallet.Transaction) Page { pg := &transactionDetailsPage{ transactionDetailsPageContainer: layout.List{ Axis: layout.Vertical, @@ -46,15 +51,18 @@ func TransactionDetailsPage(common *pageCommon) Page { Axis: layout.Vertical, }, - txnInfo: common.walletTransaction, - theme: common.theme, - common: common, + theme: common.theme, + common: common, outputsCollapsible: common.theme.Collapsible(), inputsCollapsible: common.theme.Collapsible(), - hashBtn: common.theme.Button(new(widget.Clickable), ""), - toDcrdata: new(widget.Clickable), + hashClickable: new(widget.Clickable), + destAddressClickable: new(widget.Clickable), + toDcrdata: new(widget.Clickable), + + transaction: transaction, + wallet: common.multiWallet.WalletWithID(transaction.WalletID), } pg.copyTextBtn = make([]decredmaterial.Button, 0) @@ -62,9 +70,37 @@ func TransactionDetailsPage(common *pageCommon) Page { pg.dot = common.icons.imageBrightness1 pg.dot.Color = common.theme.Color.Gray + // find source account + if transaction.Direction == dcrlibwallet.TxDirectionSent || + transaction.Direction == dcrlibwallet.TxDirectionTransferred { + for _, input := range transaction.Inputs { + if input.AccountNumber != -1 { + accountName, err := pg.wallet.AccountName(input.AccountNumber) + if err != nil { + log.Error(err) + } else { + pg.txSourceAccount = accountName + } + } + } + } + + // find destination address + if transaction.Direction == dcrlibwallet.TxDirectionSent { + for _, output := range transaction.Outputs { + if output.AccountNumber == -1 { + pg.txDestinationAddress = output.Address + } + } + } + return pg } +func (pg *transactionDetailsPage) OnResume() { + +} + func (pg *transactionDetailsPage) Layout(gtx layout.Context) layout.Dimensions { common := pg.common if pg.gtx == nil { @@ -72,7 +108,7 @@ func (pg *transactionDetailsPage) Layout(gtx layout.Context) layout.Dimensions { } body := func(gtx C) D { page := SubPage{ - title: dcrlibwallet.TransactionDirectionName((*pg.txnInfo).Txn.Direction), + title: dcrlibwallet.TransactionDirectionName(pg.transaction.Direction), back: func() { common.changePage(*common.returnPage) }, @@ -91,7 +127,7 @@ func (pg *transactionDetailsPage) Layout(gtx layout.Context) layout.Dimensions { return pg.separator(gtx) }, func(gtx C) D { - return pg.txnInputs(gtx, common) + return pg.txnInputs(gtx) }, func(gtx C) D { return pg.separator(gtx) @@ -103,16 +139,10 @@ func (pg *transactionDetailsPage) Layout(gtx layout.Context) layout.Dimensions { return pg.separator(gtx) }, func(gtx C) D { - if *pg.txnInfo == nil { - return layout.Dimensions{} - } return pg.viewTxn(gtx, common) }, } return common.theme.Card().Layout(gtx, func(gtx C) D { - if *pg.txnInfo == nil { - return layout.Dimensions{} - } return pg.transactionDetailsPageContainer.Layout(gtx, len(widgets), func(gtx C, i int) D { return layout.Inset{}.Layout(gtx, widgets[i]) }) @@ -127,7 +157,7 @@ func (pg *transactionDetailsPage) Layout(gtx layout.Context) layout.Dimensions { } func (pg *transactionDetailsPage) txnBalanceAndStatus(gtx layout.Context, common *pageCommon) layout.Dimensions { - txnWidgets := initTxnWidgets(common, **pg.txnInfo) + txnWidgets := initTxnWidgets(common, pg.transaction) return pg.pageSections(gtx, func(gtx C) D { return layout.Flex{}.Layout(gtx, layout.Rigid(func(gtx C) D { @@ -139,7 +169,7 @@ func (pg *transactionDetailsPage) txnBalanceAndStatus(gtx layout.Context, common layout.Rigid(func(gtx C) D { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { - amount := strings.Split((*pg.txnInfo).Balance, " ") + amount := strings.Split(dcrutil.Amount(pg.transaction.Amount).String(), " ") return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Baseline}.Layout(gtx, layout.Rigid(func(gtx C) D { return layout.Inset{Right: values.MarginPadding2}.Layout(gtx, common.theme.H4(amount[0]).Layout) @@ -167,8 +197,8 @@ func (pg *transactionDetailsPage) txnBalanceAndStatus(gtx layout.Context, common }), layout.Rigid(func(gtx layout.Context) layout.Dimensions { txt := common.theme.Body1("") - if (*pg.txnInfo).Status == "confirmed" { - txt.Text = strings.Title(strings.ToLower((*pg.txnInfo).Status)) + if pg.txConfirmations() > 1 { + txt.Text = strings.Title("confirmed") txt.Color = common.theme.Color.Success } else { txt.Color = common.theme.Color.Gray @@ -186,7 +216,7 @@ func (pg *transactionDetailsPage) txnBalanceAndStatus(gtx layout.Context, common }) }), layout.Rigid(func(gtx C) D { - txt := common.theme.Body1(values.StringF(values.StrNConfirmations, (*pg.txnInfo).Confirmations)) + txt := common.theme.Body1(values.StringF(values.StrNConfirmations, pg.txConfirmations())) txt.Color = common.theme.Color.Gray return txt.Layout(gtx) }), @@ -198,85 +228,100 @@ func (pg *transactionDetailsPage) txnBalanceAndStatus(gtx layout.Context, common }) } +//TODO: do this at startup +func (pg *transactionDetailsPage) txConfirmations() int32 { + transaction := pg.transaction + if transaction.BlockHeight != -1 { + return (pg.common.multiWallet.WalletWithID(transaction.WalletID).GetBestBlock() - transaction.BlockHeight) + 1 + } + + return 0 +} + func (pg *transactionDetailsPage) txnTypeAndID(gtx layout.Context) layout.Dimensions { - transaction := *pg.txnInfo + transaction := pg.transaction return pg.pageSections(gtx, func(gtx C) D { m := values.MarginPadding10 return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { - return pg.txnInfoSection(gtx, values.String(values.StrFrom), transaction.WalletName, transaction.AccountName, true, false) + return pg.txnInfoSection(gtx, values.String(values.StrFrom), pg.txSourceAccount, true, nil) + }), + layout.Rigid(func(gtx C) D { + if transaction.Direction == dcrlibwallet.TxDirectionSent { + return layout.Inset{Top: m}.Layout(gtx, func(gtx C) D { + return pg.txnInfoSection(gtx, values.String(values.StrTo), pg.txDestinationAddress, false, pg.destAddressClickable) + }) + } + return layout.Dimensions{} }), layout.Rigid(func(gtx C) D { return layout.Inset{Bottom: m, Top: m}.Layout(gtx, func(gtx C) D { - return pg.txnInfoSection(gtx, values.String(values.StrFee), "", dcrutil.Amount(transaction.Txn.Fee).String(), false, false) + return pg.txnInfoSection(gtx, values.String(values.StrFee), dcrutil.Amount(transaction.Fee).String(), false, nil) }) }), layout.Rigid(func(gtx C) D { - if transaction.Txn.BlockHeight != -1 { - return pg.txnInfoSection(gtx, values.String(values.StrIncludedInBlock), "", fmt.Sprintf("%d", transaction.Txn.BlockHeight), false, false) + if transaction.BlockHeight != -1 { + return pg.txnInfoSection(gtx, values.String(values.StrIncludedInBlock), fmt.Sprintf("%d", transaction.BlockHeight), false, nil) } return layout.Dimensions{} }), layout.Rigid(func(gtx C) D { return layout.Inset{Bottom: m, Top: m}.Layout(gtx, func(gtx C) D { - return pg.txnInfoSection(gtx, values.String(values.StrType), "", transaction.Txn.Type, false, false) + return pg.txnInfoSection(gtx, values.String(values.StrType), transaction.Type, false, nil) }) }), layout.Rigid(func(gtx C) D { - trimmedHash := transaction.Txn.Hash[:24] + "..." + transaction.Txn.Hash[len(transaction.Txn.Hash)-24:] + trimmedHash := transaction.Hash[:24] + "..." + transaction.Hash[len(transaction.Hash)-24:] return layout.Inset{Bottom: m}.Layout(gtx, func(gtx C) D { - return pg.txnInfoSection(gtx, values.String(values.StrTransactionID), "", trimmedHash, false, true) + return pg.txnInfoSection(gtx, values.String(values.StrTransactionID), trimmedHash, false, pg.hashClickable) }) }), ) }) } -func (pg *transactionDetailsPage) txnInfoSection(gtx layout.Context, t1, t2, t3 string, first, copy bool) layout.Dimensions { +func (pg *transactionDetailsPage) txnInfoSection(gtx layout.Context, label, value string, showWalletBadge bool, clickable *widget.Clickable) layout.Dimensions { gtx.Constraints.Min.X = gtx.Constraints.Max.X return layout.Flex{Spacing: layout.SpaceBetween}.Layout(gtx, layout.Rigid(func(gtx C) D { - t := pg.theme.Body1(t1) + t := pg.theme.Body1(label) t.Color = pg.theme.Color.Gray return t.Layout(gtx) }), layout.Rigid(func(gtx C) D { return layout.Flex{}.Layout(gtx, layout.Rigid(func(gtx C) D { - if t2 != "" { - if first { - card := pg.theme.Card() - card.Radius = decredmaterial.CornerRadius{ - NE: 0, - NW: 0, - SE: 0, - SW: 0, - } - card.Color = pg.theme.Color.LightGray - return card.Layout(gtx, func(gtx C) D { - return layout.UniformInset(values.MarginPadding2).Layout(gtx, func(gtx C) D { - txt := pg.theme.Body2(strings.Title(strings.ToLower(t2))) - txt.Color = pg.theme.Color.Gray - return txt.Layout(gtx) - }) - }) + if showWalletBadge { + card := pg.theme.Card() + card.Radius = decredmaterial.CornerRadius{ + NE: 0, + NW: 0, + SE: 0, + SW: 0, } - return pg.theme.Body1(t2).Layout(gtx) + card.Color = pg.theme.Color.LightGray + return card.Layout(gtx, func(gtx C) D { + return layout.UniformInset(values.MarginPadding2).Layout(gtx, func(gtx C) D { + txt := pg.theme.Body2(pg.wallet.Name) + txt.Color = pg.theme.Color.Gray + return txt.Layout(gtx) + }) + }) } return layout.Dimensions{} }), layout.Rigid(func(gtx C) D { return layout.Inset{Left: values.MarginPadding10}.Layout(gtx, func(gtx C) D { - if first || !copy { - txt := pg.theme.Body1(strings.Title(strings.ToLower(t3))) + if clickable == nil { + txt := pg.theme.Body1(value) return txt.Layout(gtx) } - pg.hashBtn.Color = pg.theme.Color.Primary - pg.hashBtn.Background = color.NRGBA{} - pg.hashBtn.Text = t3 - pg.hashBtn.Inset = layout.UniformInset(values.MarginPadding0) - return pg.hashBtn.Layout(gtx) + btn := pg.theme.Button(clickable, value) + btn.Color = pg.theme.Color.Primary + btn.Background = color.NRGBA{} + btn.Inset = layout.UniformInset(values.MarginPadding0) + return btn.Layout(gtx) }) }), ) @@ -284,22 +329,23 @@ func (pg *transactionDetailsPage) txnInfoSection(gtx layout.Context, t1, t2, t3 ) } -func (pg *transactionDetailsPage) txnInputs(gtx layout.Context, common *pageCommon) layout.Dimensions { - transaction := *pg.txnInfo - x := len(transaction.Txn.Inputs) + len(transaction.Txn.Outputs) +func (pg *transactionDetailsPage) txnInputs(gtx layout.Context) layout.Dimensions { + transaction := pg.transaction + x := len(transaction.Inputs) + len(transaction.Outputs) for i := 0; i < x; i++ { pg.copyTextBtn = append(pg.copyTextBtn, pg.theme.Button(new(widget.Clickable), "")) } collapsibleHeader := func(gtx C) D { - t := pg.theme.Body1(values.StringF(values.StrXInputsConsumed, len(transaction.Txn.Inputs))) + t := pg.theme.Body1(values.StringF(values.StrXInputsConsumed, len(transaction.Inputs))) t.Color = pg.theme.Color.Gray return t.Layout(gtx) } collapsibleBody := func(gtx C) D { - return pg.transactionInputsContainer.Layout(gtx, len(transaction.Txn.Inputs), func(gtx C, i int) D { - return pg.txnIORow(gtx, common, transaction, "INPUT", i) + return pg.transactionInputsContainer.Layout(gtx, len(transaction.Inputs), func(gtx C, i int) D { + input := transaction.Inputs[i] + return pg.txnIORow(gtx, input.Amount, input.AccountNumber, input.PreviousOutpoint, i) }) } return pg.pageSections(gtx, func(gtx C) D { @@ -308,17 +354,19 @@ func (pg *transactionDetailsPage) txnInputs(gtx layout.Context, common *pageComm } func (pg *transactionDetailsPage) txnOutputs(gtx layout.Context, common *pageCommon) layout.Dimensions { - transaction := *pg.txnInfo + transaction := pg.transaction collapsibleHeader := func(gtx C) D { - t := common.theme.Body1(values.StringF(values.StrXOutputCreated, len(transaction.Txn.Outputs))) + t := common.theme.Body1(values.StringF(values.StrXOutputCreated, len(transaction.Outputs))) t.Color = common.theme.Color.Gray return t.Layout(gtx) } collapsibleBody := func(gtx C) D { - return pg.transactionOutputsContainer.Layout(gtx, len(transaction.Txn.Outputs), func(gtx C, i int) D { - return pg.txnIORow(gtx, common, transaction, "OUTPUT", i) + return pg.transactionOutputsContainer.Layout(gtx, len(transaction.Outputs), func(gtx C, i int) D { + output := transaction.Outputs[i] + x := len(transaction.Inputs) + return pg.txnIORow(gtx, output.Amount, output.AccountNumber, output.Address, i+x) }) } return pg.pageSections(gtx, func(gtx C) D { @@ -326,29 +374,20 @@ func (pg *transactionDetailsPage) txnOutputs(gtx layout.Context, common *pageCom }) } -func (pg *transactionDetailsPage) txnIORow(gtx layout.Context, common *pageCommon, transaction *wallet.Transaction, txType string, i int) layout.Dimensions { - - var ( - amount string - accountNumber int32 - hashAcct string - ) +func (pg *transactionDetailsPage) txnIORow(gtx layout.Context, amount int64, acctNum int32, address string, i int) layout.Dimensions { - if txType == "INPUT" { - amount = dcrutil.Amount(transaction.Txn.Inputs[i].Amount).String() - accountNumber = transaction.Txn.Inputs[i].AccountNumber - hashAcct = transaction.Txn.Inputs[i].PreviousOutpoint - } else { - amount = dcrutil.Amount(transaction.Txn.Outputs[i].Amount).String() - accountNumber = transaction.Txn.Outputs[i].AccountNumber - hashAcct = transaction.Txn.Outputs[i].Address - i += len(transaction.Txn.Inputs) + accountName := "external" + walletName := "" + if acctNum != -1 { + name, err := pg.wallet.AccountName(acctNum) + if err == nil { + accountName = name + walletName = pg.wallet.Name + } } - walletID := transaction.Txn.WalletID - accountName := common.wallet.GetAccountName(walletID, accountNumber) - acctName := fmt.Sprintf("(%s)", accountName) - walName := transaction.WalletName + accountName = fmt.Sprintf("(%s)", accountName) + amt := dcrutil.Amount(amount).String() return layout.Inset{Bottom: values.MarginPadding5}.Layout(gtx, func(gtx C) D { card := pg.theme.Card() @@ -359,13 +398,13 @@ func (pg *transactionDetailsPage) txnIORow(gtx layout.Context, common *pageCommo return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { return layout.Flex{}.Layout(gtx, - layout.Rigid(pg.theme.Body1(amount).Layout), + layout.Rigid(pg.theme.Body1(amt).Layout), layout.Rigid(func(gtx C) D { m := values.MarginPadding5 return layout.Inset{ Left: m, Right: m, - }.Layout(gtx, pg.theme.Body1(acctName).Layout) + }.Layout(gtx, pg.theme.Body1(accountName).Layout) }), layout.Rigid(func(gtx C) D { card := pg.theme.Card() @@ -378,7 +417,7 @@ func (pg *transactionDetailsPage) txnIORow(gtx layout.Context, common *pageCommo card.Color = pg.theme.Color.LightGray return card.Layout(gtx, func(gtx C) D { return layout.UniformInset(values.MarginPadding2).Layout(gtx, func(gtx C) D { - txt := pg.theme.Body2(walName) + txt := pg.theme.Body2(walletName) txt.Color = pg.theme.Color.Gray return txt.Layout(gtx) }) @@ -389,7 +428,7 @@ func (pg *transactionDetailsPage) txnIORow(gtx layout.Context, common *pageCommo layout.Rigid(func(gtx C) D { pg.copyTextBtn[i].Color = pg.theme.Color.Primary pg.copyTextBtn[i].Background = color.NRGBA{} - pg.copyTextBtn[i].Text = hashAcct + pg.copyTextBtn[i].Text = address pg.copyTextBtn[i].Inset = layout.UniformInset(values.MarginPadding0) return layout.W.Layout(gtx, pg.copyTextBtn[i].Layout) @@ -429,7 +468,7 @@ func (pg *transactionDetailsPage) handle() { common := pg.common gtx := pg.gtx if pg.toDcrdata.Clicked() { - goToURL(common.wallet.GetBlockExplorerURL((*pg.txnInfo).Txn.Hash)) + goToURL(common.wallet.GetBlockExplorerURL(pg.transaction.Hash)) } for _, b := range pg.copyTextBtn { @@ -438,8 +477,12 @@ func (pg *transactionDetailsPage) handle() { } } - for pg.hashBtn.Button.Clicked() { - clipboard.WriteOp{Text: (*pg.txnInfo).Txn.Hash}.Add(gtx.Ops) + for pg.hashClickable.Clicked() { + clipboard.WriteOp{Text: pg.transaction.Hash}.Add(gtx.Ops) + } + + for pg.destAddressClickable.Clicked() { + clipboard.WriteOp{Text: pg.txDestinationAddress}.Add(gtx.Ops) } } diff --git a/ui/transactions_page.go b/ui/transactions_page.go index 4ddf26251..eace8e781 100644 --- a/ui/transactions_page.go +++ b/ui/transactions_page.go @@ -2,15 +2,11 @@ package ui import ( "image" - "sort" "time" - "gioui.org/f32" "gioui.org/gesture" "gioui.org/io/pointer" "gioui.org/layout" - "gioui.org/op" - "gioui.org/op/paint" "gioui.org/widget" "github.com/planetdecred/dcrlibwallet" @@ -28,31 +24,32 @@ type transactionWdg struct { } type transactionsPage struct { - container layout.Flex - txsList layout.List - walletTransactions **wallet.Transactions - walletTransaction **wallet.Transaction - filterSorter int - filterDirection, filterSort []decredmaterial.RadioButton - toTxnDetails []*gesture.Click - separator decredmaterial.Line - theme *decredmaterial.Theme - common *pageCommon + *pageCommon + pageClosing chan bool + container layout.Flex + txsList layout.List + toTxnDetails []*gesture.Click + separator decredmaterial.Line + theme *decredmaterial.Theme orderDropDown *decredmaterial.DropDown txTypeDropDown *decredmaterial.DropDown walletDropDown *decredmaterial.DropDown + + transactions []dcrlibwallet.Transaction + wallets []*dcrlibwallet.Wallet } func TransactionsPage(common *pageCommon) Page { pg := &transactionsPage{ - common: common, - container: layout.Flex{Axis: layout.Vertical}, - txsList: layout.List{Axis: layout.Vertical}, - walletTransactions: common.walletTransactions, - walletTransaction: common.walletTransaction, - separator: common.theme.Separator(), - theme: common.theme, + pageCommon: common, + pageClosing: make(chan bool, 1), + container: layout.Flex{Axis: layout.Vertical}, + txsList: layout.List{Axis: layout.Vertical}, + separator: common.theme.Separator(), + theme: common.theme, + + wallets: common.multiWallet.AllWallets(), } pg.orderDropDown = createOrderDropDown(common) @@ -77,18 +74,41 @@ func TransactionsPage(common *pageCommon) Page { return pg } +func (pg *transactionsPage) OnResume() { + pg.createOrUpdateWalletDropDown(&pg.walletDropDown, pg.wallets) + pg.listenForTxNotifications() + pg.loadTransactions() +} + +func (pg *transactionsPage) loadTransactions() { + selectedWallet := pg.wallets[pg.walletDropDown.SelectedIndex()] + newestFirst := pg.orderDropDown.SelectedIndex() == 0 + + txFilter := dcrlibwallet.TxFilterAll + switch pg.txTypeDropDown.SelectedIndex() { + case 1: + txFilter = dcrlibwallet.TxFilterSent + case 2: + txFilter = dcrlibwallet.TxFilterReceived + case 3: + txFilter = dcrlibwallet.TxFilterTransferred + case 4: + txFilter = dcrlibwallet.TxFilterStaking + } + + wallTxs, err := selectedWallet.GetTransactionsRaw(0, 0, txFilter, newestFirst) //TODO + if err != nil { + log.Error("Error loading transactions:", err) + } else { + pg.transactions = wallTxs + } +} + func (pg *transactionsPage) Layout(gtx layout.Context) layout.Dimensions { - common := pg.common - common.createOrUpdateWalletDropDown(&pg.walletDropDown) - container := func(gtx C) D { - walletID := common.info.Wallets[pg.walletDropDown.SelectedIndex()].ID - wallTxs := (*pg.walletTransactions).Txs[walletID] - if pg.txTypeDropDown.SelectedIndex()-1 != -1 { - wallTxs = filterTransactions(wallTxs, func(i int) bool { - return i == pg.txTypeDropDown.SelectedIndex()-1 - }) - } + common := pg.pageCommon + container := func(gtx C) D { + wallTxs := pg.transactions return layout.Stack{Alignment: layout.N}.Layout(gtx, layout.Expanded(func(gtx C) D { return layout.Inset{ @@ -116,7 +136,7 @@ func (pg *transactionsPage) Layout(gtx layout.Context) layout.Dimensions { click := pg.toTxnDetails[index] pointer.Rect(image.Rectangle{Max: gtx.Constraints.Max}).Add(gtx.Ops) click.Add(gtx.Ops) - pg.goToTxnDetails(click.Events(gtx), common, &wallTxs[index]) + pg.goToTxnDetails(click.Events(gtx), &wallTxs[index]) var row = TransactionRow{ transaction: wallTxs[index], index: index, @@ -134,16 +154,6 @@ func (pg *transactionsPage) Layout(gtx layout.Context) layout.Dimensions { return common.UniformPadding(gtx, container) } -func filterTransactions(transactions []wallet.Transaction, f func(int) bool) []wallet.Transaction { - t := make([]wallet.Transaction, 0) - for _, v := range transactions { - if f(int(v.Txn.Direction)) { - t = append(t, v) - } - } - return t -} - func (pg *transactionsPage) dropDowns(gtx layout.Context) layout.Dimensions { return layout.Inset{ Bottom: values.MarginPadding10, @@ -169,97 +179,74 @@ func (pg *transactionsPage) dropDowns(gtx layout.Context) layout.Dimensions { }) } -func (pg *transactionsPage) txsFilters(common *pageCommon) layout.Widget { - return func(gtx C) D { - return layout.Inset{ - Top: values.MarginPadding15, - Left: values.MarginPadding15, - Bottom: values.MarginPadding15}.Layout(gtx, func(gtx C) D { - return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, - layout.Rigid(func(gtx C) D { - return (&layout.List{Axis: layout.Horizontal}). - Layout(gtx, len(pg.filterSort), func(gtx C, index int) D { - return layout.Inset{Right: values.MarginPadding15}.Layout(gtx, pg.filterSort[index].Layout) - }) - }), - layout.Rigid(func(gtx C) D { - return layout.Inset{ - Left: values.MarginPadding35, - Right: values.MarginPadding35, - Top: values.MarginPadding5}.Layout(gtx, func(gtx C) D { - dims := image.Point{X: 1, Y: 35} - rect := f32.Rectangle{Max: layout.FPt(dims)} - rect.Size() - op.TransformOp{}.Add(gtx.Ops) - paint.Fill(gtx.Ops, common.theme.Color.Hint) - return layout.Dimensions{Size: dims} - }) - }), - layout.Rigid(func(gtx C) D { - return (&layout.List{Axis: layout.Horizontal}). - Layout(gtx, len(pg.filterDirection), func(gtx C, index int) D { - return layout.Inset{Right: values.MarginPadding15}.Layout(gtx, pg.filterDirection[index].Layout) - }) - }), - ) - }) - } -} - func (pg *transactionsPage) handle() { - common := pg.common - sortSelection := pg.orderDropDown.SelectedIndex() - - if pg.filterSorter != sortSelection { - pg.filterSorter = sortSelection - pg.sortTransactions(common) + for pg.txTypeDropDown.Changed() { + pg.loadTransactions() } -} -func (pg *transactionsPage) sortTransactions(common *pageCommon) { - newestFirst := pg.filterSorter == 0 + for pg.orderDropDown.Changed() { + pg.loadTransactions() + } - for _, wal := range common.info.Wallets { - transactions := (*pg.walletTransactions).Txs[wal.ID] - sort.SliceStable(transactions, func(i, j int) bool { - backTime := time.Unix(transactions[j].Txn.Timestamp, 0) - frontTime := time.Unix(transactions[i].Txn.Timestamp, 0) - if newestFirst { - return backTime.Before(frontTime) - } - return frontTime.Before(backTime) - }) + for pg.walletDropDown.Changed() { + pg.loadTransactions() } } -func (pg *transactionsPage) goToTxnDetails(events []gesture.ClickEvent, common *pageCommon, txn *wallet.Transaction) { +func (pg *transactionsPage) goToTxnDetails(events []gesture.ClickEvent, txn *dcrlibwallet.Transaction) { for _, e := range events { if e.Type == gesture.TypeClick { - *pg.walletTransaction = txn - - common.setReturnPage(PageTransactions) - common.changePage(PageTransactionDetails) + pg.setReturnPage(PageTransactions) + pg.changeFragment(TransactionDetailsPage(pg.pageCommon, txn), "txdetails") } } } -func initTxnWidgets(common *pageCommon, transaction wallet.Transaction) transactionWdg { +func (pg *transactionsPage) listenForTxNotifications() { + go func() { + for { + var notification interface{} + + select { + case notification = <-pg.notificationsUpdate: + case <-pg.pageClosing: + return + } + + switch n := notification.(type) { + case wallet.NewTransaction: + selectedWallet := pg.wallets[pg.walletDropDown.SelectedIndex()] + if selectedWallet.ID == n.Transaction.WalletID { + pg.loadTransactions() + pg.refreshWindow() + } + } + } + }() +} + +func (pg *transactionsPage) onClose() { + pg.pageClosing <- true +} + +func initTxnWidgets(common *pageCommon, transaction *dcrlibwallet.Transaction) transactionWdg { + var txn transactionWdg - t := time.Unix(transaction.Txn.Timestamp, 0).UTC() + t := time.Unix(transaction.Timestamp, 0).UTC() txn.time = common.theme.Body1(t.Format(time.UnixDate)) txn.status = common.theme.Body1("") - txn.wallet = common.theme.Body2(transaction.WalletName) + txn.wallet = common.theme.Body2(common.multiWallet.WalletWithID(transaction.WalletID).Name) - if transaction.Status == "confirmed" { - txn.status.Text = formatDateOrTime(transaction.Txn.Timestamp) + if txConfirmations(common, *transaction) > 1 { + txn.status.Text = formatDateOrTime(transaction.Timestamp) txn.statusIcon = common.icons.confirmIcon } else { - txn.status.Text = transaction.Status + txn.status.Text = "pending" txn.status.Color = common.theme.Color.Gray txn.statusIcon = common.icons.pendingIcon } - if transaction.Txn.Direction == dcrlibwallet.TxDirectionSent { + if transaction.Direction == dcrlibwallet.TxDirectionSent { txn.direction = common.icons.sendIcon } else { txn.direction = common.icons.receiveIcon @@ -267,5 +254,3 @@ func initTxnWidgets(common *pageCommon, transaction wallet.Transaction) transact return txn } - -func (pg *transactionsPage) onClose() {} diff --git a/ui/utxo_page.go b/ui/utxo_page.go index 6da961dc0..ab06f4824 100644 --- a/ui/utxo_page.go +++ b/ui/utxo_page.go @@ -63,6 +63,10 @@ func UTXOPage(common *pageCommon) Page { return pg } +func (pg *utxoPage) OnResume() { + +} + func (pg *utxoPage) handle() { common := pg.common pg.selectedWalletID = common.info.Wallets[*common.selectedWallet].ID diff --git a/ui/validate_address.go b/ui/validate_address.go index 72c504cdd..c9891c45f 100644 --- a/ui/validate_address.go +++ b/ui/validate_address.go @@ -54,6 +54,10 @@ func ValidateAddressPage(common *pageCommon) Page { return pg } +func (pg *validateAddressPage) OnResume() { + +} + func (pg *validateAddressPage) Layout(gtx layout.Context) layout.Dimensions { common := pg.common pg.walletID = common.info.Wallets[*common.selectedWallet].ID diff --git a/ui/verify_message_page.go b/ui/verify_message_page.go index 262a6ca5c..5b57026dc 100644 --- a/ui/verify_message_page.go +++ b/ui/verify_message_page.go @@ -43,6 +43,10 @@ func VerifyMessagePage(c *pageCommon) Page { return pg } +func (pg *verifyMessagePage) OnResume() { + +} + func (pg *verifyMessagePage) Layout(gtx layout.Context) layout.Dimensions { c := pg.common diff --git a/ui/wallet_page.go b/ui/wallet_page.go index 4550bb8b6..dc1f9687a 100644 --- a/ui/wallet_page.go +++ b/ui/wallet_page.go @@ -125,6 +125,10 @@ func WalletPage(common *pageCommon) Page { return pg } +func (pg *walletPage) OnResume() { + +} + func (pg *walletPage) initializeWalletMenu() { pg.optionsMenu = []menuItem{ { diff --git a/ui/wallet_settings_page.go b/ui/wallet_settings_page.go index 10dbd980d..5fc212b29 100644 --- a/ui/wallet_settings_page.go +++ b/ui/wallet_settings_page.go @@ -47,6 +47,10 @@ func WalletSettingsPage(common *pageCommon) Page { return pg } +func (pg *walletSettingsPage) OnResume() { + +} + func (pg *walletSettingsPage) Layout(gtx layout.Context) layout.Dimensions { common := pg.common diff --git a/ui/window.go b/ui/window.go index ccc795f58..74d33197a 100644 --- a/ui/window.go +++ b/ui/window.go @@ -122,6 +122,10 @@ func (win *Window) Start() { func (win *Window) changePage(page Page) { win.currentPage = page + win.refreshWindow() +} + +func (win *Window) refreshWindow() { win.invalidate <- struct{}{} } diff --git a/wallet/commands.go b/wallet/commands.go index 5e904920d..20f0f1bb8 100644 --- a/wallet/commands.go +++ b/wallet/commands.go @@ -1,6 +1,7 @@ package wallet import ( + "context" "crypto/ed25519" "encoding/base64" "encoding/json" @@ -163,18 +164,11 @@ func (wal *Wallet) AddAccount(walletID int, name string, pass []byte, errChan ch func (wal *Wallet) CreateTransaction(walletID int, accountID int32, errChan chan error) { go func() { var resp Response - wall := wal.multi.WalletWithID(walletID) - _, err := wall.GetAccount(accountID) + txAuthor, err := wal.multi.NewUnsignedTx(walletID, accountID) if err != nil { errChan <- err return } - - txAuthor := wal.multi.NewUnsignedTx(wall, accountID) - if txAuthor == nil { - errChan <- err - return - } resp.Resp = txAuthor wal.Send <- resp }() @@ -690,7 +684,7 @@ func (wal *Wallet) GetAllProposals() { } func (wal *Wallet) FetchProposalDescription(token string) (string, error) { - return wal.multi.Politeia.FetchProposalDescription(token) + return wal.multi.Politeia.FetchProposalDescription(dcrlibwallet.PoliteiaMainnetHost, token) } func (wal *Wallet) UnlockWallet(walletID int, passphrase []byte) error { @@ -750,7 +744,7 @@ func (wal *Wallet) CancelSync() { } func (wal *Wallet) SyncProposals() { - go wal.multi.Politeia.Sync() + go wal.multi.Politeia.Sync(dcrlibwallet.PoliteiaMainnetHost) } func (wal *Wallet) IsSyncingProposals() bool { @@ -952,7 +946,7 @@ func (wal *Wallet) TicketPrice() (int64, string) { return pr.TicketPrice, dcrutil.Amount(pr.TicketPrice).String() } -func (wal *Wallet) NewVSPD(host string, walletID int, accountID int32) (*dcrlibwallet.VSPD, error) { +func (wal *Wallet) NewVSPD(host string, walletID int, accountID int32) (*dcrlibwallet.VSP, error) { if host == "" { return nil, fmt.Errorf("Host is required") } @@ -960,15 +954,15 @@ func (wal *Wallet) NewVSPD(host string, walletID int, accountID int32) (*dcrlibw if wall == nil { return nil, ErrIDNotExist } - vspd := wal.multi.NewVSPD(host, walletID, accountID) - if vspd == nil { - return nil, fmt.Errorf("Something wrong when creating new VSPD") + vspd, err := wal.multi.NewVSPClient(host, walletID, uint32(accountID)) + if err != nil { + return nil, fmt.Errorf("Something wrong when creating new VSPD: %v", err) } return vspd, nil } // PurchaseTicket buy a ticket with given parameters -func (wal *Wallet) PurchaseTicket(walletID int, accountID int32, tickets uint32, passphrase []byte, vspd *dcrlibwallet.VSPD, errChan chan error) { +func (wal *Wallet) PurchaseTicket(walletID int, accountID int32, tickets uint32, passphrase []byte, vspd *dcrlibwallet.VSP, errChan chan error) { go func() { var resp Response wall := wal.multi.WalletWithID(walletID) @@ -979,7 +973,7 @@ func (wal *Wallet) PurchaseTicket(walletID int, accountID int32, tickets uint32, return } - _, err := vspd.GetInfo() + _, err := vspd.GetInfo(context.Background()) if err != nil { go func() { errChan <- err @@ -987,15 +981,7 @@ func (wal *Wallet) PurchaseTicket(walletID int, accountID int32, tickets uint32, return } - request := &dcrlibwallet.PurchaseTicketsRequest{ - Account: uint32(accountID), - Passphrase: passphrase, - NumTickets: tickets, - Expiry: uint32(wal.multi.GetBestBlock().Height) + 256, - RequiredConfirmations: dcrlibwallet.DefaultRequiredConfirmations, - } - - hashes, err := wall.PurchaseTickets(request, "") + err = vspd.PurchaseTickets(int32(tickets), wal.multi.GetBestBlock().Height+256, passphrase) if err != nil { go func() { errChan <- err @@ -1003,31 +989,6 @@ func (wal *Wallet) PurchaseTicket(walletID int, accountID int32, tickets uint32, return } - for _, hash := range hashes { - r, err := vspd.GetVSPFeeAddress(hash, passphrase) - if err != nil { - go func() { - errChan <- err - }() - return - } - - transactionResponse, err := vspd.CreateTicketFeeTx(r.FeeAmount, hash, r.FeeAddress, passphrase) - if err != nil { - go func() { - errChan <- err - }() - return - } - _, err = vspd.PayVSPFee(transactionResponse, hash, "", passphrase) - if err != nil { - go func() { - errChan <- err - }() - return - } - } - go func() { errChan <- nil }() @@ -1365,7 +1326,7 @@ func (wal *Wallet) GetRememberVSP() string { } // getVSPInfo returns the information of the specified VSP base URL -func getVSPInfo(url string) (*dcrlibwallet.GetVspInfoResponse, error) { +func getVSPInfo(url string) (*dcrlibwallet.VspInfoResponse, error) { rq := new(http.Client) resp, err := rq.Get((url + "/api/v3/vspinfo")) @@ -1383,7 +1344,7 @@ func getVSPInfo(url string) (*dcrlibwallet.GetVspInfoResponse, error) { return nil, fmt.Errorf("non 200 response from server: %v", string(b)) } - var vspInfoResponse dcrlibwallet.GetVspInfoResponse + var vspInfoResponse dcrlibwallet.VspInfoResponse err = json.Unmarshal(b, &vspInfoResponse) if err != nil { return nil, err @@ -1397,7 +1358,7 @@ func getVSPInfo(url string) (*dcrlibwallet.GetVspInfoResponse, error) { } // getInitVSPInfo returns the list information of the VSP -func getInitVSPInfo(url string) (map[string]*dcrlibwallet.GetVspInfoResponse, error) { +func getInitVSPInfo(url string) (map[string]*dcrlibwallet.VspInfoResponse, error) { rq := new(http.Client) resp, err := rq.Get((url)) if err != nil { @@ -1414,7 +1375,7 @@ func getInitVSPInfo(url string) (map[string]*dcrlibwallet.GetVspInfoResponse, er return nil, fmt.Errorf("non 200 response from server: %v", string(b)) } - var vspInfoResponse map[string]*dcrlibwallet.GetVspInfoResponse + var vspInfoResponse map[string]*dcrlibwallet.VspInfoResponse err = json.Unmarshal(b, &vspInfoResponse) if err != nil { return nil, err diff --git a/wallet/responses.go b/wallet/responses.go index a2a355a18..51e31b0a6 100644 --- a/wallet/responses.go +++ b/wallet/responses.go @@ -235,7 +235,7 @@ type Balance struct { // CreateVSP is sent when the Wallet is done creating a new VSP type VSPInfo struct { Host string - Info *dcrlibwallet.GetVspInfoResponse + Info *dcrlibwallet.VspInfoResponse } // VSP is sent when the Wallet is done getting all VSP info diff --git a/wallet/txlistener.go b/wallet/txlistener.go index ff3d79030..8c47d54ce 100644 --- a/wallet/txlistener.go +++ b/wallet/txlistener.go @@ -1,7 +1,6 @@ package wallet -// NewTransaction is sent when a new transaction is received. -type NewTransaction string +import "github.com/planetdecred/dcrlibwallet" // NewBlock is sent when a block is attached to the multiwallet. type NewBlock struct { @@ -16,6 +15,10 @@ type TxConfirmed struct { Hash string } +type NewTransaction struct { + Transaction *dcrlibwallet.Transaction +} + func (l *listener) OnTransaction(transaction string) { l.Send <- SyncStatusUpdate{} } diff --git a/wallet/wallet.go b/wallet/wallet.go index a1f149945..d3766fb39 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -71,7 +71,7 @@ func (wal *Wallet) SetupListeners() { return } - wal.multi.SetAccountMixerNotification(l) + wal.multi.AddAccountMixerNotificationListener(l, syncID) wal.multi.Politeia.AddNotificationListener(l, syncID) @@ -117,7 +117,7 @@ func (wal *Wallet) LoadWallets() { return } - wal.multi.SetAccountMixerNotification(l) + wal.multi.AddAccountMixerNotificationListener(l, syncID) wal.multi.Politeia.AddNotificationListener(l, syncID)