account changing barely working

This commit is contained in:
fosse 2023-08-10 18:34:20 -04:00
parent c0a8ddbf73
commit 181ca98688
20 changed files with 830 additions and 123 deletions

View file

@ -0,0 +1,22 @@
import 'package:hive/hive.dart';
part 'nano_account.g.dart';
@HiveType(typeId: NanoAccount.typeId)
class NanoAccount extends HiveObject {
NanoAccount({required this.label, required this.id, this.balance, this.isSelected = false});
static const typeId = 13;
@HiveField(0)
String label;
@HiveField(1)
final int id;
@HiveField(2)
bool isSelected;
@HiveField(3)
String? balance;
}

View file

@ -7,77 +7,77 @@ import 'package:cw_nano/api/structs/account_row.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_nano/api/wallet.dart';
final accountSizeNative = moneroApi
.lookup<NativeFunction<account_size>>('account_size')
.asFunction<SubaddressSize>();
// final accountSizeNative = moneroApi
// .lookup<NativeFunction<account_size>>('account_size')
// .asFunction<SubaddressSize>();
final accountRefreshNative = moneroApi
.lookup<NativeFunction<account_refresh>>('account_refresh')
.asFunction<AccountRefresh>();
// final accountRefreshNative = moneroApi
// .lookup<NativeFunction<account_refresh>>('account_refresh')
// .asFunction<AccountRefresh>();
final accountGetAllNative = moneroApi
.lookup<NativeFunction<account_get_all>>('account_get_all')
.asFunction<AccountGetAll>();
// final accountGetAllNative = moneroApi
// .lookup<NativeFunction<account_get_all>>('account_get_all')
// .asFunction<AccountGetAll>();
final accountAddNewNative = moneroApi
.lookup<NativeFunction<account_add_new>>('account_add_row')
.asFunction<AccountAddNew>();
// final accountAddNewNative = moneroApi
// .lookup<NativeFunction<account_add_new>>('account_add_row')
// .asFunction<AccountAddNew>();
final accountSetLabelNative = moneroApi
.lookup<NativeFunction<account_set_label>>('account_set_label_row')
.asFunction<AccountSetLabel>();
// final accountSetLabelNative = moneroApi
// .lookup<NativeFunction<account_set_label>>('account_set_label_row')
// .asFunction<AccountSetLabel>();
bool isUpdating = false;
void refreshAccounts() {
try {
isUpdating = true;
accountRefreshNative();
isUpdating = false;
} catch (e) {
isUpdating = false;
rethrow;
}
// try {
// isUpdating = true;
// accountRefreshNative();
// isUpdating = false;
// } catch (e) {
// isUpdating = false;
// rethrow;
// }
}
List<AccountRow> getAllAccount() {
final size = accountSizeNative();
final accountAddressesPointer = accountGetAllNative();
final accountAddresses = accountAddressesPointer.asTypedList(size);
// final size = accountSizeNative();
// final accountAddressesPointer = accountGetAllNative();
// final accountAddresses = accountAddressesPointer.asTypedList(size);
return accountAddresses
.map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
.toList();
// return accountAddresses
// .map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
// .toList();
return [];
}
void addAccountSync({required String label}) {
final labelPointer = label.toNativeUtf8();
accountAddNewNative(labelPointer);
calloc.free(labelPointer);
// final labelPointer = label.toNativeUtf8();
// accountAddNewNative(labelPointer);
// calloc.free(labelPointer);
}
void setLabelForAccountSync({required int accountIndex, required String label}) {
final labelPointer = label.toNativeUtf8();
accountSetLabelNative(accountIndex, labelPointer);
calloc.free(labelPointer);
// final labelPointer = label.toNativeUtf8();
// accountSetLabelNative(accountIndex, labelPointer);
// calloc.free(labelPointer);
}
void _addAccount(String label) => addAccountSync(label: label);
void _setLabelForAccount(Map<String, dynamic> args) {
final label = args['label'] as String;
final accountIndex = args['accountIndex'] as int;
// final label = args['label'] as String;
// final accountIndex = args['accountIndex'] as int;
setLabelForAccountSync(label: label, accountIndex: accountIndex);
// setLabelForAccountSync(label: label, accountIndex: accountIndex);
}
Future<void> addAccount({required String label}) async {
await compute(_addAccount, label);
await store();
// await compute(_addAccount, label);
// await store();
}
Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
await compute(
_setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
await store();
}
// await compute(_setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
// await store();
}

