Fix db lock in sync price history

This commit is contained in:
Hanh 2023-03-15 00:59:02 +10:00
parent ab72ea1e23
commit 20bd10a471
6 changed files with 142 additions and 108 deletions

View File

@ -242,7 +242,7 @@ class QRAddressState extends State<QRAddressWidget> {
}
_onQRTap() {
active.changeAddrMode();
active.updateAddrMode(_getNextMode());
}
_onAddressCopy() {

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:warp_api/data_fb_generated.dart';
import 'coin/coins.dart';
@ -209,7 +211,7 @@ abstract class _ActiveAccount with Store {
draftRecipient = null;
update();
Future.microtask(priceStore.updateChart);
Future(priceStore.updateChart);
}
@action
@ -218,8 +220,8 @@ abstract class _ActiveAccount with Store {
}
@action
void changeAddrMode() {
addrMode = (addrMode + 1) % 3;
void updateAddrMode(int v) {
addrMode = v;
}
@action

View File

@ -42,10 +42,10 @@ class HomeState extends State<HomePage> {
void initState() {
super.initState();
contacts.fetchContacts();
Future.microtask(() async {
Future(() async {
await syncStatus.update();
active.updateBalances();
await priceStore.updateChart();
active.updateBalances(); // lazy
priceStore.updateChart(); // lazy
await Future.delayed(Duration(seconds: 3));
await syncStatus.sync(false);
@ -77,8 +77,7 @@ class HomeState extends State<HomePage> {
active.update();
final progress = syncStatus.progress;
if (progress != null && isMobile()) {
FlutterForegroundTask.updateService(
notificationText: "$progress %");
FlutterForegroundTask.updateService(notificationText: "$progress %");
}
syncStats.add(DateTime.now(), syncedHeight.height);
}
@ -108,7 +107,8 @@ class HomeInnerPage extends StatefulWidget {
HomeInnerState createState() => HomeInnerState();
}
class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderStateMixin {
class HomeInnerState extends State<HomeInnerPage>
with SingleTickerProviderStateMixin {
TabController? _tabController;
int _tabIndex = 0;
final contactKey = GlobalKey<ContactsState>();
@ -116,9 +116,9 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
@override
void initState() {
super.initState();
if (Platform.isAndroid)
_initForegroundTask();
final tabController = TabController(length: settings.simpleMode ? 4 : 7, vsync: this);
if (Platform.isAndroid) _initForegroundTask();
final tabController =
TabController(length: settings.simpleMode ? 4 : 7, vsync: this);
tabController.addListener(() {
setState(() {
_tabIndex = tabController.index;
@ -171,11 +171,11 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
rescanMsg = s.rescan;
final unread = active.unread;
final messageTab = unread != 0 ?
Tab(child: Badges.Badge(
child: Text(s.messages),
badgeContent: Text('$unread'))) :
Tab(text: s.messages);
final messageTab = unread != 0
? Tab(
child: Badges.Badge(
child: Text(s.messages), badgeContent: Text('$unread')))
: Tab(text: s.messages);
if (active.id == 0) {
Future.microtask(() async {
@ -190,24 +190,45 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
PopupMenuItem(child: Text(s.accounts), value: "Accounts"),
PopupMenuItem(child: Text(s.backup), value: "Backup"),
PopupMenuItem(child: Text(rescanMsg), value: "Rescan"),
if (!simpleMode) PopupMenuItem(child: Text(s.pools), value: "Pools"),
if (!simpleMode)
PopupMenuItem(child:
PopupMenuButton(
child: Text(s.advanced),
itemBuilder: (_) => [
if (!isMobile()) PopupMenuItem(child: Text(s.encryptDatabase), value: "Encrypt"),
PopupMenuItem(child: Text(s.rewindToCheckpoint), value: "Rewind"),
PopupMenuItem(child: Text(s.convertToWatchonly), enabled: active.canPay, value: "Cold"),
PopupMenuItem(child: Text(s.signOffline), enabled: active.canPay, value: "Sign"),
PopupMenuItem(child: Text(s.broadcast), value: "Broadcast"),
PopupMenuItem(child: Text(s.multipay), value: "MultiPay"),
PopupMenuItem(child: Text(s.keyTool), enabled: active.canPay, value: "KeyTool"),
PopupMenuItem(child: Text(s.sweep), enabled: active.canPay, value: "Sweep"),
], onSelected: _onMenu)),
PopupMenuItem(child: Text(s.pools), value: "Pools"),
if (!simpleMode)
PopupMenuItem(
child: PopupMenuButton(
child: Text(s.advanced),
itemBuilder: (_) => [
if (!isMobile())
PopupMenuItem(
child: Text(s.encryptDatabase),
value: "Encrypt"),
PopupMenuItem(
child: Text(s.rewindToCheckpoint),
value: "Rewind"),
PopupMenuItem(
child: Text(s.convertToWatchonly),
enabled: active.canPay,
value: "Cold"),
PopupMenuItem(
child: Text(s.signOffline),
enabled: active.canPay,
value: "Sign"),
PopupMenuItem(
child: Text(s.broadcast), value: "Broadcast"),
PopupMenuItem(
child: Text(s.multipay), value: "MultiPay"),
PopupMenuItem(
child: Text(s.keyTool),
enabled: active.canPay,
value: "KeyTool"),
PopupMenuItem(
child: Text(s.sweep),
enabled: active.canPay,
value: "Sweep"),
],
onSelected: _onMenu)),
// if (!simpleMode && !isMobile())
// PopupMenuItem(child: Text(s.ledger), value: "Ledger"),
if (settings.isDeveloper)
if (settings.isDeveloper)
PopupMenuItem(child: Text(s.expert), value: "Expert"),
PopupMenuItem(child: Text(s.settings), value: "Settings"),
PopupMenuItem(child: Text(s.help), value: "Help"),
@ -219,13 +240,13 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
showAboutOnce(this.context);
return WithForegroundTask(child:
Scaffold(
return WithForegroundTask(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: GestureDetector(
onTap: () => settings.tapDeveloperMode(context),
child: Text("${active.account.name}")),
onTap: () => settings.tapDeveloperMode(context),
child: Text("${active.account.name}")),
bottom: TabBar(
controller: _tabController,
isScrollable: true,
@ -319,14 +340,16 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
}
_backup() async {
final didAuthenticate = await authenticate(context, S.of(context).pleaseAuthenticateToShowAccountSeed);
final didAuthenticate = await authenticate(
context, S.of(context).pleaseAuthenticateToShowAccountSeed);
if (didAuthenticate) {
Navigator.of(context).pushNamed('/backup');
}
}
_keyTool() async {
final didAuthenticate = await authenticate(context, S.of(context).pleaseAuthenticateToShowAccountSeed);
final didAuthenticate = await authenticate(
context, S.of(context).pleaseAuthenticateToShowAccountSeed);
if (didAuthenticate) {
Navigator.of(context).pushNamed('/keytool');
}
@ -342,63 +365,72 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
return null;
};
final confirmed = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text(s.sweep),
content: SingleChildScrollView(child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
decoration: InputDecoration(labelText: s.transparentKey),
controller: keyController,
validator: checkKey,
),
FormBuilderRadioGroup<int>(
orientation: OptionsOrientation.horizontal,
decoration: InputDecoration(labelText: s.toPool),
name: 'pool',
initialValue: 0,
onChanged: (v) { pool = v ?? 0; },
options: [
FormBuilderFieldOption(
child: Text('T'), value: 0),
FormBuilderFieldOption(
child: Text('S'), value: 1),
if (active.coinDef.supportsUA) FormBuilderFieldOption(
child: Text('O'), value: 2),
]),
],
)),
actions: confirmButtons(context, () => Navigator.of(context).pop(true))
)
) ?? false;
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text(s.sweep),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
decoration: InputDecoration(labelText: s.transparentKey),
controller: keyController,
validator: checkKey,
),
FormBuilderRadioGroup<int>(
orientation: OptionsOrientation.horizontal,
decoration: InputDecoration(labelText: s.toPool),
name: 'pool',
initialValue: 0,
onChanged: (v) {
pool = v ?? 0;
},
options: [
FormBuilderFieldOption(child: Text('T'), value: 0),
FormBuilderFieldOption(child: Text('S'), value: 1),
if (active.coinDef.supportsUA)
FormBuilderFieldOption(child: Text('O'), value: 2),
]),
],
)),
actions: confirmButtons(
context, () => Navigator.of(context).pop(true)))) ??
false;
if (confirmed) {
final txid = await WarpApi.sweepTransparent(syncStatus.latestHeight, keyController.text, pool, settings.anchorOffset);
final txid = await WarpApi.sweepTransparent(syncStatus.latestHeight,
keyController.text, pool, settings.anchorOffset);
showSnackBar(s.txId(txid));
}
}
_rewind() async {
final s = S.of(context);
int? height;
final checkpoints = WarpApi.getCheckpoints(active.coin);
final items = checkpoints.map((c) => DropdownMenuItem<int>(value: c.height,
child: Text('${noteDateFormat.format(DateTime.fromMillisecondsSinceEpoch(c.timestamp * 1000))} - ${c.height}')
)).toList();
final items = checkpoints
.map((c) => DropdownMenuItem<int>(
value: c.height,
child: Text(
'${noteDateFormat.format(DateTime.fromMillisecondsSinceEpoch(c.timestamp * 1000))} - ${c.height}')))
.toList();
final confirmed = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text(s.rewindToCheckpoint),
content: SingleChildScrollView(child: Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownButtonFormField<int>(items: items, hint: Text(s.selectCheckpoint), onChanged: (v) { height = v; })]
)),
actions: confirmButtons(context, () => Navigator.of(context).pop(true))
)
) ?? false;
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text(s.rewindToCheckpoint),
content: SingleChildScrollView(
child: Column(mainAxisSize: MainAxisSize.min, children: [
DropdownButtonFormField<int>(
items: items,
hint: Text(s.selectCheckpoint),
onChanged: (v) {
height = v;
})
])),
actions: confirmButtons(
context, () => Navigator.of(context).pop(true)))) ??
false;
final h = height;
if (confirmed && h != null) {
showSnackBar(s.blockReorgDetectedRewind(h));
@ -413,7 +445,7 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
builder: (context) => AlertDialog(
title: Text(S.of(context).coldStorage),
content:
Text(S.of(context).doYouWantToDeleteTheSecretKeyAndConvert),
Text(S.of(context).doYouWantToDeleteTheSecretKeyAndConvert),
actions: confirmButtons(context, _convertToWatchOnly,
okLabel: S.of(context).delete)));
}
@ -442,8 +474,7 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
final file = File(path);
tx = file.readAsStringSync();
}
if (tx != null)
Navigator.of(context).pushNamed('/sign', arguments: tx);
if (tx != null) Navigator.of(context).pushNamed('/sign', arguments: tx);
}
_broadcast() async {
@ -463,8 +494,7 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
try {
final res = WarpApi.broadcast(rawTx);
showSnackBar(res);
}
on String catch (e) {
} on String catch (e) {
showSnackBar(e);
}
}
@ -487,23 +517,27 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
final newPasswdController = TextEditingController();
final repeatPasswdController = TextEditingController();
final confirmed = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (context) =>
AlertDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text(s.encryptDatabase),
contentPadding: EdgeInsets.all(16),
content: Form(child: SingleChildScrollView(child: Column(children: [
if (hasPasswd) TextFormField(
decoration: InputDecoration(labelText: s.currentPassword),
obscureText: true,
controller: oldPasswdController),
content: Form(
child: SingleChildScrollView(
child: Column(children: [
if (hasPasswd)
TextFormField(
decoration:
InputDecoration(labelText: s.currentPassword),
obscureText: true,
controller: oldPasswdController),
TextFormField(
decoration: InputDecoration(labelText: s.newPassword),
obscureText: true,
controller: newPasswdController),
TextFormField(
decoration: InputDecoration(labelText: s.repeatNewPassword),
decoration:
InputDecoration(labelText: s.repeatNewPassword),
obscureText: true,
controller: repeatPasswdController),
]))),
@ -516,8 +550,7 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
showSnackBar(s.currentPasswordIncorrect);
else if (newPasswdController.text != repeatPasswdController.text) {
showSnackBar(s.newPasswordsDoNotMatch);
}
else {
} else {
final passwd = newPasswdController.text;
for (var c in coins) {
final tempPath = p.join(settings.tempDir, c.dbName);
@ -573,4 +606,3 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
FlutterForegroundTask.setOnLockScreenVisibility(false);
}
}

View File

@ -780,7 +780,7 @@ abstract class _SyncStatus with Store {
if (res == 0) {
if (currentSyncedHeight != syncedHeight) {
active.update();
await priceStore.updateChart();
priceStore.updateChart();
contacts.fetchContacts();
}
} else if (res == 1) {

@ -1 +1 @@
Subproject commit 8a2f2b7fea90f37868eb3f61e30e599067e081a4
Subproject commit 637e4c5eac94c9f18691292faea40028f61ac8ac

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.3.6+414
version: 1.3.6+415
environment:
sdk: ">=2.12.0 <3.0.0"