zwallet/lib/txplan.dart

170 lines
6.1 KiB
Dart

import 'dart:convert';
import 'package:YWallet/main.dart';
import 'package:YWallet/settings.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:warp_api/types.dart';
import 'package:warp_api/warp_api.dart';
import 'generated/l10n.dart';
class TxPlanPage extends StatelessWidget {
final String plan;
final TxReport report;
final bool signOnly;
TxPlanPage(this.plan, this.report, this.signOnly);
factory TxPlanPage.fromPlan(String plan, bool signOnly) {
final reportStr = WarpApi.transactionReport(active.coin, plan);
final json = jsonDecode(reportStr);
final report = TxReport.fromJson(json);
return TxPlanPage(plan, report, signOnly);
}
@override
Widget build(BuildContext context) {
final s = S.of(context);
final t = Theme.of(context);
final supportsUA = active.coinDef.supportsUA;
final theme = Theme.of(context);
final rows = report.outputs
.map((e) => DataRow(cells: [
DataCell(Text('...${trailing(e.address, 12)}')),
DataCell(Text('${poolToString(e.pool)}')),
DataCell(Text('${amountToString(e.amount, 3)}')),
]))
.toList();
final invalidPrivacy = report.privacy_level < settings.minPrivacyLevel;
return Scaffold(
appBar: AppBar(title: Text('Transaction Plan')),
body: Padding(
padding: EdgeInsets.all(8),
child: SingleChildScrollView(child: Column(
children: [
Card(
child: DataTable(columnSpacing: 32, columns: [
DataColumn(label: Text('Address')),
DataColumn(label: Text('Pool')),
DataColumn(label: Expanded(child: Text('Amount'))),
], rows: rows)),
Divider(height: 16, thickness: 2, color: theme.primaryColor,),
ListTile(title: Text('Transparent Input'), trailing: Text(amountToString(report.transparent, MAX_PRECISION))),
ListTile(title: Text('Sapling Input'), trailing: Text(
amountToString(report.sapling, MAX_PRECISION))),
if (supportsUA) ListTile(title: Text('Orchard Input'), trailing: Text(
amountToString(report.orchard, MAX_PRECISION))),
ListTile(title: Text('Net Sapling Change'), trailing: Text(
amountToString(report.net_sapling, MAX_PRECISION))),
if (supportsUA) ListTile(title: Text('Net Orchard Change'), trailing: Text(
amountToString(report.net_orchard, MAX_PRECISION))),
ListTile(title: Text('Fee'), trailing: Text(amountToString(report.fee, MAX_PRECISION))),
privacyToString(context, report.privacy_level)!,
if (invalidPrivacy) Padding(padding: EdgeInsets.only(top: 8), child: Text(s.privacyLevelTooLow, style: t.textTheme.bodyLarge)),
ButtonBar(children:
<ElevatedButton>[
ElevatedButton.icon(
icon: Icon(Icons.cancel),
label: Text(s.cancel),
onPressed: () { Navigator.of(context).pop(); }),
ElevatedButton.icon(
icon: Icon(Icons.done),
label: Text(s.send),
onPressed: invalidPrivacy ? null: _onSend,
onLongPress: _onSend,
)],
)]))));
}
_onSend() async {
if (active.canPay) {
if (signOnly)
await _sign();
else {
Future(() async {
active.setBanner(S.current.paymentInProgress);
final player = AudioPlayer();
try {
final txid = await WarpApi.signAndBroadcast(active.coin, active.id, plan);
showSnackBar(S.current.txId(txid));
await player.play(AssetSource("success.mp3"));
active.setDraftRecipient(null);
active.update();
}
on String catch (message) {
showSnackBar(message);
await player.play(AssetSource("fail.mp3"));
}
finally {
active.setBanner("");
}
});
navigatorKey.currentState?.pop();
}
}
else {
if (settings.qrOffline) {
navigatorKey.currentState?.pushReplacementNamed('/qroffline', arguments: plan);
}
else {
await saveFile(plan, "tx.json", S.current.unsignedTransactionFile);
showSnackBar(S.current.fileSaved);
}
}
}
_sign() async {
try {
showSnackBar(S.current.signingPleaseWait);
final res = await WarpApi.signOnly(
active.coin, active.id, plan, (progress) {
// TODO progressPort.sendPort.send(progress);
// Orchard builder does not support progress reporting yet
});
// TODO progressPort.sendPort.send(0);
active.setBanner("");
active.setDraftRecipient(null);
if (settings.qrOffline) {
navigatorKey.currentState?.pushReplacementNamed(
'/showRawTx', arguments: res);
} else {
await saveFile(res, 'tx.raw', S.current.rawTransaction);
}
}
on String catch (error) {
showSnackBar(error);
}
}
}
String poolToString(int pool) {
switch (pool) {
case 0:
return "Transp.";
case 1:
return "Sapling";
}
return "Orchard";
}
Widget? privacyToString(BuildContext context, int privacyLevel) {
final m = S.of(context).privacy(getPrivacyLevel(context, privacyLevel).toUpperCase());
switch (privacyLevel) {
case 0: return getColoredButton(m, Colors.red);
case 1: return getColoredButton(m, Colors.orange);
case 2: return getColoredButton(m, Colors.yellow);
case 3: return getColoredButton(m, Colors.green);
}
return null;
}
ElevatedButton getColoredButton(String text, Color color) {
var foregroundColor = color.computeLuminance() > 0.5 ? Colors.black : Colors.white;
return ElevatedButton(onPressed: null, child: Text(text), style:
ElevatedButton.styleFrom(
disabledBackgroundColor: color, disabledForegroundColor: foregroundColor));
}