View file

@ -1,34 +1,36 @@
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/nano_account.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/account.dart';
import 'package:cw_nano/api/account_list.dart' as account_list;
import 'package:hive/hive.dart';
part 'nano_account_list.g.dart';
class NanoAccountList = NanoAccountListBase with _$NanoAccountList;
abstract class NanoAccountListBase with Store {
NanoAccountListBase()
: accounts = ObservableList<Account>(),
NanoAccountListBase(this.address)
: accounts = ObservableList<NanoAccount>(),
_isRefreshing = false,
_isUpdating = false {
// refresh();
refresh();
}
@observable
ObservableList<Account> accounts;
ObservableList<NanoAccount> accounts;
bool _isRefreshing;
bool _isUpdating;
void update() async {
String address;
Future<void> update() async {
if (_isUpdating) {
return;
}
try {
_isUpdating = true;
refresh();
final accounts = getAll();
// refresh();
print(this.address);
final accounts = await getAll();
if (accounts.isNotEmpty) {
this.accounts.clear();
@ -42,39 +44,26 @@ abstract class NanoAccountListBase with Store {
}
}
List<Account> getAll() => account_list.getAllAccount().map((accountRow) {
final accountIndex = accountRow.getId();
Future<List<NanoAccount>> getAll() async {
final box = await Hive.openBox<NanoAccount>(address);
return Account(
id: accountRow.getId(),
label: accountRow.getLabel(),
balance: "01",
);
}).toList();
// get all accounts in box:
return box.values.toList();
}
Future<void> addAccount({required String label}) async {
await account_list.addAccount(label: label);
update();
final box = await Hive.openBox<NanoAccount>(address);
final account = NanoAccount(id: box.length, label: label, balance: "0.00", isSelected: false);
await box.add(account);
await account.save();
}
Future<void> setLabelAccount({required int accountIndex, required String label}) async {
await account_list.setLabelForAccount(accountIndex: accountIndex, label: label);
update();
final box = await Hive.openBox<NanoAccount>(address);
final account = box.getAt(accountIndex);
account!.label = label;
await account.save();
}
void refresh() {
if (_isRefreshing) {
return;
}
try {
_isRefreshing = true;
account_list.refreshAccounts();
_isRefreshing = false;
} catch (e) {
_isRefreshing = false;
print(e);
rethrow;
}
}
void refresh() {}
}

View file

@ -0,0 +1,91 @@
import 'package:cw_nano/api/structs/subaddress_row.dart';
import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_nano/api/subaddress_list.dart' as subaddress_list;
import 'package:cw_core/subaddress.dart';
part 'nano_subaddress_list.g.dart';
class NanoSubaddressList = NanoSubaddressListBase
with _$NanoSubaddressList;
abstract class NanoSubaddressListBase with Store {
NanoSubaddressListBase()
: _isRefreshing = false,
_isUpdating = false,
subaddresses = ObservableList<Subaddress>();
@observable
ObservableList<Subaddress> subaddresses;
bool _isRefreshing;
bool _isUpdating;
void update({required int accountIndex}) {
if (_isUpdating) {
return;
}
try {
_isUpdating = true;
refresh(accountIndex: accountIndex);
subaddresses.clear();
subaddresses.addAll(getAll());
_isUpdating = false;
} catch (e) {
_isUpdating = false;
rethrow;
}
}
List<Subaddress> getAll() {
var subaddresses = subaddress_list.getAllSubaddresses();
if (subaddresses.length > 2) {
final primary = subaddresses.first;
final rest = subaddresses.sublist(1).reversed;
subaddresses = [primary] + rest.toList();
}
return [];
// return subaddresses
// .map((subaddressRow) => Subaddress(
// id: subaddressRow.getId(),
// address: subaddressRow.getAddress(),
// label: subaddressRow.getId() == 0 &&
// subaddressRow.getLabel().toLowerCase() == 'Primary account'.toLowerCase()
// ? 'Primary address'
// : subaddressRow.getLabel()))
// .toList();
}
Future<void> addSubaddress({required int accountIndex, required String label}) async {
await subaddress_list.addSubaddress(
accountIndex: accountIndex, label: label);
update(accountIndex: accountIndex);
}
Future<void> setLabelSubaddress(
{required int accountIndex, required int addressIndex, required String label}) async {
await subaddress_list.setLabelForSubaddress(
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
update(accountIndex: accountIndex);
}
void refresh({required int accountIndex}) {
if (_isRefreshing) {
return;
}
try {
_isRefreshing = true;
subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
_isRefreshing = false;
} on PlatformException catch (e) {
_isRefreshing = false;
print(e);
rethrow;
}
}
}

View file

@ -11,6 +11,7 @@ import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_nano/file.dart';
import 'package:cw_core/nano_account.dart';
import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_client.dart';
import 'package:cw_nano/nano_transaction_credentials.dart';
@ -21,6 +22,7 @@ import 'package:cw_nano/nano_wallet_info.dart';
import 'package:cw_nano/nano_wallet_keys.dart';
import 'package:cw_nano/pending_nano_transaction.dart';
import 'package:mobx/mobx.dart';
import 'package:hive/hive.dart';
import 'dart:async';
import 'package:cw_nano/nano_wallet_addresses.dart';
import 'package:cw_core/wallet_base.dart';
@ -53,6 +55,9 @@ abstract class NanoWalletBase
super(walletInfo) {
this.walletInfo = walletInfo;
transactionHistory = NanoTransactionHistory(walletInfo: walletInfo, password: password);
if (!Hive.isAdapterRegistered(NanoAccount.typeId)) {
Hive.registerAdapter(NanoAccountAdapter());
}
}
final String _mnemonic;
@ -70,7 +75,7 @@ abstract class NanoWalletBase
bool _isTransactionUpdating;
@override
WalletAddresses walletAddresses;
NanoWalletAddresses walletAddresses;
@override
@observable
@ -134,7 +139,7 @@ abstract class NanoWalletBase
}
}
@override
@override
Future<void> connectToPowNode({required Node node}) async {
_client.connectPow(node);
}
@ -242,7 +247,9 @@ abstract class NanoWalletBase
id: transactionModel.hash,
amountRaw: transactionModel.amount,
height: transactionModel.height,
direction: transactionModel.type == "send" ? TransactionDirection.outgoing : TransactionDirection.incoming,
direction: transactionModel.type == "send"
? TransactionDirection.outgoing
: TransactionDirection.incoming,
confirmed: transactionModel.confirmed,
date: transactionModel.date ?? DateTime.now(),
confirmations: transactionModel.confirmed ? 1 : 0,
@ -365,6 +372,17 @@ abstract class NanoWalletBase
}
}
Future<void> regenerateAddress() async {
final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd";
_privateKey =
await NanoUtil.uniSeedToPrivate(_seedKey!, this.walletAddresses.account!.id, type);
_publicAddress =
await NanoUtil.uniSeedToAddress(_seedKey!, this.walletAddresses.account!.id, type);
this.walletInfo.address = _publicAddress!;
this.walletAddresses.address = _publicAddress!;
}
Future<void> changeRep(String address) async {
try {
final String hash = await _client.changeRep(

View file

@ -1,9 +1,11 @@
import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/account.dart';
import 'package:cw_core/nano_account.dart';
import 'package:cw_nano/nano_account_list.dart';
import 'package:cw_core/subaddress.dart';
// import 'package:cw_core/account.dart';
// import 'package:cw_core/subaddress.dart';
import 'package:mobx/mobx.dart';
import 'package:hive/hive.dart';
part 'nano_wallet_addresses.g.dart';
@ -11,26 +13,46 @@ class NanoWalletAddresses = NanoWalletAddressesBase with _$NanoWalletAddresses;
abstract class NanoWalletAddressesBase extends WalletAddresses with Store {
NanoWalletAddressesBase(WalletInfo walletInfo)
: address = '',
: accountList = NanoAccountList(walletInfo.address),
address = '',
super(walletInfo);
@override
@observable
String address;
@observable
NanoAccount? account;
// NanoSubaddressList subaddressList;
NanoAccountList accountList;
@override
Future<void> init() async {
var box = await Hive.openBox<NanoAccount>(walletInfo.address);
try {
box.getAt(0);
} catch (e) {
box.add(NanoAccount(id: 0, label: "Primary Account", balance: "0"));
}
await accountList.update();
print("####################");
print(accountList.accounts);
account = accountList.accounts.first;
address = walletInfo.address;
await updateAddressesInBox();
}
@override
Future<void> updateAddressesInBox() async {
try {
addressesMap.clear();
addressesMap[address] = '';
await saveAddressesInBox();
} catch (e) {
print(e.toString());
}
// try {
// addressesMap.clear();
// addressesMap[address] = '';
// await saveAddressesInBox();
// } catch (e) {
// print(e.toString());
// }
}
}
}

View file

@ -23,6 +23,8 @@ import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart';
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_list_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
@ -69,6 +71,8 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
import 'package:cake_wallet/view_model/node_list/pow_node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
@ -82,6 +86,7 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_i
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cw_core/erc20_token.dart';
import 'package:cw_core/nano_account.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/core/backup_service.dart';
import 'package:cw_core/wallet_service.dart';
@ -207,6 +212,7 @@ import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/entities/qr_view_data.dart';
import 'package:cake_wallet/nano/nano.dart' as nanoNano;
import 'core/totp_request_details.dart';
@ -609,20 +615,45 @@ Future setup({
editingWallet: editingWallet);
});
// getIt.registerFactory(() {
// final wallet = getIt.get<AppStore>().wallet!;
// if (wallet.type == WalletType.monero || wallet.type == WalletType.haven) {
// return MoneroAccountListViewModel(wallet);
// }
// if (wallet.type == WalletType.nano || wallet.type == WalletType.banano) {
// return NanoAccountListViewModel(wallet);
// }
// throw Exception(
// 'Unexpected wallet type: ${wallet.type} for generate Nano/Monero AccountListViewModel');
// });
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet!;
if (wallet.type == WalletType.nano || wallet.type == WalletType.banano) {
return NanoAccountListViewModel(wallet);
}
throw Exception(
'Unexpected wallet type: ${wallet.type} for generate Nano/Monero AccountListViewModel');
});
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet!;
if (wallet.type == WalletType.monero || wallet.type == WalletType.haven) {
return MoneroAccountListViewModel(wallet);
}
throw Exception(
'Unexpected wallet type: ${wallet.type} for generate MoneroAccountListViewModel');
'Unexpected wallet type: ${wallet.type} for generate Nano/Monero AccountListViewModel');
});
getIt.registerFactory(
() => MoneroAccountListPage(accountListViewModel: getIt.get<MoneroAccountListViewModel>()));
getIt.registerFactory(
() => NanoAccountListPage(accountListViewModel: getIt.get<NanoAccountListViewModel>()));
/*getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;
@ -650,6 +681,18 @@ Future setup({
moneroAccountCreationViewModel:
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
getIt.registerFactoryParam<NanoAccountEditOrCreateViewModel, NanoAccount?, void>(
(NanoAccount? account, _) =>
NanoAccountEditOrCreateViewModel(nano!.getAccountList(getIt.get<AppStore>().wallet!),
// banano?.getAccountList(getIt.get<AppStore>().wallet!),
wallet: getIt.get<AppStore>().wallet!,
accountListItem: account));
getIt.registerFactoryParam<NanoAccountEditOrCreatePage, NanoAccount?, void>(
(NanoAccount? account, _) => NanoAccountEditOrCreatePage(
nanoAccountCreationViewModel:
getIt.get<NanoAccountEditOrCreateViewModel>(param1: account)));
getIt.registerFactory(() {
return DisplaySettingsViewModel(getIt.get<SettingsStore>());
});

View file

@ -1,6 +1,74 @@
part of 'nano.dart';
class CWNanoAccountList extends NanoAccountList {
CWNanoAccountList(this._wallet);
final Object _wallet;
@override
@computed
ObservableList<NanoAccount> get accounts {
final nanoWallet = _wallet as NanoWallet;
final accounts = nanoWallet.walletAddresses.accountList.accounts
.map((acc) => NanoAccount(id: acc.id, label: acc.label, balance: acc.balance))
.toList();
return ObservableList<NanoAccount>.of(accounts);
}
@override
void update(Object wallet) {
final nanoWallet = wallet as NanoWallet;
nanoWallet.walletAddresses.accountList.update();
}
@override
void refresh(Object wallet) {
final nanoWallet = wallet as NanoWallet;
nanoWallet.walletAddresses.accountList.refresh();
}
@override
Future<List<NanoAccount>> getAll(Object wallet) async {
final nanoWallet = wallet as NanoWallet;
return (await nanoWallet.walletAddresses.accountList.getAll())
.map((acc) => NanoAccount(id: acc.id, label: acc.label, balance: acc.balance))
.toList();
}
@override
Future<void> addAccount(Object wallet, {required String label}) async {
final nanoWallet = wallet as NanoWallet;
await nanoWallet.walletAddresses.accountList.addAccount(label: label);
}
@override
Future<void> setLabelAccount(Object wallet,
{required int accountIndex, required String label}) async {
final nanoWallet = wallet as NanoWallet;
await nanoWallet.walletAddresses.accountList
.setLabelAccount(accountIndex: accountIndex, label: label);
}
}
class CWNano extends Nano {
@override
NanoAccountList getAccountList(Object wallet) {
return CWNanoAccountList(wallet);
}
@override
Account getCurrentAccount(Object wallet) {
final nanoWallet = wallet as NanoWallet;
final acc = nanoWallet.walletAddresses.account;
return Account(id: acc!.id, label: acc.label, balance: acc.balance);
}
@override
void setCurrentAccount(Object wallet, int id, String label, String? balance) {
final nanoWallet = wallet as NanoWallet;
nanoWallet.walletAddresses.account = NanoAccount(id: id, label: label, balance: balance);
nanoWallet.regenerateAddress();
}
@override
List<String> getNanoWordList(String language) {
return NanoMnemomics.WORDLIST;
@ -73,4 +141,12 @@ class CWNano extends Nano {
.toList(),
);
}
@override
Future<void> setLabelAccount(Object wallet,
{required int accountIndex, required String label}) async {
final nanoWallet = wallet as NanoWallet;
await nanoWallet.walletAddresses.accountList
.setLabelAccount(accountIndex: accountIndex, label: label);
}
}

View file

@ -1,4 +1,4 @@
import 'package:cw_core/nano_account.dart';
import 'package:cw_nano/nano_mnemonic.dart';
import 'package:cw_nano/nano_wallet.dart';
import 'package:cw_nano/nano_wallet_service.dart';
@ -12,9 +12,6 @@ import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/output_info.dart';
import 'package:hive/hive.dart';
import 'package:cw_nano/api/wallet.dart' as nano_wallet_api;
import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_wallet_creation_credentials.dart';
import 'package:cw_nano/nano_transaction_credentials.dart';
part 'cw_nano.dart';
@ -22,7 +19,11 @@ part 'cw_nano.dart';
Nano? nano = CWNano();
abstract class Nano {
// NanoAccountList getAccountList(Object wallet);
NanoAccountList getAccountList(Object wallet);
Account getCurrentAccount(Object wallet);
void setCurrentAccount(Object wallet, int id, String label, String? balance);
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource);
@ -32,7 +33,7 @@ abstract class Nano {
required String name,
String password,
});
WalletCredentials createNanoRestoreWalletFromSeedCredentials({
required String name,
required String password,
@ -50,11 +51,10 @@ abstract class Nano {
}
abstract class NanoAccountList {
ObservableList<Account> get accounts;
ObservableList<NanoAccount> get accounts;
void update(Object wallet);
void refresh(Object wallet);
List<Account> getAll(Object wallet);
Future<List<NanoAccount>> getAll(Object wallet);
Future<void> addAccount(Object wallet, {required String label});
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label});
}

View file

@ -13,6 +13,7 @@ import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart';
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
@ -52,6 +53,7 @@ import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/nano_account.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
@ -330,6 +332,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => getIt.get<MoneroAccountEditOrCreatePage>(
param1: settings.arguments as AccountListItem?));
case Routes.nanoAccountCreation:
return CupertinoPageRoute<String>(
builder: (_) => getIt.get<NanoAccountEditOrCreatePage>(
param1: settings.arguments as NanoAccount?));
case Routes.addressBook:
return MaterialPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<ContactListPage>());

View file

@ -22,6 +22,7 @@ class Routes {
static const login = '/login';
static const splash = '/splash';
static const accountCreation = '/account_new';
static const nanoAccountCreation = '/nano_account_new';
static const addressBook = '/address_book';
static const pickerAddressBook = '/picker_address_book';
static const addressBookAddContact = '/address_book_add_contact';

View file

@ -0,0 +1,66 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/monero_account_label_validator.dart';
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
class NanoAccountEditOrCreatePage extends BasePage {
NanoAccountEditOrCreatePage({required this.nanoAccountCreationViewModel})
: _formKey = GlobalKey<FormState>(),
_textController = TextEditingController() {
_textController.addListener(() => nanoAccountCreationViewModel.label = _textController.text);
_textController.text = nanoAccountCreationViewModel.label;
}
final NanoAccountEditOrCreateViewModel nanoAccountCreationViewModel;
@override
String get title => S.current.account;
final GlobalKey<FormState> _formKey;
final TextEditingController _textController;
@override
Widget body(BuildContext context) => Form(
key: _formKey,
child: Container(
padding: EdgeInsets.all(24.0),
child: Column(
children: <Widget>[
Expanded(
child: Center(
child: BaseTextFormField(
controller: _textController,
hintText: S.of(context).account,
validator: MoneroLabelValidator(),
))),
Observer(
builder: (_) => LoadingPrimaryButton(
onPressed: () async {
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
return;
}
await nanoAccountCreationViewModel.save();
Navigator.of(context).pop(_textController.text);
},
text: nanoAccountCreationViewModel.isEdit
? S.of(context).rename
: S.of(context).add,
color: Theme.of(context).accentTextTheme!.bodyLarge!.color!,
textColor: Colors.white,
isLoading: nanoAccountCreationViewModel.state is IsExecutingState,
isDisabled: nanoAccountCreationViewModel.label?.isEmpty ?? true,
))
],
),
),
);
}

View file

@ -0,0 +1,94 @@
import 'package:cake_wallet/src/widgets/picker_inner_wrapper_widget.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/monero_accounts/widgets/account_tile.dart';
class NanoAccountListPage extends StatelessWidget {
NanoAccountListPage({required this.accountListViewModel});
final NanoAccountListViewModel accountListViewModel;
final ScrollController controller = ScrollController();
@override
Widget build(BuildContext context) {
double itemHeight = 80;
double buttonHeight = 62;
return Observer(builder: (_) {
final accounts = accountListViewModel.accounts;
print(accounts);
return PickerInnerWrapperWidget(
title: S.of(context).choose_account,
itemsHeight: (itemHeight * accounts.length) + buttonHeight,
children: [
Expanded(
child: Scrollbar(
controller: controller,
child: ListView.separated(
padding: EdgeInsets.zero,
controller: controller,
separatorBuilder: (context, index) => const SectionDivider(),
itemCount: accounts.length,
itemBuilder: (context, index) {
final account = accounts[index];
return AccountTile(
isCurrent: account.isSelected,
accountName: account.label,
accountBalance: account.balance ?? '0.00',
currency: accountListViewModel.currency.toString(),
onTap: () {
if (account.isSelected) {
return;
}
accountListViewModel.select(account);
Navigator.of(context).pop();
},
onEdit: () async => await Navigator.of(context)
.pushNamed(Routes.nanoAccountCreation, arguments: account));
},
),
)),
GestureDetector(
onTap: () async => await Navigator.of(context).pushNamed(Routes.nanoAccountCreation),
child: Container(
height: buttonHeight,
color: Theme.of(context).cardColor,
padding: EdgeInsets.symmetric(horizontal: 24),
child: Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.add,
color: Colors.white,
),
Padding(
padding: EdgeInsets.only(left: 5),
child: Text(
S.of(context).create_new_account,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: Colors.white,
decoration: TextDecoration.none,
),
),
)
],
),
),
),
)
],
);
});
}
}

View file

@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:cake_wallet/generated/i18n.dart';
class AccountTile extends StatelessWidget {
AccountTile(
{required this.isCurrent,
required this.accountName,
this.accountBalance,
required this.currency,
required this.onTap,
required this.onEdit});
final bool isCurrent;
final String accountName;
final String? accountBalance;
final String currency;
final Function() onTap;
final Function() onEdit;
@override
Widget build(BuildContext context) {
final color = isCurrent
? Theme.of(context).textTheme.titleSmall!.decorationColor!
: Theme.of(context).textTheme.displayLarge!.decorationColor!;
final textColor = isCurrent
? Theme.of(context).textTheme.titleSmall!.color!
: Theme.of(context).textTheme.displayLarge!.color!;
final Widget cell = GestureDetector(
onTap: onTap,
child: Container(
height: 77,
width: double.infinity,
padding: EdgeInsets.only(left: 24, right: 24),
color: color,
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.spaceBetween,
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Container(
child: Text(
accountName,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: textColor,
decoration: TextDecoration.none,
),
),
),
if (accountBalance != null)
Container(
child: Text(
'${accountBalance.toString()} $currency',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: Theme.of(context).textTheme.headlineMedium!.color!,
decoration: TextDecoration.none,
),
),
),
],
),
),
);
// return cell;
return Slidable(
key: Key(accountName),
child: cell,
endActionPane: _actionPane(context)
);
}
ActionPane _actionPane(BuildContext context) => ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.3,
children: [
SlidableAction(
onPressed: (_) => onEdit.call(),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
icon: Icons.edit,
label: S.of(context).edit,
),
],
);
}

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_list_page.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:cake_wallet/themes/theme_base.dart';
@ -148,9 +149,18 @@ class ReceivePage extends BasePage {
if (item is WalletAccountListHeader) {
cell = HeaderTile(
onTap: () async => await showPopUp<void>(
context: context,
builder: (_) => getIt.get<MoneroAccountListPage>()),
onTap: () async {
if (addressListViewModel.type == WalletType.monero ||
addressListViewModel.type == WalletType.haven) {
await showPopUp<void>(
context: context,
builder: (_) => getIt.get<MoneroAccountListPage>());
} else {
await showPopUp<void>(
context: context,
builder: (_) => getIt.get<NanoAccountListPage>());
}
},
title: S.of(context).accounts,
icon: Icon(
Icons.arrow_forward_ios,

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
@ -144,6 +145,10 @@ abstract class DashboardViewModelBase with Store {
settingsStore: appStore.settingsStore)));
}
if (_wallet.type == WalletType.nano || _wallet.type == WalletType.banano) {
subname = nano!.getCurrentAccount(_wallet).label;
}
reaction((_) => appStore.wallet, _onWalletChange);
connectMapToListWithTransform(

View file

@ -0,0 +1,89 @@
import 'package:cake_wallet/nano/nano.dart';
import 'package:cw_core/nano_account.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
// import 'package:cw_nano/nano_account_list.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
part 'nano_account_edit_or_create_view_model.g.dart';
class NanoAccountEditOrCreateViewModel = NanoAccountEditOrCreateViewModelBase
with _$NanoAccountEditOrCreateViewModel;
abstract class NanoAccountEditOrCreateViewModelBase with Store {
NanoAccountEditOrCreateViewModelBase(this._nanoAccountList,
/*this._bananoAccountList,*/
{required WalletBase wallet,
NanoAccount? accountListItem})
: state = InitialExecutionState(),
isEdit = accountListItem != null,
label = accountListItem?.label ?? '',
_accountListItem = accountListItem,
_wallet = wallet;
final bool isEdit;
@observable
ExecutionState state;
@observable
String label;
final NanoAccountList _nanoAccountList;
// final BananoAccountList? _bananoAccountList;
final NanoAccount? _accountListItem;
final WalletBase _wallet;
Future<void> save() async {
if (_wallet.type == WalletType.nano) {
await saveNano();
}
// if (_wallet.type == WalletType.banano) {
// await saveBanano();
// }
}
Future<void> saveNano() async {
try {
state = IsExecutingState();
if (_accountListItem != null) {
await _nanoAccountList.setLabelAccount(_wallet, accountIndex: _accountListItem!.id, label: label);
} else {
await _nanoAccountList.addAccount(_wallet, label: label);
}
await _wallet.save();
state = ExecutedSuccessfullyState();
} catch (e) {
state = FailureState(e.toString());
}
}
// Future<void> saveBanano() async {
// if (!(_wallet.type == WalletType.banano)) {
// return;
// }
// try {
// state = IsExecutingState();
// if (_accountListItem != null) {
// await _bananoAccountList!
// .setLabelAccount(_wallet, accountIndex: _accountListItem!.id, label: label);
// } else {
// await _bananoAccountList!.addAccount(_wallet, label: label);
// }
// await _wallet.save();
// state = ExecutedSuccessfullyState();
// } catch (e) {
// state = FailureState(e.toString());
// }
// }
}

