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:
parent
f68830e2c7
commit
f977338c7a
|
@ -37,7 +37,6 @@ class _AccountPageState extends State<AccountPage>
|
||||||
String _snapAddress = "";
|
String _snapAddress = "";
|
||||||
TabController _tabController;
|
TabController _tabController;
|
||||||
bool _accountTab = true;
|
bool _accountTab = true;
|
||||||
bool _syncing = false;
|
|
||||||
StreamSubscription _progressDispose;
|
StreamSubscription _progressDispose;
|
||||||
StreamSubscription _syncDispose;
|
StreamSubscription _syncDispose;
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ class _AccountPageState extends State<AccountPage>
|
||||||
syncStatus.setSyncHeight(height);
|
syncStatus.setSyncHeight(height);
|
||||||
eta.checkpoint(height, DateTime.now());
|
eta.checkpoint(height, DateTime.now());
|
||||||
} else {
|
} else {
|
||||||
_syncing = false;
|
|
||||||
WarpApi.mempoolReset(syncStatus.latestHeight);
|
WarpApi.mempoolReset(syncStatus.latestHeight);
|
||||||
_trySync();
|
_trySync();
|
||||||
}
|
}
|
||||||
|
@ -104,10 +102,21 @@ class _AccountPageState extends State<AccountPage>
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
if (!syncStatus.isSynced() && !_syncing) _trySync();
|
if (!syncStatus.isSynced() && !syncStatus.syncing) _trySync();
|
||||||
if (accountManager.active == null) return CircularProgressIndicator();
|
if (accountManager.active == null) return CircularProgressIndicator();
|
||||||
final theme = Theme.of(this.context);
|
final theme = Theme.of(this.context);
|
||||||
final hasTAddr = accountManager.taddress.isNotEmpty;
|
final hasTAddr = accountManager.taddress.isNotEmpty;
|
||||||
|
|
||||||
|
if (syncStatus.accountRestored) {
|
||||||
|
syncStatus.setAccountRestored(false);
|
||||||
|
Future.microtask(() {
|
||||||
|
rescanDialog(context, () {
|
||||||
|
syncStatus.sync(context);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Observer(
|
title: Observer(
|
||||||
|
@ -158,8 +167,8 @@ class _AccountPageState extends State<AccountPage>
|
||||||
final _1 = eta.eta;
|
final _1 = eta.eta;
|
||||||
final _2 = syncStatus.syncedHeight;
|
final _2 = syncStatus.syncedHeight;
|
||||||
final _3 = syncStatus.latestHeight;
|
final _3 = syncStatus.latestHeight;
|
||||||
return syncStatus.syncedHeight <= 0
|
return syncStatus.syncedHeight < 0
|
||||||
? Text(S.of(context).synching)
|
? Text("")
|
||||||
: syncStatus.isSynced()
|
: syncStatus.isSynced()
|
||||||
? Text('${syncStatus.syncedHeight}',
|
? Text('${syncStatus.syncedHeight}',
|
||||||
style: theme.textTheme.caption)
|
style: theme.textTheme.caption)
|
||||||
|
@ -368,9 +377,6 @@ class _AccountPageState extends State<AccountPage>
|
||||||
}
|
}
|
||||||
|
|
||||||
_sync() async {
|
_sync() async {
|
||||||
_syncing = true;
|
|
||||||
await syncStatus.update();
|
|
||||||
await sync(settings.getTx, settings.anchorOffset, syncPort.sendPort);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_trySync() async {
|
_trySync() async {
|
||||||
|
@ -463,15 +469,8 @@ class _AccountPageState extends State<AccountPage>
|
||||||
_rescan() {
|
_rescan() {
|
||||||
rescanDialog(context, () {
|
rescanDialog(context, () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
final snackBar =
|
syncStatus.sync(context);
|
||||||
SnackBar(content: Text(S
|
});
|
||||||
.of(context)
|
|
||||||
.rescanRequested));
|
|
||||||
rootScaffoldMessengerKey.currentState.showSnackBar(snackBar);
|
|
||||||
syncStatus.setSyncHeight(0);
|
|
||||||
WarpApi.rewindToHeight(0);
|
|
||||||
_sync();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_cold() {
|
_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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ class AccountManagerState extends State<AccountManagerPage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(S.of(context).accounts), actions: [
|
appBar: AppBar(title: Text(S.of(context).selectAccount), actions: [
|
||||||
PopupMenuButton<String>(
|
PopupMenuButton<String>(
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
|
@ -36,36 +36,33 @@ class AccountManagerState extends State<AccountManagerPage> {
|
||||||
onSelected: _onMenu)
|
onSelected: _onMenu)
|
||||||
]),
|
]),
|
||||||
body: Observer(
|
body: Observer(
|
||||||
builder: (context) => Stack(children: [
|
builder: (context) =>
|
||||||
accountManager.accounts.isEmpty
|
accountManager.accounts.isEmpty
|
||||||
? Center(child: NoAccount())
|
? Center(child: NoAccount())
|
||||||
: ListView(
|
: ListView.builder(
|
||||||
children: accountManager.accounts
|
itemCount: accountManager.accounts.length,
|
||||||
.asMap()
|
itemBuilder: (BuildContext context, int index) {
|
||||||
.entries
|
final a = accountManager.accounts[index];
|
||||||
.map((a) => Card(
|
return Card(
|
||||||
child: Dismissible(
|
child: Dismissible(
|
||||||
key: Key(a.value.name),
|
key: Key(a.name),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(a.value.name,
|
title: Text(a.name,
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.headline5),
|
||||||
.textTheme
|
trailing: Text("${a.balance / ZECUNIT}"),
|
||||||
.headline5),
|
onTap: () {
|
||||||
trailing:
|
_selectAccount(a);
|
||||||
Text("${a.value.balance / ZECUNIT}"),
|
},
|
||||||
onTap: () {
|
onLongPress: () {
|
||||||
_selectAccount(a.value);
|
_editAccount(a);
|
||||||
},
|
},
|
||||||
onLongPress: () {
|
),
|
||||||
_editAccount(a.value);
|
confirmDismiss: _onAccountDelete,
|
||||||
},
|
onDismissed: (direction) =>
|
||||||
),
|
_onDismissed(index, a.id),
|
||||||
confirmDismiss: _onAccountDelete,
|
));
|
||||||
onDismissed: (direction) =>
|
}),
|
||||||
_onDismissed(a.key, a.value.id),
|
),
|
||||||
)))
|
|
||||||
.toList()),
|
|
||||||
])),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: _onRestore, child: Icon(Icons.add)));
|
onPressed: _onRestore, child: Icon(Icons.add)));
|
||||||
}
|
}
|
||||||
|
@ -135,14 +132,10 @@ class AccountManagerState extends State<AccountManagerPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class NoAccount extends StatelessWidget {
|
class NoAccount extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Widget wallet = SvgPicture.asset(
|
final Widget wallet = SvgPicture.asset('assets/wallet.svg',
|
||||||
'assets/wallet.svg',
|
color: Theme.of(context).primaryColor, semanticsLabel: 'Wallet');
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
semanticsLabel: 'Wallet'
|
|
||||||
);
|
|
||||||
|
|
||||||
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
SizedBox(child: wallet, height: 150, width: 150),
|
SizedBox(child: wallet, height: 150, width: 150),
|
||||||
|
|
|
@ -119,6 +119,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Scan starting momentarily"),
|
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Scan starting momentarily"),
|
||||||
"secretKey" : MessageLookupByLibrary.simpleMessage("Secret Key"),
|
"secretKey" : MessageLookupByLibrary.simpleMessage("Secret Key"),
|
||||||
"seed" : MessageLookupByLibrary.simpleMessage("Seed"),
|
"seed" : MessageLookupByLibrary.simpleMessage("Seed"),
|
||||||
|
"selectAccount" : MessageLookupByLibrary.simpleMessage("Select Account"),
|
||||||
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Select notes to EXCLUDE from payments"),
|
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Select notes to EXCLUDE from payments"),
|
||||||
"send" : MessageLookupByLibrary.simpleMessage("Send"),
|
"send" : MessageLookupByLibrary.simpleMessage("Send"),
|
||||||
"sendCointicker" : m2,
|
"sendCointicker" : m2,
|
||||||
|
|
|
@ -119,6 +119,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Escaneo comenzando momentáneamente "),
|
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Escaneo comenzando momentáneamente "),
|
||||||
"secretKey" : MessageLookupByLibrary.simpleMessage("Llave Secreta"),
|
"secretKey" : MessageLookupByLibrary.simpleMessage("Llave Secreta"),
|
||||||
"seed" : MessageLookupByLibrary.simpleMessage("Semilla"),
|
"seed" : MessageLookupByLibrary.simpleMessage("Semilla"),
|
||||||
|
"selectAccount" : MessageLookupByLibrary.simpleMessage("Select Account"),
|
||||||
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Seleccionar Notas a EXCLUIR de los pagos"),
|
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Seleccionar Notas a EXCLUIR de los pagos"),
|
||||||
"send" : MessageLookupByLibrary.simpleMessage("Enviar"),
|
"send" : MessageLookupByLibrary.simpleMessage("Enviar"),
|
||||||
"sendCointicker" : m2,
|
"sendCointicker" : m2,
|
||||||
|
|
|
@ -119,6 +119,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Le scan démarre momentanément"),
|
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("Le scan démarre momentanément"),
|
||||||
"secretKey" : MessageLookupByLibrary.simpleMessage("Clé secrète"),
|
"secretKey" : MessageLookupByLibrary.simpleMessage("Clé secrète"),
|
||||||
"seed" : MessageLookupByLibrary.simpleMessage("Graine"),
|
"seed" : MessageLookupByLibrary.simpleMessage("Graine"),
|
||||||
|
"selectAccount" : MessageLookupByLibrary.simpleMessage("Select Account"),
|
||||||
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Sélectionnez les billets à EXCLURE des paiements"),
|
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("Sélectionnez les billets à EXCLURE des paiements"),
|
||||||
"send" : MessageLookupByLibrary.simpleMessage("Envoyer"),
|
"send" : MessageLookupByLibrary.simpleMessage("Envoyer"),
|
||||||
"sendCointicker" : m2,
|
"sendCointicker" : m2,
|
||||||
|
|
|
@ -115,6 +115,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("掃描即將開始"),
|
"scanStartingMomentarily" : MessageLookupByLibrary.simpleMessage("掃描即將開始"),
|
||||||
"secretKey" : MessageLookupByLibrary.simpleMessage("秘密鎖匙"),
|
"secretKey" : MessageLookupByLibrary.simpleMessage("秘密鎖匙"),
|
||||||
"seed" : MessageLookupByLibrary.simpleMessage("種子"),
|
"seed" : MessageLookupByLibrary.simpleMessage("種子"),
|
||||||
|
"selectAccount" : MessageLookupByLibrary.simpleMessage("Select Account"),
|
||||||
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("選取不需要的貨幣"),
|
"selectNotesToExcludeFromPayments" : MessageLookupByLibrary.simpleMessage("選取不需要的貨幣"),
|
||||||
"send" : MessageLookupByLibrary.simpleMessage("發送"),
|
"send" : MessageLookupByLibrary.simpleMessage("發送"),
|
||||||
"sendCointicker" : m2,
|
"sendCointicker" : m2,
|
||||||
|
|
|
@ -1204,6 +1204,16 @@ class S {
|
||||||
args: [],
|
args: [],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `Select Account`
|
||||||
|
String get selectAccount {
|
||||||
|
return Intl.message(
|
||||||
|
'Select Account',
|
||||||
|
name: 'selectAccount',
|
||||||
|
desc: '',
|
||||||
|
args: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||||
|
|
|
@ -115,5 +115,6 @@
|
||||||
"useUa": "Use UA",
|
"useUa": "Use UA",
|
||||||
"createANewAccount": "Create a new account and it will show up here",
|
"createANewAccount": "Create a new account and it will show up here",
|
||||||
"duplicateAccount": "Duplicate Account",
|
"duplicateAccount": "Duplicate Account",
|
||||||
"thisAccountAlreadyExists": "Another account has the same address"
|
"thisAccountAlreadyExists": "Another account has the same address",
|
||||||
|
"selectAccount": "Select Account"
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,5 +116,6 @@
|
||||||
"useUa": "Use UA",
|
"useUa": "Use UA",
|
||||||
"createANewAccount": "Create a new account and it will show up here",
|
"createANewAccount": "Create a new account and it will show up here",
|
||||||
"duplicateAccount": "Duplicate Account",
|
"duplicateAccount": "Duplicate Account",
|
||||||
"thisAccountAlreadyExists": "This account already exists."
|
"thisAccountAlreadyExists": "This account already exists.",
|
||||||
|
"selectAccount": "Select Account"
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,5 +116,6 @@
|
||||||
"useUa": "Use UA",
|
"useUa": "Use UA",
|
||||||
"createANewAccount": "Create a new account and it will show up here",
|
"createANewAccount": "Create a new account and it will show up here",
|
||||||
"duplicateAccount": "Duplicate Account",
|
"duplicateAccount": "Duplicate Account",
|
||||||
"thisAccountAlreadyExists": "This account already exists."
|
"thisAccountAlreadyExists": "This account already exists.",
|
||||||
|
"selectAccount": "Select Account"
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,5 +112,6 @@
|
||||||
"useUa": "Use UA",
|
"useUa": "Use UA",
|
||||||
"createANewAccount": "Create a new account and it will show up here",
|
"createANewAccount": "Create a new account and it will show up here",
|
||||||
"duplicateAccount": "Duplicate Account",
|
"duplicateAccount": "Duplicate Account",
|
||||||
"thisAccountAlreadyExists": "This account already exists."
|
"thisAccountAlreadyExists": "This account already exists.",
|
||||||
|
"selectAccount": "Select Account"
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,6 @@ class _RestorePageState extends State<RestorePage> {
|
||||||
if (_formKey.currentState.validate()) {
|
if (_formKey.currentState.validate()) {
|
||||||
final account =
|
final account =
|
||||||
WarpApi.newAccount(_nameController.text, _keyController.text);
|
WarpApi.newAccount(_nameController.text, _keyController.text);
|
||||||
print("$account");
|
|
||||||
if (account < 0) {
|
if (account < 0) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -85,15 +84,11 @@ class _RestorePageState extends State<RestorePage> {
|
||||||
await accountManager.refresh();
|
await accountManager.refresh();
|
||||||
await accountManager.setActiveAccountId(account);
|
await accountManager.setActiveAccountId(account);
|
||||||
if (_keyController.text != "") {
|
if (_keyController.text != "") {
|
||||||
await rescanDialog(context, () {
|
syncStatus.setAccountRestored(true);
|
||||||
WarpApi.rewindToHeight(0);
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (accountManager.accounts.length == 1)
|
else if (accountManager.accounts.length == 1)
|
||||||
WarpApi.skipToLastHeight(); // single new account -> quick sync
|
WarpApi.skipToLastHeight(); // single new account -> quick sync
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
Navigator.of(context).pushReplacementNamed('/account');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:isolate';
|
import 'dart:isolate';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
import 'package:charts_flutter/flutter.dart' as charts show MaterialPalette;
|
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:convert/convert.dart';
|
||||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||||
|
|
||||||
|
import 'generated/l10n.dart';
|
||||||
import 'main.dart';
|
import 'main.dart';
|
||||||
|
|
||||||
part 'store.g.dart';
|
part 'store.g.dart';
|
||||||
|
@ -423,6 +425,8 @@ abstract class _AccountManager with Store {
|
||||||
Future<void> delete(int account) async {
|
Future<void> delete(int account) async {
|
||||||
await db.rawDelete("DELETE FROM accounts WHERE id_account = ?1", [account]);
|
await db.rawDelete("DELETE FROM accounts WHERE id_account = ?1", [account]);
|
||||||
await db.rawDelete("DELETE FROM taddrs WHERE account = ?1", [account]);
|
await db.rawDelete("DELETE FROM taddrs WHERE account = ?1", [account]);
|
||||||
|
if (account == active?.id)
|
||||||
|
resetToDefaultAccount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -786,6 +790,12 @@ abstract class _SyncStatus with Store {
|
||||||
await update();
|
await update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool accountRestored = false;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool syncing = false;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
int syncedHeight = -1;
|
int syncedHeight = -1;
|
||||||
|
|
||||||
|
@ -810,6 +820,27 @@ abstract class _SyncStatus with Store {
|
||||||
if (_syncedHeight > 0) syncedHeight = _syncedHeight;
|
if (_syncedHeight > 0) syncedHeight = _syncedHeight;
|
||||||
return syncedHeight == latestHeight;
|
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;
|
class MultiPayStore = _MultiPayStore with _$MultiPayStore;
|
||||||
|
|
Loading…
Reference in New Issue