diff --git a/intl.sh b/intl.sh new file mode 100755 index 0000000..1001fbf --- /dev/null +++ b/intl.sh @@ -0,0 +1 @@ +flutter pub global run intl_utils:generate diff --git a/lib/account_manager.dart b/lib/account_manager.dart index 7e61e98..3d4452f 100644 --- a/lib/account_manager.dart +++ b/lib/account_manager.dart @@ -265,11 +265,33 @@ class AccountManagerState extends State { } _onFullRestore() { - Navigator.of(this.context).pushNamed('/fullRestore'); + Navigator.of(context).pushNamed('/fullRestore'); } - _onScanSubAccounts() { - Navigator.of(this.context).pushNamed('/scantaddr'); + _onScanSubAccounts() async { + final s = S.of(context); + final nav = Navigator.of(context); + final gapController = TextEditingController(text: '10'); + final confirmed = await showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: Text(s.scanTransparentAddresses), + content: SingleChildScrollView( + child: Column(mainAxisSize: MainAxisSize.min, children: [ + TextFormField( + decoration: InputDecoration(labelText: s.gapLimit), + controller: gapController, + keyboardType: TextInputType.number) + ])), + actions: confirmButtons(context, () { + nav.pop(true); + }))) ?? + false; + if (confirmed) { + final gapLimit = int.parse(gapController.text); + Navigator.of(this.context).pushNamed('/scantaddr', arguments: gapLimit); + } } } diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 666f51c..f302a36 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -397,6 +397,10 @@ class MessageLookup extends MessageLookupByLibrary { "scanQrCode": MessageLookupByLibrary.simpleMessage("Scan QR Code"), "scanStartingMomentarily": MessageLookupByLibrary.simpleMessage("Scan starting momentarily"), + "scanTransparentAddresses": + MessageLookupByLibrary.simpleMessage("Scan Transparent Addresses"), + "scanningAddresses": + MessageLookupByLibrary.simpleMessage("Scanning addresses"), "secondary": MessageLookupByLibrary.simpleMessage("Secondary"), "secretKey": MessageLookupByLibrary.simpleMessage("Secret Key"), "secretShare": MessageLookupByLibrary.simpleMessage("Secret Share"), diff --git a/lib/generated/intl/messages_es.dart b/lib/generated/intl/messages_es.dart index 1217aad..ad014f1 100644 --- a/lib/generated/intl/messages_es.dart +++ b/lib/generated/intl/messages_es.dart @@ -404,6 +404,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Escanear Código QR"), "scanStartingMomentarily": MessageLookupByLibrary.simpleMessage( "Escaneo iniciado momentáneamente"), + "scanTransparentAddresses": + MessageLookupByLibrary.simpleMessage("Scan Transparent Addresses"), + "scanningAddresses": + MessageLookupByLibrary.simpleMessage("Scanning addresses"), "secondary": MessageLookupByLibrary.simpleMessage("Secundario"), "secretKey": MessageLookupByLibrary.simpleMessage("Clave secreta"), "secretShare": MessageLookupByLibrary.simpleMessage("Clave secreta"), diff --git a/lib/generated/intl/messages_fr.dart b/lib/generated/intl/messages_fr.dart index 68d9904..520c90a 100644 --- a/lib/generated/intl/messages_fr.dart +++ b/lib/generated/intl/messages_fr.dart @@ -408,6 +408,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Scanner le QR Code"), "scanStartingMomentarily": MessageLookupByLibrary.simpleMessage( "Le scan démarre momentanément"), + "scanTransparentAddresses": + MessageLookupByLibrary.simpleMessage("Scan Transparent Addresses"), + "scanningAddresses": + MessageLookupByLibrary.simpleMessage("Scanning addresses"), "secondary": MessageLookupByLibrary.simpleMessage("Secondaire"), "secretKey": MessageLookupByLibrary.simpleMessage("Clé secrète"), "secretShare": MessageLookupByLibrary.simpleMessage("Secret Share"), diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 094cfe4..d79af43 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -3121,6 +3121,26 @@ class S { args: [], ); } + + /// `Scan Transparent Addresses` + String get scanTransparentAddresses { + return Intl.message( + 'Scan Transparent Addresses', + name: 'scanTransparentAddresses', + desc: '', + args: [], + ); + } + + /// `Scanning addresses` + String get scanningAddresses { + return Intl.message( + 'Scanning addresses', + name: 'scanningAddresses', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 74c94ae..1b9e63c 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -305,5 +305,7 @@ "invalidPassword": "Invalid Password", "databaseRestored": "Database Restored", "never": "Never", - "always": "Always" + "always": "Always", + "scanTransparentAddresses": "Scan Transparent Addresses", + "scanningAddresses": "Scanning addresses" } diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 17f690c..83c7de8 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -303,5 +303,7 @@ "invalidPassword": "Invalid Password", "databaseRestored": "Database Restored", "never": "Never", - "always": "Always" + "always": "Always", + "scanTransparentAddresses": "Scan Transparent Addresses", + "scanningAddresses": "Scanning addresses" } diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index fb83208..ed7018a 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -304,5 +304,7 @@ "invalidPassword": "Mot de Passe incorrect", "databaseRestored": "BD Récupèrée", "never": "Jamais", - "always": "Toujours" + "always": "Toujours", + "scanTransparentAddresses": "Scan Transparent Addresses", + "scanningAddresses": "Scanning addresses" } diff --git a/lib/main.dart b/lib/main.dart index fbbb385..a27a032 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -93,8 +93,8 @@ void handleUri(BuildContext context, Uri uri) { final coin = coinDef.coin; final id = WarpApi.getActiveAccountId(coin); active.setActiveAccount(coin, id); - Navigator.of(context).pushNamed( - '/send', arguments: SendPageArgs(uri: uri.toString())); + Navigator.of(context) + .pushNamed('/send', arguments: SendPageArgs(uri: uri.toString())); } Future registerURLHandler(BuildContext context) async { @@ -128,7 +128,7 @@ void handleQuickAction(BuildContext context, String type) { } class LoadProgress extends StatefulWidget { - LoadProgress({Key? key}): super(key: key); + LoadProgress({Key? key}) : super(key: key); @override LoadProgressState createState() => LoadProgressState(); @@ -154,7 +154,7 @@ class LoadProgressState extends State { _disposed = true; super.dispose(); } - + void cancelResetTimer() { _reset?.cancel(); _reset = null; @@ -165,21 +165,21 @@ class LoadProgressState extends State { Widget build(BuildContext context) { final theme = Theme.of(context); final textTheme = theme.textTheme; - return Scaffold(body: Container( - alignment: Alignment.center, - child: SizedBox(height: 240, width: 200, child: - Column( - children: [ - Image.asset('assets/icon.png', height: 64), - Padding(padding: EdgeInsets.all(16)), - Text(S.of(context).loading, style: textTheme.headlineMedium), - Padding(padding: EdgeInsets.all(16)), - LinearProgressIndicator(value: _value), - Padding(padding: EdgeInsets.all(8)), - Text(_message, style: textTheme.labelMedium), - ] - ) - ))); + return Scaffold( + body: Container( + alignment: Alignment.center, + child: SizedBox( + height: 240, + width: 200, + child: Column(children: [ + Image.asset('assets/icon.png', height: 64), + Padding(padding: EdgeInsets.all(16)), + Text(S.of(context).loading, style: textTheme.headlineMedium), + Padding(padding: EdgeInsets.all(16)), + LinearProgressIndicator(value: _value), + Padding(padding: EdgeInsets.all(8)), + Text(_message, style: textTheme.labelMedium), + ])))); } void setValue(double v, String message) { @@ -221,7 +221,8 @@ void main() async { size: size, backgroundColor: Colors.transparent, skipTaskbar: false, - titleBarStyle: Platform.isMacOS ? TitleBarStyle.hidden : TitleBarStyle.normal, + titleBarStyle: + Platform.isMacOS ? TitleBarStyle.hidden : TitleBarStyle.normal, ); windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.show(); @@ -230,90 +231,97 @@ void main() async { windowManager.addListener(OnWindow()); } AwesomeNotifications().initialize( - 'resource://drawable/res_notification', - [ - NotificationChannel( - channelKey: APP_NAME, - channelName: APP_NAME, - channelDescription: 'Notification channel for $APP_NAME', - defaultColor: Color(0xFFB3F0FF), - ledColor: Colors.white, - ) - ], - debug: true - ); + 'resource://drawable/res_notification', + [ + NotificationChannel( + channelKey: APP_NAME, + channelName: APP_NAME, + channelDescription: 'Notification channel for $APP_NAME', + defaultColor: Color(0xFFB3F0FF), + ledColor: Colors.white, + ) + ], + debug: true); final home = ZWalletApp(); runApp(FutureBuilder( future: settings.restore(), builder: (context, snapshot) { return snapshot.connectionState == ConnectionState.waiting - ? MaterialApp(home: Container()) : - Observer(builder: (context) { - final theme = settings.themeData.copyWith( - useMaterial3: true, - dataTableTheme: DataTableThemeData( - headingRowColor: MaterialStateColor.resolveWith( - (_) => settings.themeData.highlightColor))); - return MaterialApp( - title: APP_NAME, - debugShowCheckedModeBanner: false, - theme: theme, - home: home, - scaffoldMessengerKey: rootScaffoldMessengerKey, - navigatorKey: navigatorKey, - localizationsDelegates: [ - S.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: S.delegate.supportedLocales, - onGenerateRoute: (RouteSettings routeSettings) { - var routes = { - '/welcome': (context) => WelcomePage(), - '/account': (context) => HomePage(), - '/add_account': (context) => AddAccountPage(), - '/add_first_account': (context) => AddAccountPage(firstAccount: true), - '/send': (context) => - SendPage(routeSettings.arguments as SendPageArgs?), - '/receive': (context) => - PaymentURIPage(), - '/accounts': (context) => AccountManagerPage(), - '/settings': (context) => SettingsPage(), - '/tx': (context) => - TransactionPage(routeSettings.arguments as int), - '/message': (context) => - MessagePage(routeSettings.arguments as int), - '/backup': (context) { - final accountId = routeSettings.arguments as AccountId?; - final accountId2 = accountId ?? active.toId(); - return BackupPage(accountId2.coin, accountId2.id); - }, - '/pools': (context) => PoolsPage(), - '/multipay': (context) => MultiPayPage(), - '/edit_theme': (context) => - ThemeEditorPage(onSaved: settings.updateCustomThemeColors), - '/reset': (context) => ResetPage(), - '/fullBackup': (context) => FullBackupPage(), - '/fullRestore': (context) => FullRestorePage(), - '/scantaddr': (context) => ScanTAddrPage(), - '/qroffline': (context) => QrOffline(routeSettings.arguments as String), - '/showRawTx': (context) => ShowRawTx(routeSettings.arguments as String), - '/keytool': (context) => KeyToolPage(), - '/dev': (context) => DevPage(), - '/txplan': (context) => TxPlanPage.fromPlan(routeSettings.arguments as String, false), - '/sign': (context) => TxPlanPage.fromPlan(routeSettings.arguments as String, true), - '/syncstats': (context) => SyncChartPage(), - '/scanner': (context) { - final args = routeSettings.arguments as Map; - return QRScanner(args['onScan'], completed: args['completed'], multi: args['multi']); - }, - }; - return MaterialPageRoute(builder: routes[routeSettings.name]!); - }, - ); - }); + ? MaterialApp(home: Container()) + : Observer(builder: (context) { + final theme = settings.themeData.copyWith( + useMaterial3: true, + dataTableTheme: DataTableThemeData( + headingRowColor: MaterialStateColor.resolveWith( + (_) => settings.themeData.highlightColor))); + return MaterialApp( + title: APP_NAME, + debugShowCheckedModeBanner: false, + theme: theme, + home: home, + scaffoldMessengerKey: rootScaffoldMessengerKey, + navigatorKey: navigatorKey, + localizationsDelegates: [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: S.delegate.supportedLocales, + onGenerateRoute: (RouteSettings routeSettings) { + var routes = { + '/welcome': (context) => WelcomePage(), + '/account': (context) => HomePage(), + '/add_account': (context) => AddAccountPage(), + '/add_first_account': (context) => + AddAccountPage(firstAccount: true), + '/send': (context) => + SendPage(routeSettings.arguments as SendPageArgs?), + '/receive': (context) => PaymentURIPage(), + '/accounts': (context) => AccountManagerPage(), + '/settings': (context) => SettingsPage(), + '/tx': (context) => + TransactionPage(routeSettings.arguments as int), + '/message': (context) => + MessagePage(routeSettings.arguments as int), + '/backup': (context) { + final accountId = routeSettings.arguments as AccountId?; + final accountId2 = accountId ?? active.toId(); + return BackupPage(accountId2.coin, accountId2.id); + }, + '/pools': (context) => PoolsPage(), + '/multipay': (context) => MultiPayPage(), + '/edit_theme': (context) => ThemeEditorPage( + onSaved: settings.updateCustomThemeColors), + '/reset': (context) => ResetPage(), + '/fullBackup': (context) => FullBackupPage(), + '/fullRestore': (context) => FullRestorePage(), + '/scantaddr': (context) => + ScanTAddrPage(routeSettings.arguments as int), + '/qroffline': (context) => + QrOffline(routeSettings.arguments as String), + '/showRawTx': (context) => + ShowRawTx(routeSettings.arguments as String), + '/keytool': (context) => KeyToolPage(), + '/dev': (context) => DevPage(), + '/txplan': (context) => TxPlanPage.fromPlan( + routeSettings.arguments as String, false), + '/sign': (context) => TxPlanPage.fromPlan( + routeSettings.arguments as String, true), + '/syncstats': (context) => SyncChartPage(), + '/scanner': (context) { + final args = + routeSettings.arguments as Map; + return QRScanner(args['onScan'], + completed: args['completed'], multi: args['multi']); + }, + }; + return MaterialPageRoute( + builder: routes[routeSettings.name]!); + }, + ); + }); })); } @@ -346,11 +354,14 @@ class ZWalletAppState extends State { } // Only after at least the action method is set, the notification events are delivered AwesomeNotifications().setListeners( - onActionReceivedMethod: NotificationController.onActionReceivedMethod, - onNotificationCreatedMethod: NotificationController.onNotificationCreatedMethod, - onNotificationDisplayedMethod: NotificationController.onNotificationDisplayedMethod, - onDismissActionReceivedMethod: NotificationController.onDismissActionReceivedMethod - ); + onActionReceivedMethod: + NotificationController.onActionReceivedMethod, + onNotificationCreatedMethod: + NotificationController.onNotificationCreatedMethod, + onNotificationDisplayedMethod: + NotificationController.onNotificationDisplayedMethod, + onDismissActionReceivedMethod: + NotificationController.onDismissActionReceivedMethod); }); } } @@ -367,15 +378,14 @@ class ZWalletAppState extends State { final dbPath = await getDbPath(); for (var coin in coins) { coin.init(dbPath); - final server = settings.servers.firstWhere((s) => s.coin == coin.coin); + final server = + settings.servers.firstWhere((s) => s.coin == coin.coin); final url = server.getLWDUrl(); - if (url != null) - WarpApi.updateLWD(coin.coin, url); + if (url != null) WarpApi.updateLWD(coin.coin, url); } if (exportDb) { - for (var coin in coins) - await coin.export(context, dbPath); + for (var coin in coins) await coin.export(context, dbPath); prefs.setBool('export_db', false); } if (recover) { @@ -394,24 +404,24 @@ class ZWalletAppState extends State { if (WarpApi.decryptDb(c.dbFullPath, '')) break; // not encrypted final reset = await getDbPasswd(context, c.dbFullPath); - if (reset) { // user didn't input the passwd and wants to reset + if (reset) { + // user didn't input the passwd and wants to reset await clearApp(context); - } - else break; - } while(true); + } else + break; + } while (true); for (var c in coins) { - _setProgress(0.2 * (c.coin+1), 'Initializing ${c.ticker}'); - await compute(_initWallet, { 'coin': c, 'passwd': settings.dbPasswd }); + _setProgress(0.2 * (c.coin + 1), 'Initializing ${c.ticker}'); + await compute(_initWallet, {'coin': c, 'passwd': settings.dbPasswd}); } _setProgress(0.7, 'Restoring Active Account'); if (recover) { final aid = getAvailableId(coins[0].coin); - if (aid != null) - active.setActiveAccount(aid.coin, aid.id); - } - else await active.restore(); + if (aid != null) active.setActiveAccount(aid.coin, aid.id); + } else + await active.restore(); _setProgress(0.8, 'Register URL Protocol Handlers'); await registerURLHandler(this.context); @@ -434,10 +444,12 @@ class ZWalletAppState extends State { for (var c in settings.coins) { final coin = c.coin; final ticker = c.def.ticker; - shortcuts.add(ShortcutItem(type: '$coin.receive', + shortcuts.add(ShortcutItem( + type: '$coin.receive', localizedTitle: s.receive(ticker), icon: 'receive')); - shortcuts.add(ShortcutItem(type: '$coin.send', + shortcuts.add(ShortcutItem( + type: '$coin.send', localizedTitle: s.sendCointicker(ticker), icon: 'send')); } @@ -468,8 +480,7 @@ class ZWalletAppState extends State { WarpApi.initWallet(c.coin, c.dbFullPath); try { WarpApi.migrateData(c.coin); - } - catch (e) {} // do not fail on network exception + } catch (e) {} // do not fail on network exception } @override @@ -489,10 +500,10 @@ class ZWalletAppState extends State { } final GlobalKey rootScaffoldMessengerKey = -GlobalKey(); + GlobalKey(); -List confirmButtons(BuildContext context, - VoidCallback? onPressed, +List confirmButtons( + BuildContext context, VoidCallback? onPressed, {String? okLabel, Icon? okIcon, cancelValue}) { final s = S.of(context); final navigator = Navigator.of(context); @@ -511,7 +522,8 @@ List confirmButtons(BuildContext context, ]; } -List> sampleDaily(List timeseries, +List> sampleDaily( + List timeseries, int start, int end, int Function(T) getDay, @@ -550,67 +562,73 @@ void showQR(BuildContext context, String text, String title) { return AlertDialog( content: Container( width: double.maxFinite, - child: SingleChildScrollView(child: Column(children: [ + child: SingleChildScrollView( + child: Column(children: [ LayoutBuilder(builder: (context, constraints) { final size = getScreenSize(context) * 0.5; - return QrImage(data: text, backgroundColor: Colors.white, size: size); + return QrImage( + data: text, backgroundColor: Colors.white, size: size); }), Padding(padding: EdgeInsets.all(8)), - Text(title, style: Theme - .of(context) - .textTheme - .titleSmall), + Text(title, style: Theme.of(context).textTheme.titleSmall), Padding(padding: EdgeInsets.all(4)), ButtonBar(children: [ - ElevatedButton.icon(onPressed: () { - Clipboard.setData(ClipboardData(text: text)); - showSnackBar(s.textCopiedToClipboard(title)); - Navigator.of(context).pop(); - }, icon: Icon(Icons.copy), label: Text(s.copy)), - ElevatedButton.icon(onPressed: () => saveQRImage(text, title), - icon: Icon(Icons.save), label: Text(s.save)) + ElevatedButton.icon( + onPressed: () { + Clipboard.setData(ClipboardData(text: text)); + showSnackBar(s.textCopiedToClipboard(title)); + Navigator.of(context).pop(); + }, + icon: Icon(Icons.copy), + label: Text(s.copy)), + ElevatedButton.icon( + onPressed: () => saveQRImage(text, title), + icon: Icon(Icons.save), + label: Text(s.save)) ]) - ]))) - ); }); + ])))); + }); } Future saveQRImage(String data, String title) async { - final code = QrCode.fromData(data: data, errorCorrectLevel: QrErrorCorrectLevel.L); + final code = + QrCode.fromData(data: data, errorCorrectLevel: QrErrorCorrectLevel.L); code.make(); - final painter = QrPainter.withQr(qr: code, emptyColor: Colors.white, gapless: true); + final painter = + QrPainter.withQr(qr: code, emptyColor: Colors.white, gapless: true); final recorder = PictureRecorder(); final canvas = Canvas(recorder); final size = code.moduleCount * 32; - final whitePaint = Paint()..color = Colors.white..style = PaintingStyle.fill; + final whitePaint = Paint() + ..color = Colors.white + ..style = PaintingStyle.fill; canvas.drawRect(Rect.fromLTWH(0, 0, size + 256, size + 256), whitePaint); canvas.translate(128, 128); painter.paint(canvas, Size(size.toDouble(), size.toDouble())); final image = await recorder.endRecording().toImage(size + 256, size + 256); - final ByteData? byteData = await image.toByteData(format: ImageByteFormat.png); + final ByteData? byteData = + await image.toByteData(format: ImageByteFormat.png); final Uint8List pngBytes = byteData!.buffer.asUint8List(); await saveFileBinary(pngBytes, 'qr.png', title); } -Future showMessageBox(BuildContext context, String title, String content, - String label) async { +Future showMessageBox( + BuildContext context, String title, String content, String label) async { final confirm = await showDialog( context: context, barrierDismissible: false, - builder: (context) => - AlertDialog( - title: Text(title), - content: Text(content), - actions: confirmButtons(context, () { - Navigator.of(context).pop(true); - }, okLabel: label, cancelValue: false)), + builder: (context) => AlertDialog( + title: Text(title), + content: Text(content), + actions: confirmButtons(context, () { + Navigator.of(context).pop(true); + }, okLabel: label, cancelValue: false)), ); return confirm ?? false; } double getScreenSize(BuildContext context) { - final size = MediaQuery - .of(context) - .size; + final size = MediaQuery.of(context).size; return min(size.height, size.width); } @@ -650,8 +668,7 @@ int stringToAmount(String? s) { bool checkNumber(String s) { try { NumberFormat.currency().parse(s); - } - on FormatException { + } on FormatException { return false; } return true; @@ -664,8 +681,7 @@ Future scanCode(BuildContext context) async { if (!isMobile()) { final code = await pickDecodeQRImage(); return code; - } - else { + } else { final f = Completer(); Navigator.of(context).pushNamed('/scanner', arguments: { 'onScan': (String code) { @@ -679,29 +695,30 @@ Future scanCode(BuildContext context) async { } String centerTrim(String v) => - v.length >= 16 ? v.substring(0, 8) + "..." + - v.substring(v.length - 16) : v; + v.length >= 16 ? v.substring(0, 8) + "..." + v.substring(v.length - 16) : v; String trailing(String v, int n) { final len = min(n, v.length); return v.substring(v.length - len); } -void showSnackBar(String msg, { bool autoClose = false, bool quick = false }) { +void showSnackBar(String msg, {bool autoClose = false, bool quick = false}) { final duration = quick ? Duration(seconds: 1) : Duration(seconds: 4); - final snackBar = SnackBar(content: SelectableText(msg), - duration: autoClose ? duration : Duration(minutes: 1), - action: SnackBarAction(label: S.current.close, onPressed: () { - rootScaffoldMessengerKey.currentState?.hideCurrentSnackBar(); - })); + final snackBar = SnackBar( + content: SelectableText(msg), + duration: autoClose ? duration : Duration(minutes: 1), + action: SnackBarAction( + label: S.current.close, + onPressed: () { + rootScaffoldMessengerKey.currentState?.hideCurrentSnackBar(); + })); rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar); } void showBalanceNotification(int prevBalances, int curBalances) { final s = S.current; if (syncStatus.isRescan) return; - if (Platform.isAndroid && - prevBalances != curBalances) { + if (Platform.isAndroid && prevBalances != curBalances) { final amount = (prevBalances - curBalances).abs(); final amountStr = amountToString(amount, MAX_PRECISION); final ticker = active.coinDef.ticker; @@ -714,8 +731,7 @@ void showBalanceNotification(int prevBalances, int curBalances) { body: s.received(amountStr, ticker), actionType: ActionType.Default, ); - } - else { + } else { content = NotificationContent( id: 1, channelKey: APP_NAME, @@ -724,25 +740,14 @@ void showBalanceNotification(int prevBalances, int curBalances) { actionType: ActionType.Default, ); } - AwesomeNotifications().createNotification( - content: content - ); + AwesomeNotifications().createNotification(content: content); } } -enum DeviceWidth { - xs, - sm, - md, - lg, - xl -} +enum DeviceWidth { xs, sm, md, lg, xl } DeviceWidth getWidth(BuildContext context) { - final width = MediaQuery - .of(context) - .size - .width; + final width = MediaQuery.of(context).size.width; if (width < 600) return DeviceWidth.xs; if (width < 960) return DeviceWidth.sm; if (width < 1280) return DeviceWidth.md; @@ -773,11 +778,13 @@ String humanizeDateTime(DateTime datetime) { return dateString; } -String decimalFormat(double x, int decimalDigits, { String symbol = '' }) => - NumberFormat.currency(decimalDigits: decimalDigits, symbol: symbol).format( - x).trimRight(); +String decimalFormat(double x, int decimalDigits, {String symbol = ''}) => + NumberFormat.currency(decimalDigits: decimalDigits, symbol: symbol) + .format(x) + .trimRight(); -String amountToString(int amount, int decimalDigits) => decimalFormat(amount / ZECUNIT, decimalDigits); +String amountToString(int amount, int decimalDigits) => + decimalFormat(amount / ZECUNIT, decimalDigits); DecodedPaymentURI decodeAddress(BuildContext context, String? v) { final s = S.of(context); @@ -789,8 +796,7 @@ DecodedPaymentURI decodeAddress(BuildContext context, String? v) { final json = WarpApi.parsePaymentURI(v); final payment = DecodedPaymentURI.fromJson(jsonDecode(json)); return payment; - } - on String catch (e) { + } on String catch (e) { throw e; } } @@ -802,8 +808,7 @@ Future authenticate(BuildContext context, String reason) async { final bool didAuthenticate; if (Platform.isAndroid && !await localAuth.canCheckBiometrics) { didAuthenticate = await KeyGuardmanager.authStatus == "true"; - } - else { + } else { didAuthenticate = await localAuth.authenticate( localizedReason: reason, options: AuthenticationOptions()); } @@ -814,10 +819,9 @@ Future authenticate(BuildContext context, String reason) async { await showDialog( context: context, barrierDismissible: true, - builder: (context) => - AlertDialog( - title: Text(S.of(context).noAuthenticationMethod), - content: Text(e.message ?? ""))); + builder: (context) => AlertDialog( + title: Text(S.of(context).noAuthenticationMethod), + content: Text(e.message ?? ""))); } return false; } @@ -827,8 +831,7 @@ Future shieldTAddr(BuildContext context) async { final txPlan = WarpApi.shieldTAddr( active.coin, active.id, active.tbalance, settings.anchorOffset); Navigator.of(context).pushNamed('/txplan', arguments: txPlan); - } - on String catch (msg) { + } on String catch (msg) { showSnackBar(msg); } } @@ -851,7 +854,8 @@ Future saveFile(String data, String filename, String title) async { await saveFileBinary(utf8.encode(data), filename, title); } -Future saveFileBinary(List data, String filename, String title) async { +Future saveFileBinary( + List data, String filename, String title) async { if (isMobile()) { final context = navigatorKey.currentContext!; Size size = MediaQuery.of(context).size; @@ -860,10 +864,12 @@ Future saveFileBinary(List data, String filename, String title) async final xfile = XFile(path); final file = File(path); await file.writeAsBytes(data); - await Share.shareXFiles([xfile], subject: title, sharePositionOrigin: Rect.fromLTWH(0, 0, size.width, size.height / 2)); - } - else { - final fn = await FilePicker.platform.saveFile(dialogTitle: title, fileName: filename); + await Share.shareXFiles([xfile], + subject: title, + sharePositionOrigin: Rect.fromLTWH(0, 0, size.width, size.height / 2)); + } else { + final fn = await FilePicker.platform + .saveFile(dialogTitle: title, fileName: filename); if (fn != null) { final file = File(fn); await file.writeAsBytes(data); @@ -872,15 +878,17 @@ Future saveFileBinary(List data, String filename, String title) async } Future exportFile(BuildContext context, String path, String title) async { - final confirmed = await showMessageBox(context, title, "Exporting $path", S.of(context).ok); + final confirmed = + await showMessageBox(context, title, "Exporting $path", S.of(context).ok); if (!confirmed) return; if (isMobile()) { final context = navigatorKey.currentContext!; Size size = MediaQuery.of(context).size; final xfile = XFile(path); - await Share.shareXFiles([xfile], subject: title, sharePositionOrigin: Rect.fromLTWH(0, 0, size.width, size.height / 2)); - } - else { + await Share.shareXFiles([xfile], + subject: title, + sharePositionOrigin: Rect.fromLTWH(0, 0, size.width, size.height / 2)); + } else { final fn = await FilePicker.platform.saveFile(); if (fn != null) { final file = File(path); @@ -895,18 +903,20 @@ Future getRecoveryFile() async { return f; } -Future showConfirmDialog(BuildContext context, String title, String body) async { +Future showConfirmDialog( + BuildContext context, String title, String body) async { final s = S.of(context); final confirmation = await showDialog( - context: context, - barrierDismissible: false, - builder: (context) => AlertDialog( - title: Text(title), - content: Text(body), - actions: confirmButtons(context, () { - Navigator.of(context).pop(true); - }, okLabel: s.ok, cancelValue: false)), - ) ?? false; + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: Text(title), + content: Text(body), + actions: confirmButtons(context, () { + Navigator.of(context).pop(true); + }, okLabel: s.ok, cancelValue: false)), + ) ?? + false; return confirmation; } @@ -925,9 +935,12 @@ void cancelScan(BuildContext context) { Future getDataPath() async { String? home; - if (Platform.isAndroid) home = (await getApplicationDocumentsDirectory()).parent.path; + if (Platform.isAndroid) + home = (await getApplicationDocumentsDirectory()).parent.path; if (Platform.isWindows) home = Platform.environment['LOCALAPPDATA']; - if (Platform.isLinux) home = Platform.environment['XDG_DATA_HOME'] ?? Platform.environment['HOME']; + if (Platform.isLinux) + home = + Platform.environment['XDG_DATA_HOME'] ?? Platform.environment['HOME']; if (Platform.isMacOS) home = Platform.environment['HOME']; final h = home ?? ""; return h; @@ -953,27 +966,27 @@ Future getDbPath() async { bool isMobile() => Platform.isAndroid || Platform.isIOS; class NotificationController { - /// Use this method to detect when a new notification or a schedule is created @pragma("vm:entry-point") - static Future onNotificationCreatedMethod(ReceivedNotification receivedNotification) async { - } + static Future onNotificationCreatedMethod( + ReceivedNotification receivedNotification) async {} /// Use this method to detect every time that a new notification is displayed @pragma("vm:entry-point") - static Future onNotificationDisplayedMethod(ReceivedNotification receivedNotification) async { + static Future onNotificationDisplayedMethod( + ReceivedNotification receivedNotification) async { FlutterRingtonePlayer.playNotification(); } /// Use this method to detect if the user dismissed a notification @pragma("vm:entry-point") - static Future onDismissActionReceivedMethod(ReceivedAction receivedAction) async { - } + static Future onDismissActionReceivedMethod( + ReceivedAction receivedAction) async {} /// Use this method to detect when the user taps on a notification or action button @pragma("vm:entry-point") - static Future onActionReceivedMethod(ReceivedAction receivedAction) async { - } + static Future onActionReceivedMethod( + ReceivedAction receivedAction) async {} } void resetApp() { @@ -992,40 +1005,46 @@ Future getDbPasswd(BuildContext context, String dbPath) async { final formKey = GlobalKey(); final reset = await showDialog( - context: context, - barrierColor: Colors.black, - barrierDismissible: false, - builder: (context) { - return AlertDialog( - content: Container( - width: double.maxFinite, - child: SingleChildScrollView(child: Form(key: formKey, child: Column(children: [ - TextFormField( - decoration: InputDecoration(labelText: s.databasePassword), - controller: passwdController, - validator: checkPasswd, - onSaved: (v) { settings.dbPasswd = v!; }, - obscureText: true, - ), - ])))), - actions: - [ - ElevatedButton.icon( - icon: Icon(Icons.lock_reset), - label: Text(s.reset), - onPressed: () => navigator.pop(true)), - ElevatedButton.icon( - icon: Icon(Icons.done), - label: Text(s.ok), - onPressed: () { - final fs = formKey.currentState!; - if (fs.validate()) { - fs.save(); - navigator.pop(false); - } - }) - ]); - }) ?? false; + context: context, + barrierColor: Colors.black, + barrierDismissible: false, + builder: (context) { + return AlertDialog( + content: Container( + width: double.maxFinite, + child: SingleChildScrollView( + child: Form( + key: formKey, + child: Column(children: [ + TextFormField( + decoration: InputDecoration( + labelText: s.databasePassword), + controller: passwdController, + validator: checkPasswd, + onSaved: (v) { + settings.dbPasswd = v!; + }, + obscureText: true, + ), + ])))), + actions: [ + ElevatedButton.icon( + icon: Icon(Icons.lock_reset), + label: Text(s.reset), + onPressed: () => navigator.pop(true)), + ElevatedButton.icon( + icon: Icon(Icons.done), + label: Text(s.ok), + onPressed: () { + final fs = formKey.currentState!; + if (fs.validate()) { + fs.save(); + navigator.pop(false); + } + }) + ]); + }) ?? + false; return reset; } diff --git a/lib/scantaddr.dart b/lib/scantaddr.dart index 8f2121d..ab1a25b 100644 --- a/lib/scantaddr.dart +++ b/lib/scantaddr.dart @@ -5,6 +5,9 @@ import 'generated/l10n.dart'; import 'main.dart'; class ScanTAddrPage extends StatefulWidget { + final int gapLimit; + ScanTAddrPage(this.gapLimit); + @override ScanTAddrPageState createState() => ScanTAddrPageState(); } @@ -16,7 +19,8 @@ class ScanTAddrPageState extends State { void initState() { super.initState(); Future(() async { - final _addresses = await WarpApi.scanTransparentAccounts(active.coin, active.id, settings.gapLimit); + final _addresses = await WarpApi.scanTransparentAccounts( + active.coin, active.id, widget.gapLimit); setState(() { addresses = _addresses; }); @@ -25,23 +29,25 @@ class ScanTAddrPageState extends State { @override Widget build(BuildContext context) { + final s = S.of(context); final _addresses = addresses; return Scaffold( - appBar: AppBar(title: Text('Scan Transparent Addresses')), - body: (_addresses == null) ? - Center(child: Text('Scanning addresses')) - : Column( - children: [ - Expanded(child: ListView.builder( - itemCount: _addresses.length, - itemBuilder: (BuildContext context, int index) { - final a = _addresses[index]; - return ListTile(title: Text(a.address!), subtitle: Text(amountToString(a.balance, MAX_PRECISION))); - })), - ButtonBar(children: confirmButtons(this.context, onPressed)) - ] - ) - ); + appBar: AppBar(title: Text(s.scanTransparentAddresses)), + body: (_addresses == null) + ? Center(child: Text(s.scanningAddresses)) + : Column(children: [ + Expanded( + child: ListView.builder( + itemCount: _addresses.length, + itemBuilder: (BuildContext context, int index) { + final a = _addresses[index]; + return ListTile( + title: Text(a.address!), + subtitle: Text( + amountToString(a.balance, MAX_PRECISION))); + })), + ButtonBar(children: confirmButtons(this.context, onPressed)) + ])); } onPressed() async { @@ -54,4 +60,3 @@ class ScanTAddrPageState extends State { Navigator.of(context).pop(); } } - diff --git a/lib/settings.dart b/lib/settings.dart index a3b6630..995a21b 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -36,7 +36,6 @@ class SettingsState extends State var _anchorController = TextEditingController(text: "${settings.anchorOffset}"); var _memoController = TextEditingController(); - var _gapLimitController = TextEditingController(text: "${settings.gapLimit}"); var _currency = settings.currency; var _needAuth = false; var _messageView = settings.messageView; @@ -50,7 +49,6 @@ class SettingsState extends State final simpleMode = settings.simpleMode; _memoController.text = settings.memoSignature ?? s.sendFrom(APP_NAME); - final hasUA = active.coinDef.supportsUA; final uaType = settings.uaType; List uaList = []; @@ -153,7 +151,6 @@ class SettingsState extends State }, onSaved: _onProtectOpen)), ]), - if (!simpleMode) FormBuilderCheckbox( name: 'use_millis', @@ -191,7 +188,8 @@ class SettingsState extends State FormBuilderCheckboxGroup( orientation: OptionsOrientation.horizontal, name: 'ua', - decoration: InputDecoration(labelText: 'Main Address Type'), + decoration: InputDecoration( + labelText: 'Main Address Type'), initialValue: uaList, onSaved: _onUAType, validator: _checkUA, @@ -207,19 +205,23 @@ class SettingsState extends State initialValue: settings.getTx, onSaved: _onGetTx), FormBuilderRadioGroup( - orientation: OptionsOrientation.horizontal, - name: 'auto_hide', - decoration: InputDecoration(labelText: s.autoHideBalance), - initialValue: settings.autoHide, - onSaved: _onAutoHide, - options: [ - FormBuilderFieldOption(child: Text(s.never), value: 0), - FormBuilderFieldOption(child: Text(s.auto), value: 1), - FormBuilderFieldOption(child: Text(s.always), value: 2), - ]), + orientation: OptionsOrientation.horizontal, + name: 'auto_hide', + decoration: + InputDecoration(labelText: s.autoHideBalance), + initialValue: settings.autoHide, + onSaved: _onAutoHide, + options: [ + FormBuilderFieldOption( + child: Text(s.never), value: 0), + FormBuilderFieldOption( + child: Text(s.auto), value: 1), + FormBuilderFieldOption( + child: Text(s.always), value: 2), + ]), DropdownButtonFormField( decoration: - InputDecoration(labelText: s.minPrivacy), + InputDecoration(labelText: s.minPrivacy), value: _minPrivacy, items: getPrivacyOptions(context), onChanged: (v) { @@ -235,41 +237,60 @@ class SettingsState extends State title: Text(s.includeReplyTo), initialValue: settings.includeReplyTo, onSaved: _onIncludeReplyTo), - if (!simpleMode) Row(children: [ - Expanded(child: DropdownButtonFormField( - decoration: InputDecoration(labelText: s.messages), - value: _messageView, - items: ViewStyle.values.map((v) => DropdownMenuItem( - child: Text(v.name), value: v)).toList(), - onChanged: (v) { - setState(() { _messageView = v!; }); - }, - onSaved: (_) { - settings.setMessageView(_messageView); - })), - Expanded(child: DropdownButtonFormField( - decoration: InputDecoration(labelText: s.notes), - value: _noteView, - items: ViewStyle.values.map((v) => DropdownMenuItem( - child: Text(v.name), value: v)).toList(), - onChanged: (v) { - setState(() { _noteView = v!; }); - }, - onSaved: (_) { - settings.setNoteView(_noteView); - })), - Expanded(child: DropdownButtonFormField( - decoration: InputDecoration(labelText: s.transactions), - value: _txView, - items: ViewStyle.values.map((v) => DropdownMenuItem( - child: Text(v.name), value: v)).toList(), - onChanged: (v) { - setState(() { _txView = v!; }); - }, - onSaved: (_) { - settings.setTxView(_txView); - })), - ]), + if (!simpleMode) + Row(children: [ + Expanded( + child: DropdownButtonFormField( + decoration: InputDecoration( + labelText: s.messages), + value: _messageView, + items: ViewStyle.values + .map((v) => DropdownMenuItem( + child: Text(v.name), value: v)) + .toList(), + onChanged: (v) { + setState(() { + _messageView = v!; + }); + }, + onSaved: (_) { + settings.setMessageView(_messageView); + })), + Expanded( + child: DropdownButtonFormField( + decoration: + InputDecoration(labelText: s.notes), + value: _noteView, + items: ViewStyle.values + .map((v) => DropdownMenuItem( + child: Text(v.name), value: v)) + .toList(), + onChanged: (v) { + setState(() { + _noteView = v!; + }); + }, + onSaved: (_) { + settings.setNoteView(_noteView); + })), + Expanded( + child: DropdownButtonFormField( + decoration: InputDecoration( + labelText: s.transactions), + value: _txView, + items: ViewStyle.values + .map((v) => DropdownMenuItem( + child: Text(v.name), value: v)) + .toList(), + onChanged: (v) { + setState(() { + _txView = v!; + }); + }, + onSaved: (_) { + settings.setTxView(_txView); + })), + ]), if (!simpleMode) FormBuilderCheckbox( name: 'use_cold_qr', @@ -295,14 +316,6 @@ class SettingsState extends State name: 'memo', controller: _memoController, onSaved: _onMemo), - if (!simpleMode) - FormBuilderTextField( - decoration: - InputDecoration(labelText: s.gapLimit), - name: 'gap_limit', - keyboardType: TextInputType.number, - controller: _gapLimitController, - onSaved: _onGapLimit), Padding(padding: EdgeInsets.symmetric(vertical: 8)), ButtonBar(children: confirmButtons(context, _onSave)) ])))))); @@ -345,9 +358,15 @@ class SettingsState extends State int r = 0; for (var v in vs) { switch (v) { - case 'T': r |= 1; break; - case 'S': r |= 2; break; - case 'O': r |= 4; break; + case 'T': + r |= 1; + break; + case 'S': + r |= 2; + break; + case 'O': + r |= 4; + break; } } return r; @@ -393,10 +412,6 @@ class SettingsState extends State settings.setAnchorOffset(int.parse(v)); } - _onGapLimit(v) { - settings.setGapLimit(int.parse(v)); - } - _onGetTx(v) { settings.updateGetTx(v); } diff --git a/lib/store.dart b/lib/store.dart index 38569f4..fd03431 100644 --- a/lib/store.dart +++ b/lib/store.dart @@ -173,9 +173,6 @@ abstract class _Settings with Store { @observable bool qrOffline = true; - @observable - int gapLimit = 10; - @observable int primaryColorValue = 0; @observable @@ -244,7 +241,6 @@ abstract class _Settings with Store { messageView = ViewStyle.values[(prefs.getInt('message_view') ?? 0)]; noteView = ViewStyle.values[(prefs.getInt('note_view') ?? 0)]; txView = ViewStyle.values[(prefs.getInt('tx_view') ?? 0)]; - gapLimit = prefs.getInt('gap_limit') ?? 10; qrOffline = prefs.getBool('qr_offline') ?? true; primaryColorValue = prefs.getInt('primary') ?? Colors.blue.value; @@ -347,13 +343,6 @@ abstract class _Settings with Store { WarpApi.useGPU(v); } - @action - Future setGapLimit(int _gapLimit) async { - final prefs = await SharedPreferences.getInstance(); - gapLimit = _gapLimit; - prefs.setInt('gap_limit', gapLimit); - } - @action Future setTheme(String thm) async { final prefs = await SharedPreferences.getInstance(); diff --git a/native/zcash-sync b/native/zcash-sync index 09f2c10..ee76725 160000 --- a/native/zcash-sync +++ b/native/zcash-sync @@ -1 +1 @@ -Subproject commit 09f2c1093027be54cc316a758a687f9a3f58ad08 +Subproject commit ee7672569560ba1367f6449dd7a12347d42402f0 diff --git a/packages/warp_api_ffi/lib/warp_api.dart b/packages/warp_api_ffi/lib/warp_api.dart index 2b94a1c..58a2909 100644 --- a/packages/warp_api_ffi/lib/warp_api.dart +++ b/packages/warp_api_ffi/lib/warp_api.dart @@ -179,9 +179,7 @@ class WarpApi { } static bool validAddress(int coin, String address) { - return warp_api_lib.valid_address( - coin, toNative(address)) != - 0; + return warp_api_lib.valid_address(coin, toNative(address)) != 0; } static String getDiversifiedAddress(int uaType, int time) { @@ -230,50 +228,62 @@ class WarpApi { return balance; } - static Future transferPools(int coin, int account, int fromPool, int toPool, - int amount, bool includeFee, String memo, int splitAmount, int anchorOffset) async { - final txId = await compute(transferPoolsIsolateFn, TransferPoolsParams(coin, account, fromPool, toPool, amount, - includeFee, memo, splitAmount, anchorOffset)); + static Future transferPools( + int coin, + int account, + int fromPool, + int toPool, + int amount, + bool includeFee, + String memo, + int splitAmount, + int anchorOffset) async { + final txId = await compute( + transferPoolsIsolateFn, + TransferPoolsParams(coin, account, fromPool, toPool, amount, includeFee, + memo, splitAmount, anchorOffset)); return txId; } - static String shieldTAddr(int coin, int account, int amount, int anchorOffset) { - final txPlan = warp_api_lib.shield_taddr(coin, account, amount, anchorOffset); + static String shieldTAddr( + int coin, int account, int amount, int anchorOffset) { + final txPlan = + warp_api_lib.shield_taddr(coin, account, amount, anchorOffset); return unwrapResultString(txPlan); } static Future> scanTransparentAccounts( int coin, int account, int gapLimit) async { return await compute(scanTransparentAccountsParamsIsolateFn, - ScanTransparentAccountsParams(gapLimit)); + {'coin': coin, 'account': account, 'gapLimit': gapLimit}); } static Future prepareTx(int coin, int account, List recipients, int anchorOffset) async { - final builder = Builder(); + final builder = Builder(); final rs = recipients.map((r) => r.unpack()).toList(); int root = RecipientsT(values: rs).pack(builder); builder.finish(root); return await compute((_) { - final res = warp_api_lib.prepare_multi_payment( - coin, account, - toNativeBytes(builder.buffer), - builder.size(), - anchorOffset); + final res = warp_api_lib.prepare_multi_payment(coin, account, + toNativeBytes(builder.buffer), builder.size(), anchorOffset); final json = unwrapResultString(res); return json; }, null); } static TxReport transactionReport(int coin, String plan) { - final data = unwrapResultBytes(warp_api_lib.transaction_report(coin, toNative(plan))); + final data = unwrapResultBytes( + warp_api_lib.transaction_report(coin, toNative(plan))); final report = TxReport(data); return report; } - static Future signAndBroadcast (int coin, int account, String plan) async { + static Future signAndBroadcast( + int coin, int account, String plan) async { return await compute((_) { - final txid = warp_api_lib.sign_and_broadcast(coin, account, plan.toNativeUtf8().cast()); + final txid = warp_api_lib.sign_and_broadcast( + coin, account, plan.toNativeUtf8().cast()); return unwrapResultString(txid); }, null); } @@ -285,8 +295,8 @@ class WarpApi { f(progress); }); - return await compute( - signOnlyIsolateFn, SignOnlyParams(coin, account, tx, receivePort.sendPort)); + return await compute(signOnlyIsolateFn, + SignOnlyParams(coin, account, tx, receivePort.sendPort)); } static String broadcast(String txStr) { @@ -298,9 +308,11 @@ class WarpApi { return warp_api_lib.is_valid_tkey(toNative(key)) != 0; } - static Future sweepTransparent(int latestHeight, String sk, int pool, int confirmations) async { + static Future sweepTransparent( + int latestHeight, String sk, int pool, int confirmations) async { return await compute((_) { - final txid = warp_api_lib.sweep_tkey(latestHeight, toNative(sk), pool, confirmations); + final txid = warp_api_lib.sweep_tkey( + latestHeight, toNative(sk), pool, confirmations); return unwrapResultString(txid); }, null); } @@ -344,7 +356,8 @@ class WarpApi { } static String commitUnsavedContacts(int anchorOffset) { - return unwrapResultString(warp_api_lib.commit_unsaved_contacts(anchorOffset)); + return unwrapResultString( + warp_api_lib.commit_unsaved_contacts(anchorOffset)); } static void markMessageAsRead(int messageId, bool read) { @@ -367,12 +380,10 @@ class WarpApi { warp_api_lib.delete_account(coin, account); } - static String makePaymentURI(int coin, String address, int amount, String memo) { + static String makePaymentURI( + int coin, String address, int amount, String memo) { final uri = warp_api_lib.make_payment_uri( - coin, - toNative(address), - amount, - memo.toNativeUtf8().cast()); + coin, toNative(address), amount, memo.toNativeUtf8().cast()); return unwrapResultString(uri); } @@ -394,7 +405,8 @@ class WarpApi { } static void unzipBackup(String key, String path, String tmpDir) { - unwrapResultU8(warp_api_lib.unzip_backup(toNative(key), toNative(path), toNative(tmpDir))); + unwrapResultU8(warp_api_lib.unzip_backup( + toNative(key), toNative(path), toNative(tmpDir))); } static List splitData(int id, String data) { @@ -477,7 +489,8 @@ class WarpApi { } static Balance getBalance(int coin, int id, int confirmedHeight) { - final r = unwrapResultBytes(warp_api_lib.get_balances(coin, id, confirmedHeight)); + final r = + unwrapResultBytes(warp_api_lib.get_balances(coin, id, confirmedHeight)); final b = Balance(r); return b; } @@ -507,8 +520,10 @@ class WarpApi { return msgs.messages!; } - static PrevNext getPrevNextMessage(int coin, int id, String subject, int height) { - final r = unwrapResultBytes(warp_api_lib.get_prev_next_message(coin, id, toNative(subject), height)); + static PrevNext getPrevNextMessage( + int coin, int id, String subject, int height) { + final r = unwrapResultBytes(warp_api_lib.get_prev_next_message( + coin, id, toNative(subject), height)); final pn = PrevNext(r); return pn; } @@ -535,7 +550,8 @@ class WarpApi { print("templ $t"); final data = toNativeBytes(template); - return unwrapResultU32(warp_api_lib.save_send_template(coin, data, template.length)); + return unwrapResultU32( + warp_api_lib.save_send_template(coin, data, template.length)); } static void deleteSendTemplate(int coin, int id) { @@ -555,13 +571,15 @@ class WarpApi { } static List getQuotes(int coin, int timestamp, String currency) { - final r = unwrapResultBytes(warp_api_lib.get_historical_prices(coin, timestamp, toNative(currency))); + final r = unwrapResultBytes(warp_api_lib.get_historical_prices( + coin, timestamp, toNative(currency))); final quotes = QuoteVec(r); return quotes.values!; } static List getSpendings(int coin, int id, int timestamp) { - final r = unwrapResultBytes(warp_api_lib.get_spendings(coin, id, timestamp)); + final r = + unwrapResultBytes(warp_api_lib.get_spendings(coin, id, timestamp)); final quotes = SpendingVec(r); return quotes.values!; } @@ -585,17 +603,18 @@ class WarpApi { } static void cloneDbWithPasswd(int coin, String tempPath, String passwd) { - warp_api_lib.clone_db_with_passwd(coin, toNative(tempPath), toNative(passwd)); + warp_api_lib.clone_db_with_passwd( + coin, toNative(tempPath), toNative(passwd)); } static bool decryptDb(String dbPath, String passwd) { - return unwrapResultBool(warp_api_lib.decrypt_db(toNative(dbPath), toNative(passwd))); + return unwrapResultBool( + warp_api_lib.decrypt_db(toNative(dbPath), toNative(passwd))); } } String signOnlyIsolateFn(SignOnlyParams params) { - final txIdRes = warp_api_lib.sign( - params.coin, params.account, + final txIdRes = warp_api_lib.sign(params.coin, params.account, params.tx.toNativeUtf8().cast(), params.port.nativePort); if (txIdRes.error != nullptr) throw convertCString(txIdRes.error); return convertCString(txIdRes.value); @@ -606,8 +625,16 @@ int getLatestHeightIsolateFn(Null n) { } String transferPoolsIsolateFn(TransferPoolsParams params) { - final txId = warp_api_lib.transfer_pools(params.coin, params.account, params.fromPool, params.toPool, - params.amount, params.takeFee ? 1 : 0, toNative(params.memo), params.splitAmount, params.anchorOffset); + final txId = warp_api_lib.transfer_pools( + params.coin, + params.account, + params.fromPool, + params.toPool, + params.amount, + params.takeFee ? 1 : 0, + toNative(params.memo), + params.splitAmount, + params.anchorOffset); return unwrapResultString(txId); } @@ -621,7 +648,8 @@ int syncHistoricalPricesIsolateFn(SyncHistoricalPricesParams params) { } int getTBalanceIsolateFn(GetTBalanceParams params) { - return unwrapResultU64(warp_api_lib.get_taddr_balance(params.coin, params.account)); + return unwrapResultU64( + warp_api_lib.get_taddr_balance(params.coin, params.account)); } int getBlockHeightByTimeIsolateFn(BlockHeightByTimeParams params) { @@ -629,8 +657,11 @@ int getBlockHeightByTimeIsolateFn(BlockHeightByTimeParams params) { } List scanTransparentAccountsParamsIsolateFn( - ScanTransparentAccountsParams params) { - final r = unwrapResultBytes(warp_api_lib.scan_transparent_accounts(params.gapLimit)); + Map params) { + final r = unwrapResultBytes(warp_api_lib.scan_transparent_accounts( + params['coin'] as int, + params['account'] as int, + params['gapLimit'] as int)); final v = AddressBalanceVec(r); return v.values!; } @@ -653,8 +684,8 @@ class PaymentParams { final int anchorOffset; final SendPort port; - PaymentParams( - this.coin, this.account, this.recipientsJson, this.useTransparent, this.anchorOffset, this.port); + PaymentParams(this.coin, this.account, this.recipientsJson, + this.useTransparent, this.anchorOffset, this.port); } class SignOnlyParams { @@ -677,8 +708,16 @@ class TransferPoolsParams { final int splitAmount; final int anchorOffset; - TransferPoolsParams(this.coin, this.account, this.fromPool, this.toPool, this.amount, this.takeFee, this.memo, - this.splitAmount, this.anchorOffset); + TransferPoolsParams( + this.coin, + this.account, + this.fromPool, + this.toPool, + this.amount, + this.takeFee, + this.memo, + this.splitAmount, + this.anchorOffset); } class SyncHistoricalPricesParams { @@ -700,12 +739,6 @@ class BlockHeightByTimeParams { BlockHeightByTimeParams(this.time); } -class ScanTransparentAccountsParams { - final int gapLimit; - - ScanTransparentAccountsParams(this.gapLimit); -} - String convertCString(Pointer s) { final str = s.cast().toDartString(); warp_api_lib.deallocate_str(s); @@ -713,9 +746,9 @@ String convertCString(Pointer s) { } List convertBytes(Pointer s, int len) { - final bytes = [...s.asTypedList(len)]; - warp_api_lib.deallocate_bytes(s, len); - return bytes; + final bytes = [...s.asTypedList(len)]; + warp_api_lib.deallocate_bytes(s, len); + return bytes; } void mempoolRunIsolateFn(int port) { diff --git a/packages/warp_api_ffi/lib/warp_api_generated.dart b/packages/warp_api_ffi/lib/warp_api_generated.dart index b7f2e07..4c6164e 100644 --- a/packages/warp_api_ffi/lib/warp_api_generated.dart +++ b/packages/warp_api_ffi/lib/warp_api_generated.dart @@ -512,9 +512,13 @@ class NativeLibrary { _shield_taddr_ptr.asFunction<_dart_shield_taddr>(); CResult______u8 scan_transparent_accounts( + int coin, + int account, int gap_limit, ) { return _scan_transparent_accounts( + coin, + account, gap_limit, ); } @@ -1906,10 +1910,14 @@ typedef _dart_shield_taddr = CResult_____c_char Function( ); typedef _c_scan_transparent_accounts = CResult______u8 Function( + ffi.Uint8 coin, + ffi.Uint32 account, ffi.Uint32 gap_limit, ); typedef _dart_scan_transparent_accounts = CResult______u8 Function( + int coin, + int account, int gap_limit, ); diff --git a/pubspec.yaml b/pubspec.yaml index a132f32..70e3c4e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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+408 +version: 1.3.6+409 environment: sdk: ">=2.12.0 <3.0.0"