View file

@ -0,0 +1,73 @@
import 'package:cake_wallet/nano/nano.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_core/nano_account.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/wallet_base.dart';
part 'nano_account_list_view_model.g.dart';
class NanoAccountListViewModel = NanoAccountListViewModelBase with _$NanoAccountListViewModel;
abstract class NanoAccountListViewModelBase with Store {
NanoAccountListViewModelBase(this._wallet) : scrollOffsetFromTop = 0;
@observable
double scrollOffsetFromTop;
@action
void setScrollOffsetFromTop(double scrollOffsetFromTop) {
this.scrollOffsetFromTop = scrollOffsetFromTop;
}
CryptoCurrency get currency => _wallet.currency;
@computed
List<NanoAccount> get accounts {
if (_wallet.type == WalletType.nano) {
return nano!
.getAccountList(_wallet)
.accounts
.map((acc) => NanoAccount(
label: acc.label,
id: acc.id,
isSelected: acc.id == nano?.getCurrentAccount(_wallet).id,
))
.toList();
}
// if (_wallet.type == WalletType.banano) {
// return banano
// !.getAccountList(_wallet)
// .accounts.map((acc) => AccountListItem(
// label: acc.label,
// id: acc.id,
// balance: acc.balance,
// isSelected: acc.id == banano!.getCurrentAccount(_wallet).id))
// .toList();
// }
throw Exception('Unexpected wallet type: ${_wallet.type}');
}
final WalletBase _wallet;
void select(NanoAccount item) {
if (_wallet.type == WalletType.nano) {
nano!.setCurrentAccount(
_wallet,
item.id,
item.label,
item.balance,
);
}
// if (_wallet.type == WalletType.banano) {
// banano!.setCurrentAccount(
// _wallet,
// item.id,
// item.label,
// );
// }
}
}

