diff --git a/pages/wallet_select/select_wallet.go b/pages/wallet_select/select_wallet.go index 33eab75..9b0c27b 100644 --- a/pages/wallet_select/select_wallet.go +++ b/pages/wallet_select/select_wallet.go @@ -18,6 +18,7 @@ import ( "github.com/g45t345rt/g45w/animation" "github.com/g45t345rt/g45w/app_instance" "github.com/g45t345rt/g45w/components" + "github.com/g45t345rt/g45w/containers/confirm_modal" "github.com/g45t345rt/g45w/containers/notification_modals" "github.com/g45t345rt/g45w/containers/password_modal" "github.com/g45t345rt/g45w/lang" @@ -116,11 +117,10 @@ func (p *PageSelectWallet) Leave() { } func (p *PageSelectWallet) Load() { - wallets := wallet_manager.Wallets items := make([]WalletListItem, 0) - for _, wallet := range wallets { + for _, walletInfo := range wallet_manager.Wallets { items = append(items, - NewWalletListItem(wallet), + NewWalletListItem(walletInfo), ) } @@ -128,6 +128,12 @@ func (p *PageSelectWallet) Load() { return items[i].wallet.Timestamp < items[j].wallet.Timestamp }) + for addr, err := range wallet_manager.WalletsErr { + items = append(items, + NewWalletListItemErr(err, addr), + ) + } + p.walletList.items = items } @@ -165,8 +171,27 @@ func (p *PageSelectWallet) Layout(gtx layout.Context, th *material.Theme) layout } else { for _, item := range p.walletList.items { if item.Clickable.Clicked() { - p.currentWallet = item.wallet - password_modal.Instance.SetVisible(true) + if item.wallet != nil { + p.currentWallet = item.wallet + password_modal.Instance.SetVisible(true) + } else { + go func() { + yesChan := confirm_modal.Instance.Open(confirm_modal.ConfirmText{ + Prompt: lang.Translate("Delete wallet?"), + }) + + for yes := range yesChan { + if yes { + err := wallet_manager.DeleteWallet(item.addr) + if err == nil { + notification_modals.ErrorInstance.SetText("Error", err.Error()) + notification_modals.ErrorInstance.SetVisible(true, notification_modals.CLOSE_AFTER_DEFAULT) + p.Load() + } + } + } + }() + } } } @@ -369,6 +394,8 @@ type WalletListItem struct { wallet *wallet_manager.WalletInfo Clickable *widget.Clickable rounded unit.Dp + err error + addr string } func NewWalletListItem(wallet *wallet_manager.WalletInfo) WalletListItem { @@ -379,25 +406,54 @@ func NewWalletListItem(wallet *wallet_manager.WalletInfo) WalletListItem { } } +func NewWalletListItemErr(err error, addr string) WalletListItem { + return WalletListItem{ + Clickable: &widget.Clickable{}, + rounded: unit.Dp(12), + err: err, + addr: addr, + } +} + func (item *WalletListItem) Layout(gtx layout.Context, th *material.Theme) layout.Dimensions { return item.Clickable.Layout(gtx, func(gtx layout.Context) layout.Dimensions { dims := layout.UniformInset(item.rounded).Layout(gtx, func(gtx layout.Context) layout.Dimensions { return layout.Flex{Alignment: layout.Start}.Layout(gtx, layout.Flexed(1, func(gtx layout.Context) layout.Dimensions { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - name := fmt.Sprintf("%s [%s]", lang.Translate("Wallet"), item.wallet.Name) - lbl := material.Label(th, unit.Sp(18), name) - lbl.Font.Weight = font.Bold - return lbl.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - addr := utils.ReduceAddr(item.wallet.Addr) - lbl := material.Label(th, unit.Sp(15), addr) - lbl.Color = theme.Current.TextMuteColor - return lbl.Layout(gtx) - }), - ) + if item.err != nil { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + addr := utils.ReduceAddr(item.addr) + lbl := material.Label(th, unit.Sp(18), addr) + lbl.Font.Weight = font.Bold + return lbl.Layout(gtx) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + lbl := material.Label(th, unit.Sp(11), item.err.Error()) + lbl.Color = theme.Current.TextMuteColor + return lbl.Layout(gtx) + }), + ) + } + + if item.wallet != nil { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + name := fmt.Sprintf("%s [%s]", lang.Translate("Wallet"), item.wallet.Name) + lbl := material.Label(th, unit.Sp(18), name) + lbl.Font.Weight = font.Bold + return lbl.Layout(gtx) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + addr := utils.ReduceAddr(item.wallet.Addr) + lbl := material.Label(th, unit.Sp(15), addr) + lbl.Color = theme.Current.TextMuteColor + return lbl.Layout(gtx) + }), + ) + } + + return layout.Dimensions{} }), ) }) diff --git a/wallet_manager/wallet.go b/wallet_manager/wallet.go index 50384ca..a6d11da 100644 --- a/wallet_manager/wallet.go +++ b/wallet_manager/wallet.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "io" "io/fs" "math" "math/rand" @@ -44,22 +45,20 @@ type WalletInfo struct { } var Wallets map[string]*WalletInfo +var WalletsErr map[string]error var OpenedWallet *Wallet func Load() error { walletsDir := settings.WalletsDir Wallets = make(map[string]*WalletInfo) + WalletsErr = make(map[string]error) err := os.MkdirAll(walletsDir, os.ModePerm) if err != nil { return err } - return filepath.Walk(walletsDir, func(path string, info fs.FileInfo, err error) error { - if err != nil { - return err - } - + filepath.Walk(walletsDir, func(path string, info fs.FileInfo, fileErr error) error { if walletsDir == path { return nil } @@ -67,23 +66,32 @@ func Load() error { if info.IsDir() { addr := info.Name() - path := filepath.Join(walletsDir, addr, "info.json") - data, err := os.ReadFile(path) + _, err := globals.ParseValidateAddress(addr) if err != nil { - return err + return nil + } + + fileInfo := filepath.Join(walletsDir, addr, "info.json") + data, err := os.ReadFile(fileInfo) + if err != nil { + WalletsErr[addr] = err + return nil } walletInfo := &WalletInfo{} err = json.Unmarshal(data, walletInfo) if err != nil { - return err + WalletsErr[addr] = err + return nil } - Wallets[walletInfo.Addr] = walletInfo + Wallets[addr] = walletInfo } return nil }) + + return nil } func CloseOpenedWallet() { @@ -98,18 +106,53 @@ func CloseOpenedWallet() { } } +func GetWallet(addr string) (*WalletInfo, error) { + for _, walletInfo := range Wallets { + if walletInfo.Addr == addr { + return walletInfo, nil + } + } + + return nil, fmt.Errorf("wallet [%s] not found", addr) +} + func OpenWallet(addr string, password string) error { - info, ok := Wallets[addr] - if !ok { - return fmt.Errorf("wallet [%s] does not exists", addr) + walletInfo, err := GetWallet(addr) + if err != nil { + return err } walletsDir := settings.WalletsDir walletPath := filepath.Join(walletsDir, addr, "wallet.db") + bkCopied := false +open_wallet: memory, err := walletapi.Open_Encrypted_Wallet(walletPath, password) if err != nil { - return err + if bkCopied { + return err + } + + // maybe the wallet file is corrupt or does not exists + // we will try to use backup file and copy as last resort + walletBkPath := filepath.Join(walletsDir, addr, "wallet.db.bak") + bkFile, err := os.Open(walletBkPath) + if err != nil { + return err + } + + walletFile, err := os.Create(walletPath) + if err != nil { + return err + } + + _, err = io.Copy(walletFile, bkFile) + if err != nil { + return err + } + + bkCopied = true + goto open_wallet } memory.SetNetwork(globals.IsMainnet()) @@ -148,7 +191,7 @@ func OpenWallet(addr string, password string) error { } wallet := &Wallet{ - Info: info, + Info: walletInfo, Memory: memory, DB: db, } @@ -521,9 +564,13 @@ func (w *Wallet) CalculateTxFees(sizeInBytes uint64) (fees uint64) { func StoreRegistrationTx(addr string, tx *transaction.Transaction) error { txHex := hex.EncodeToString(tx.Serialize()) - wallet := Wallets[addr] - wallet.RegistrationTxHex = txHex - return saveWalletInfo(addr, wallet) + walletInfo, err := GetWallet(addr) + if err != nil { + return err + } + + walletInfo.RegistrationTxHex = txHex + return saveWalletInfo(addr, walletInfo) } func saveWallet(wallet *walletapi.Wallet_Memory, name string) error { @@ -563,8 +610,8 @@ func saveWalletInfo(addr string, walletInfo *WalletInfo) error { return err } - path = filepath.Join(walletsDir, addr, "info.json") - err = os.WriteFile(path, data, fs.ModePerm) + infoPath := filepath.Join(walletsDir, addr, "info.json") + err = os.WriteFile(infoPath, data, fs.ModePerm) if err != nil { return err }