Fix Scan TAddrs

This commit is contained in:
Hanh 2023-03-13 17:53:42 +10:00
parent a6580baa48
commit 9b16a6b7be
17 changed files with 553 additions and 423 deletions

1
intl.sh Executable file
View File

@ -0,0 +1 @@
flutter pub global run intl_utils:generate

View File

@ -265,11 +265,33 @@ class AccountManagerState extends State<AccountManagerPage> {
}
_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<bool>(
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);
}
}
}

View File

@ -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"),

View File

@ -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"),

View File

@ -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"),

View File

@ -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<S> {

View File

@ -305,5 +305,7 @@
"invalidPassword": "Invalid Password",
"databaseRestored": "Database Restored",
"never": "Never",
"always": "Always"
"always": "Always",
"scanTransparentAddresses": "Scan Transparent Addresses",
"scanningAddresses": "Scanning addresses"
}

View File

@ -303,5 +303,7 @@
"invalidPassword": "Invalid Password",
"databaseRestored": "Database Restored",
"never": "Never",
"always": "Always"
"always": "Always",
"scanTransparentAddresses": "Scan Transparent Addresses",
"scanningAddresses": "Scanning addresses"
}

View File

@ -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"
}

View File

@ -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<void> 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<LoadProgress> {
_disposed = true;
super.dispose();
}
void cancelResetTimer() {
_reset?.cancel();
_reset = null;
@ -165,21 +165,21 @@ class LoadProgressState extends State<LoadProgress> {
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 = <String, WidgetBuilder>{
'/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<String, dynamic>;
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 = <String, WidgetBuilder>{
'/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<String, dynamic>;
return QRScanner(args['onScan'],
completed: args['completed'], multi: args['multi']);
},
};
return MaterialPageRoute(
builder: routes[routeSettings.name]!);
},
);
});
}));
}
@ -346,11 +354,14 @@ class ZWalletAppState extends State<ZWalletApp> {
}
// 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<ZWalletApp> {
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<ZWalletApp> {
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<ZWalletApp> {
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<ZWalletApp> {
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<ZWalletApp> {
}
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState>();
GlobalKey<ScaffoldMessengerState>();
List<ElevatedButton> confirmButtons(BuildContext context,
VoidCallback? onPressed,
List<ElevatedButton> 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<ElevatedButton> confirmButtons(BuildContext context,
];
}
List<TimeSeriesPoint<V>> sampleDaily<T, Y, V>(List<T> timeseries,
List<TimeSeriesPoint<V>> sampleDaily<T, Y, V>(
List<T> 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<void> 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<bool> showMessageBox(BuildContext context, String title, String content,
String label) async {
Future<bool> showMessageBox(
BuildContext context, String title, String content, String label) async {
final confirm = await showDialog<bool>(
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<String?> 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<String?> 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<bool> 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<bool> 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<void> 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<void> saveFile(String data, String filename, String title) async {
await saveFileBinary(utf8.encode(data), filename, title);
}
Future<void> saveFileBinary(List<int> data, String filename, String title) async {
Future<void> saveFileBinary(
List<int> data, String filename, String title) async {
if (isMobile()) {
final context = navigatorKey.currentContext!;
Size size = MediaQuery.of(context).size;
@ -860,10 +864,12 @@ Future<void> saveFileBinary(List<int> 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<void> saveFileBinary(List<int> data, String filename, String title) async
}
Future<void> 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<File> getRecoveryFile() async {
return f;
}
Future<bool> showConfirmDialog(BuildContext context, String title, String body) async {
Future<bool> showConfirmDialog(
BuildContext context, String title, String body) async {
final s = S.of(context);
final confirmation = await showDialog<bool>(
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<String> 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<String> 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 <void> onNotificationCreatedMethod(ReceivedNotification receivedNotification) async {
}
static Future<void> onNotificationCreatedMethod(
ReceivedNotification receivedNotification) async {}
/// Use this method to detect every time that a new notification is displayed
@pragma("vm:entry-point")
static Future <void> onNotificationDisplayedMethod(ReceivedNotification receivedNotification) async {
static Future<void> onNotificationDisplayedMethod(
ReceivedNotification receivedNotification) async {
FlutterRingtonePlayer.playNotification();
}
/// Use this method to detect if the user dismissed a notification
@pragma("vm:entry-point")
static Future <void> onDismissActionReceivedMethod(ReceivedAction receivedAction) async {
}
static Future<void> 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 <void> onActionReceivedMethod(ReceivedAction receivedAction) async {
}
static Future<void> onActionReceivedMethod(
ReceivedAction receivedAction) async {}
}
void resetApp() {
@ -992,40 +1005,46 @@ Future<bool> getDbPasswd(BuildContext context, String dbPath) async {
final formKey = GlobalKey<FormState>();
final reset = await showDialog<bool>(
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>[
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>[
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;
}

View File

@ -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<ScanTAddrPage> {
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<ScanTAddrPage> {
@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<ScanTAddrPage> {
Navigator.of(context).pop();
}
}

View File

@ -36,7 +36,6 @@ class SettingsState extends State<SettingsPage>
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<SettingsPage>
final simpleMode = settings.simpleMode;
_memoController.text = settings.memoSignature ?? s.sendFrom(APP_NAME);
final hasUA = active.coinDef.supportsUA;
final uaType = settings.uaType;
List<String> uaList = [];
@ -153,7 +151,6 @@ class SettingsState extends State<SettingsPage>
},
onSaved: _onProtectOpen)),
]),
if (!simpleMode)
FormBuilderCheckbox(
name: 'use_millis',
@ -191,7 +188,8 @@ class SettingsState extends State<SettingsPage>
FormBuilderCheckboxGroup<String>(
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<SettingsPage>
initialValue: settings.getTx,
onSaved: _onGetTx),
FormBuilderRadioGroup<int>(
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<int>(
decoration:
InputDecoration(labelText: s.minPrivacy),
InputDecoration(labelText: s.minPrivacy),
value: _minPrivacy,
items: getPrivacyOptions(context),
onChanged: (v) {
@ -235,41 +237,60 @@ class SettingsState extends State<SettingsPage>
title: Text(s.includeReplyTo),
initialValue: settings.includeReplyTo,
onSaved: _onIncludeReplyTo),
if (!simpleMode) Row(children: [
Expanded(child: DropdownButtonFormField<ViewStyle>(
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<ViewStyle>(
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<ViewStyle>(
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<ViewStyle>(
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<ViewStyle>(
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<ViewStyle>(
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<SettingsPage>
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<SettingsPage>
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<SettingsPage>
settings.setAnchorOffset(int.parse(v));
}
_onGapLimit(v) {
settings.setGapLimit(int.parse(v));
}
_onGetTx(v) {
settings.updateGetTx(v);
}

View File

@ -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<void> setGapLimit(int _gapLimit) async {
final prefs = await SharedPreferences.getInstance();
gapLimit = _gapLimit;
prefs.setInt('gap_limit', gapLimit);
}
@action
Future<void> setTheme(String thm) async {
final prefs = await SharedPreferences.getInstance();

@ -1 +1 @@
Subproject commit 09f2c1093027be54cc316a758a687f9a3f58ad08
Subproject commit ee7672569560ba1367f6449dd7a12347d42402f0

View File

@ -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<String> 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<String> 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<List<AddressBalance>> scanTransparentAccounts(
int coin, int account, int gapLimit) async {
return await compute(scanTransparentAccountsParamsIsolateFn,
ScanTransparentAccountsParams(gapLimit));
{'coin': coin, 'account': account, 'gapLimit': gapLimit});
}
static Future<String> prepareTx(int coin, int account,
List<Recipient> 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<String> signAndBroadcast (int coin, int account, String plan) async {
static Future<String> signAndBroadcast(
int coin, int account, String plan) async {
return await compute((_) {
final txid = warp_api_lib.sign_and_broadcast(coin, account, plan.toNativeUtf8().cast<Int8>());
final txid = warp_api_lib.sign_and_broadcast(
coin, account, plan.toNativeUtf8().cast<Int8>());
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<String> sweepTransparent(int latestHeight, String sk, int pool, int confirmations) async {
static Future<String> 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<Int8>());
coin, toNative(address), amount, memo.toNativeUtf8().cast<Int8>());
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<String> 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<Quote> 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<Spending> 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<Int8>(), 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<AddressBalance> scanTransparentAccountsParamsIsolateFn(
ScanTransparentAccountsParams params) {
final r = unwrapResultBytes(warp_api_lib.scan_transparent_accounts(params.gapLimit));
Map<String, Object> 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<Int8> s) {
final str = s.cast<Utf8>().toDartString();
warp_api_lib.deallocate_str(s);
@ -713,9 +746,9 @@ String convertCString(Pointer<Int8> s) {
}
List<int> convertBytes(Pointer<Uint8> 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) {

View File

@ -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,
);

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+408
version: 1.3.6+409
environment:
sdk: ">=2.12.0 <3.0.0"