View file

@ -299,11 +299,13 @@ abstract class WalletAddressListViewModelBase with Store {
void _init() {
_baseItems = [];
if (_wallet.type == WalletType.monero || _wallet.type == WalletType.haven) {
if (_wallet.type == WalletType.monero || _wallet.type == WalletType.haven || _wallet.type == WalletType.nano || _wallet.type == WalletType.banano) {
_baseItems.add(WalletAccountListHeader());
}
_baseItems.add(WalletAddressListHeader());
if (_wallet.type != WalletType.nano && _wallet.type != WalletType.banano) {
_baseItems.add(WalletAddressListHeader());
}
}
@action

View file

@ -24,7 +24,7 @@ Future<void> main(List<String> args) async {
await generateEthereum(hasEthereum);
await generateNano(hasNano);
// await generateBanano(hasEthereum);
await generatePubspec(
hasMonero: hasMonero,
hasBitcoin: hasBitcoin,
@ -494,7 +494,6 @@ abstract class HavenAccountList {
}
Future<void> generateEthereum(bool hasImplementation) async {
final outputFile = File(ethereumOutputPath);
const ethereumCommonHeaders = """
import 'package:cake_wallet/view_model/send/output.dart';
@ -561,12 +560,12 @@ abstract class Ethereum {
const ethereumEmptyDefinition = 'Ethereum? ethereum;\n';
const ethereumCWDefinition = 'Ethereum? ethereum = CWEthereum();\n';
final output = '$ethereumCommonHeaders\n'
+ (hasImplementation ? '$ethereumCWHeaders\n' : '\n')
+ (hasImplementation ? '$ethereumCwPart\n\n' : '\n')
+ (hasImplementation ? ethereumCWDefinition : ethereumEmptyDefinition)
+ '\n'
+ ethereumContent;
final output = '$ethereumCommonHeaders\n' +
(hasImplementation ? '$ethereumCWHeaders\n' : '\n') +
(hasImplementation ? '$ethereumCwPart\n\n' : '\n') +
(hasImplementation ? ethereumCWDefinition : ethereumEmptyDefinition) +
'\n' +
ethereumContent;
if (outputFile.existsSync()) {
await outputFile.delete();
@ -580,6 +579,7 @@ Future<void> generateNano(bool hasImplementation) async {
const nanoCommonHeaders = """
""";
const nanoCWHeaders = """
import 'package:cw_core/nano_account.dart';
import 'package:cw_nano/nano_mnemonic.dart';
import 'package:cw_nano/nano_wallet.dart';
import 'package:cw_nano/nano_wallet_service.dart';
@ -601,7 +601,11 @@ import 'package:cw_nano/nano_transaction_credentials.dart';
const nanoCwPart = "part 'cw_nano.dart';";
const nanoContent = """
abstract class Nano {
// NanoAccountList getAccountList(Object wallet);
NanoAccountList getAccountList(Object wallet);
Account getCurrentAccount(Object wallet);
void setCurrentAccount(Object wallet, int id, String label, String? balance);
WalletService createNanoWalletService(Box<WalletInfo> walletInfoSource);
@ -629,10 +633,10 @@ abstract class Nano {
}
abstract class NanoAccountList {
ObservableList<Account> get accounts;
ObservableList<NanoAccount> get accounts;
void update(Object wallet);
void refresh(Object wallet);
List<Account> getAll(Object wallet);
Future<List<NanoAccount>> getAll(Object wallet);
Future<void> addAccount(Object wallet, {required String label});
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label});
}