Account Manager

- New account from seed does not trigger rescan until manager closed
- No account icon
- Message Box when duplicate account
This commit is contained in:
Hanh 2021-09-06 12:41:32 +08:00
parent f68830e2c7
commit f977338c7a
13 changed files with 98 additions and 66 deletions

View File

@ -37,7 +37,6 @@ class _AccountPageState extends State<AccountPage>
String _snapAddress = "";
TabController _tabController;
bool _accountTab = true;
bool _syncing = false;
StreamSubscription _progressDispose;
StreamSubscription _syncDispose;
@ -70,7 +69,6 @@ class _AccountPageState extends State<AccountPage>
syncStatus.setSyncHeight(height);
eta.checkpoint(height, DateTime.now());
} else {
_syncing = false;
WarpApi.mempoolReset(syncStatus.latestHeight);
_trySync();
}
@ -104,10 +102,21 @@ class _AccountPageState extends State<AccountPage>
@override
Widget build(BuildContext context) {
super.build(context);
if (!syncStatus.isSynced() && !_syncing) _trySync();
if (!syncStatus.isSynced() && !syncStatus.syncing) _trySync();
if (accountManager.active == null) return CircularProgressIndicator();
final theme = Theme.of(this.context);
final hasTAddr = accountManager.taddress.isNotEmpty;
if (syncStatus.accountRestored) {
syncStatus.setAccountRestored(false);
Future.microtask(() {
rescanDialog(context, () {
syncStatus.sync(context);
Navigator.of(context).pop();
});
});
}
return Scaffold(
appBar: AppBar(
title: Observer(
@ -158,8 +167,8 @@ class _AccountPageState extends State<AccountPage>
final _1 = eta.eta;
final _2 = syncStatus.syncedHeight;
final _3 = syncStatus.latestHeight;
return syncStatus.syncedHeight <= 0
? Text(S.of(context).synching)
return syncStatus.syncedHeight < 0
? Text("")
: syncStatus.isSynced()
? Text('${syncStatus.syncedHeight}',
style: theme.textTheme.caption)
@ -368,9 +377,6 @@ class _AccountPageState extends State<AccountPage>
}
_sync() async {
_syncing = true;
await syncStatus.update();
await sync(settings.getTx, settings.anchorOffset, syncPort.sendPort);
}
_trySync() async {
@ -463,15 +469,8 @@ class _AccountPageState extends State<AccountPage>
_rescan() {
rescanDialog(context, () {
Navigator.of(context).pop();
final snackBar =
SnackBar(content: Text(S
.of(context)
.rescanRequested));
rootScaffoldMessengerKey.currentState.showSnackBar(snackBar);
syncStatus.setSyncHeight(0);
WarpApi.rewindToHeight(0);
_sync();
});
syncStatus.sync(context);
});
}
_cold() {
@ -992,7 +991,3 @@ class ContactsState extends State<ContactsWidget>
}
}
Future<void> sync(bool getTx, int anchorOffset, SendPort port) async {
final params = SyncParams(getTx, anchorOffset, port);
await compute(WarpApi.warpSync, params);
}

View File

@ -25,7 +25,7 @@ class AccountManagerState extends State<AccountManagerPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(S.of(context).accounts), actions: [
appBar: AppBar(title: Text(S.of(context).selectAccount), actions: [
PopupMenuButton<String>(
itemBuilder: (context) => [
PopupMenuItem(
@ -36,36 +36,33 @@ class AccountManagerState extends State<AccountManagerPage> {
onSelected: _onMenu)
]),
body: Observer(
builder: (context) => Stack(children: [
builder: (context) =>
accountManager.accounts.isEmpty
? Center(child: NoAccount())
: ListView(
children: accountManager.accounts
.asMap()
.entries
.map((a) => Card(
child: Dismissible(
key: Key(a.value.name),
child: ListTile(
title: Text(a.value.name,
style: Theme.of(context)
.textTheme
.headline5),
trailing:
Text("${a.value.balance / ZECUNIT}"),
onTap: () {
_selectAccount(a.value);
},
onLongPress: () {
_editAccount(a.value);
},
),
confirmDismiss: _onAccountDelete,
onDismissed: (direction) =>
_onDismissed(a.key, a.value.id),
)))
.toList()),
])),
: ListView.builder(
itemCount: accountManager.accounts.length,
itemBuilder: (BuildContext context, int index) {
final a = accountManager.accounts[index];
return Card(
child: Dismissible(
key: Key(a.name),
child: ListTile(
title: Text(a.name,
style: Theme.of(context).textTheme.headline5),
trailing: Text("${a.balance / ZECUNIT}"),
onTap: () {
_selectAccount(a);
},
onLongPress: () {
_editAccount(a);
},
),
confirmDismiss: _onAccountDelete,
onDismissed: (direction) =>
_onDismissed(index, a.id),
));
}),
),
floatingActionButton: FloatingActionButton(
onPressed: _onRestore, child: Icon(Icons.add)));
}
@ -135,14 +132,10 @@ class AccountManagerState extends State<AccountManagerPage> {
}
class NoAccount extends StatelessWidget {
@override
Widget build(BuildContext context) {
final Widget wallet = SvgPicture.asset(
'assets/wallet.svg',
color: Theme.of(context).primaryColor,
semanticsLabel: 'Wallet'
);
final Widget wallet = SvgPicture.asset('assets/wallet.svg',
color: Theme.of(context).primaryColor, semanticsLabel: 'Wallet');
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
SizedBox(child: wallet, height: 150, width: 150),

View File

@ -119,6 +119,7 @@ class MessageLookup extends MessageLookupByLibrary {
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Scan starting momentarily"),
"secretKey" : MessageLookupByLibrary.simpleMessage("Secret Key"),
"seed" : MessageLookupByLibrary.simpleMessage("Seed"),
"selectAccount" : MessageLookupByLibrary.simpleMessage("Select Account"),
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Select notes to EXCLUDE from payments"),
"send" : MessageLookupByLibrary.simpleMessage("Send"),
"sendCointicker" : m2,

View File

@ -119,6 +119,7 @@ class MessageLookup extends MessageLookupByLibrary {
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Escaneo comenzando momentáneamente "),
"secretKey" : MessageLookupByLibrary.simpleMessage("Llave Secreta"),
"seed" : MessageLookupByLibrary.simpleMessage("Semilla"),
"selectAccount" : MessageLookupByLibrary.simpleMessage("Select Account"),
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Seleccionar Notas a EXCLUIR de los pagos"),
"send" : MessageLookupByLibrary.simpleMessage("Enviar"),
"sendCointicker" : m2,

View File

@ -119,6 +119,7 @@ class MessageLookup extends MessageLookupByLibrary {
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Le scan démarre momentanément"),
"secretKey" : MessageLookupByLibrary.simpleMessage("Clé secrète"),
"seed" : MessageLookupByLibrary.simpleMessage("Graine"),
"selectAccount" : MessageLookupByLibrary.simpleMessage("Select Account"),
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Sélectionnez les billets à EXCLURE des paiements"),
"send" : MessageLookupByLibrary.simpleMessage("Envoyer"),
"sendCointicker" : m2,

View File

@ -115,6 +115,7 @@ class MessageLookup extends MessageLookupByLibrary {
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("掃描即將開始"),
"secretKey" : MessageLookupByLibrary.simpleMessage("秘密鎖匙"),
"seed" : MessageLookupByLibrary.simpleMessage("種子"),
"selectAccount" : MessageLookupByLibrary.simpleMessage("Select Account"),
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("選取不需要的貨幣"),
"send" : MessageLookupByLibrary.simpleMessage("發送"),
"sendCointicker" : m2,

View File

@ -1204,6 +1204,16 @@ class S {
args: [],
);
}
/// `Select Account`
String get selectAccount {
return Intl.message(
'Select Account',
name: 'selectAccount',
desc: '',
args: [],
);
}
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

@ -115,5 +115,6 @@
"useUa": "Use UA",
"createANewAccount": "Create a new account and it will show up here",
"duplicateAccount": "Duplicate Account",
"thisAccountAlreadyExists": "Another account has the same address"
"thisAccountAlreadyExists": "Another account has the same address",
"selectAccount": "Select Account"
}

View File

@ -116,5 +116,6 @@
"useUa": "Use UA",
"createANewAccount": "Create a new account and it will show up here",
"duplicateAccount": "Duplicate Account",
"thisAccountAlreadyExists": "This account already exists."
"thisAccountAlreadyExists": "This account already exists.",
"selectAccount": "Select Account"
}

View File

@ -116,5 +116,6 @@
"useUa": "Use UA",
"createANewAccount": "Create a new account and it will show up here",
"duplicateAccount": "Duplicate Account",
"thisAccountAlreadyExists": "This account already exists."
"thisAccountAlreadyExists": "This account already exists.",
"selectAccount": "Select Account"
}

View File

@ -112,5 +112,6 @@
"useUa": "Use UA",
"createANewAccount": "Create a new account and it will show up here",
"duplicateAccount": "Duplicate Account",
"thisAccountAlreadyExists": "This account already exists."
"thisAccountAlreadyExists": "This account already exists.",
"selectAccount": "Select Account"
}

View File

@ -64,7 +64,6 @@ class _RestorePageState extends State<RestorePage> {
if (_formKey.currentState.validate()) {
final account =
WarpApi.newAccount(_nameController.text, _keyController.text);
print("$account");
if (account < 0) {
showDialog(
context: context,
@ -85,15 +84,11 @@ class _RestorePageState extends State<RestorePage> {
await accountManager.refresh();
await accountManager.setActiveAccountId(account);
if (_keyController.text != "") {
await rescanDialog(context, () {
WarpApi.rewindToHeight(0);
Navigator.of(context).pop();
});
syncStatus.setAccountRestored(true);
}
else if (accountManager.accounts.length == 1)
WarpApi.skipToLastHeight(); // single new account -> quick sync
Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed('/account');
}
}
}

View File

@ -1,6 +1,7 @@
import 'dart:isolate';
import 'dart:typed_data';
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:charts_flutter/flutter.dart' as charts show MaterialPalette;
@ -16,6 +17,7 @@ import 'dart:convert' as convert;
import 'package:convert/convert.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'generated/l10n.dart';
import 'main.dart';
part 'store.g.dart';
@ -423,6 +425,8 @@ abstract class _AccountManager with Store {
Future<void> delete(int account) async {
await db.rawDelete("DELETE FROM accounts WHERE id_account = ?1", [account]);
await db.rawDelete("DELETE FROM taddrs WHERE account = ?1", [account]);
if (account == active?.id)
resetToDefaultAccount();
}
@action
@ -786,6 +790,12 @@ abstract class _SyncStatus with Store {
await update();
}
@observable
bool accountRestored = false;
@observable
bool syncing = false;
@observable
int syncedHeight = -1;
@ -810,6 +820,27 @@ abstract class _SyncStatus with Store {
if (_syncedHeight > 0) syncedHeight = _syncedHeight;
return syncedHeight == latestHeight;
}
@action
Future<void> sync(BuildContext context) async {
syncing = true;
final snackBar =
SnackBar(content: Text(S
.of(context)
.rescanRequested));
rootScaffoldMessengerKey.currentState.showSnackBar(snackBar);
syncStatus.setSyncHeight(0);
WarpApi.rewindToHeight(0);
await syncStatus.update();
final params = SyncParams(settings.getTx, settings.anchorOffset, syncPort.sendPort);
await compute(WarpApi.warpSync, params);
syncing = false;
}
@action
void setAccountRestored(bool v) {
accountRestored = v;
}
}
class MultiPayStore = _MultiPayStore with _$MultiPayStore;