Export P/L

Fix Payment URI scan missing amount
This commit is contained in:
Hanh 2021-10-10 10:11:40 +08:00
parent ec7fabdd06
commit 6fdb70cbe4
12 changed files with 116 additions and 52 deletions

View File

@ -13,7 +13,6 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import 'package:sensors_plus/sensors_plus.dart'; import 'package:sensors_plus/sensors_plus.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:warp/payment_uri.dart';
import 'package:warp/store.dart'; import 'package:warp/store.dart';
import 'package:warp_api/warp_api.dart'; import 'package:warp_api/warp_api.dart';
@ -592,36 +591,54 @@ class PnLState extends State<PnLWidget> with AutomaticKeepAliveClientMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column(children: [ return IconTheme.merge(
FormBuilderRadioGroup( data: IconThemeData(opacity: 0.54),
orientation: OptionsOrientation.horizontal, child:
name: S.of(context).pnl, Column(children: [
initialValue: accountManager.pnlSeriesIndex, Row(children: [
onChanged: (int? v) { Expanded(child:
setState(() { FormBuilderRadioGroup(
accountManager.setPnlSeriesIndex(v!); orientation: OptionsOrientation.horizontal,
}); name: S.of(context).pnl,
}, initialValue: accountManager.pnlSeriesIndex,
options: [ onChanged: (int? v) {
FormBuilderFieldOption(child: Text(S.of(context).price), value: 0), setState(() {
FormBuilderFieldOption( accountManager.setPnlSeriesIndex(v!);
child: Text(S.of(context).realized), value: 1), });
FormBuilderFieldOption(child: Text(S.of(context).mm), value: 2), },
FormBuilderFieldOption(child: Text(S.of(context).total), value: 3), options: [
FormBuilderFieldOption(child: Text(S.of(context).qty), value: 4), FormBuilderFieldOption(child: Text(S.of(context).price), value: 0),
FormBuilderFieldOption(child: Text(S.of(context).table), value: 5), FormBuilderFieldOption(
child: Text(S.of(context).realized), value: 1),
FormBuilderFieldOption(child: Text(S.of(context).mm), value: 2),
FormBuilderFieldOption(child: Text(S.of(context).total), value: 3),
FormBuilderFieldOption(child: Text(S.of(context).qty), value: 4),
FormBuilderFieldOption(child: Text(S.of(context).table), value: 5),
])),
IconButton(onPressed: _onExport, icon: Icon(Icons.save)),
]), ]),
Observer(builder: (context) { Observer(builder: (context) {
final _ = accountManager.pnlSorted; final _ = accountManager.pnlSorted;
return Expanded( return Expanded(
child: Padding( child: Padding(
padding: EdgeInsets.only(right: 20), padding: EdgeInsets.only(right: 20),
child: accountManager.pnlSeriesIndex != 5 child: accountManager.pnlSeriesIndex != 5
? PnLChart( ? PnLChart(
accountManager.pnls, accountManager.pnlSeriesIndex) accountManager.pnls, accountManager.pnlSeriesIndex)
: PnLTable())); : PnLTable()));
}) })
]); ]));
}
_onExport() async {
final csvData = accountManager.pnlSorted.map((pnl) => [
pnl.timestamp,
pnl.amount,
pnl.price,
pnl.realized,
pnl.unrealized,
pnl.realized + pnl.unrealized]).toList();
await shareCsv(csvData, 'pnl_history.csv', S.of(context).pnlHistory);
} }
} }

View File

@ -178,6 +178,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Please authenticate to show account seed"), "Please authenticate to show account seed"),
"pleaseConfirm": MessageLookupByLibrary.simpleMessage("Please Confirm"), "pleaseConfirm": MessageLookupByLibrary.simpleMessage("Please Confirm"),
"pnl": MessageLookupByLibrary.simpleMessage("Pnl"), "pnl": MessageLookupByLibrary.simpleMessage("Pnl"),
"pnlHistory": MessageLookupByLibrary.simpleMessage("PNL History"),
"preparingTransaction": "preparingTransaction":
MessageLookupByLibrary.simpleMessage("Preparing transaction..."), MessageLookupByLibrary.simpleMessage("Preparing transaction..."),
"price": MessageLookupByLibrary.simpleMessage("Price"), "price": MessageLookupByLibrary.simpleMessage("Price"),

View File

@ -179,6 +179,7 @@ class MessageLookup extends MessageLookupByLibrary {
"pleaseConfirm": "pleaseConfirm":
MessageLookupByLibrary.simpleMessage("Por favor, confirmar"), MessageLookupByLibrary.simpleMessage("Por favor, confirmar"),
"pnl": MessageLookupByLibrary.simpleMessage("Pnl"), "pnl": MessageLookupByLibrary.simpleMessage("Pnl"),
"pnlHistory": MessageLookupByLibrary.simpleMessage("PNL History"),
"preparingTransaction": "preparingTransaction":
MessageLookupByLibrary.simpleMessage("Preparando la transacción…"), MessageLookupByLibrary.simpleMessage("Preparando la transacción…"),
"price": MessageLookupByLibrary.simpleMessage("Precio"), "price": MessageLookupByLibrary.simpleMessage("Precio"),

View File

@ -179,6 +179,7 @@ class MessageLookup extends MessageLookupByLibrary {
"pleaseConfirm": "pleaseConfirm":
MessageLookupByLibrary.simpleMessage("Veuillez confirmer"), MessageLookupByLibrary.simpleMessage("Veuillez confirmer"),
"pnl": MessageLookupByLibrary.simpleMessage("P/P"), "pnl": MessageLookupByLibrary.simpleMessage("P/P"),
"pnlHistory": MessageLookupByLibrary.simpleMessage("PNL History"),
"preparingTransaction": MessageLookupByLibrary.simpleMessage( "preparingTransaction": MessageLookupByLibrary.simpleMessage(
"Préparation de la transaction..."), "Préparation de la transaction..."),
"price": MessageLookupByLibrary.simpleMessage("Prix"), "price": MessageLookupByLibrary.simpleMessage("Prix"),

View File

@ -1591,6 +1591,16 @@ class S {
args: [ticker], args: [ticker],
); );
} }
/// `PNL History`
String get pnlHistory {
return Intl.message(
'PNL History',
name: 'pnlHistory',
desc: '',
args: [],
);
}
} }
class AppLocalizationDelegate extends LocalizationsDelegate<S> { class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

@ -1,11 +1,7 @@
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:csv/csv.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
import 'main.dart'; import 'main.dart';
import 'generated/l10n.dart'; import 'generated/l10n.dart';
@ -108,13 +104,7 @@ class HistoryState extends State<HistoryWidget>
final csvData = accountManager.sortedTxs.map((tx) => [ final csvData = accountManager.sortedTxs.map((tx) => [
tx.fullTxId, tx.height, tx.timestamp, tx.address, tx.contact ?? '', tx.fullTxId, tx.height, tx.timestamp, tx.address, tx.contact ?? '',
tx.value, tx.memo]).toList(); tx.value, tx.memo]).toList();
final csvConverter = ListToCsvConverter(); await shareCsv(csvData, 'tx_history.csv', S.of(context).transactionHistory);
final csv = csvConverter.convert(csvData);
Directory tempDir = await getTemporaryDirectory();
String filename = "${tempDir.path}/tx_history.csv";
final file = File(filename);
await file.writeAsString(csv);
Share.shareFiles([filename], subject: S.of(context).transactionHistory);
} }
} }

View File

@ -152,5 +152,6 @@
"tapTransactionForDetails": "Tap Transaction for Details", "tapTransactionForDetails": "Tap Transaction for Details",
"transactionHistory": "Transaction History", "transactionHistory": "Transaction History",
"help": "Help", "help": "Help",
"receive": "Receive {ticker}" "receive": "Receive {ticker}",
"pnlHistory": "PNL History"
} }

View File

@ -152,5 +152,6 @@
"tapTransactionForDetails": "Tap Transaction for Details", "tapTransactionForDetails": "Tap Transaction for Details",
"transactionHistory": "Transaction History", "transactionHistory": "Transaction History",
"help": "Help", "help": "Help",
"receive": "Receive {ticker}" "receive": "Receive {ticker}",
"pnlHistory": "PNL History"
} }

View File

@ -152,5 +152,6 @@
"tapTransactionForDetails": "Presser sur une Transaction pour plus de details", "tapTransactionForDetails": "Presser sur une Transaction pour plus de details",
"transactionHistory": "Historique des Transactions", "transactionHistory": "Historique des Transactions",
"help": "Aide", "help": "Aide",
"receive": "Recevoir {ticker}" "receive": "Recevoir {ticker}",
"pnlHistory": "PNL History"
} }

View File

@ -1,7 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:ui'; import 'dart:ui';
import 'package:csv/csv.dart';
import 'package:currency_text_input_formatter/currency_text_input_formatter.dart'; import 'package:currency_text_input_formatter/currency_text_input_formatter.dart';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -11,8 +13,10 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:local_auth/local_auth.dart'; import 'package:local_auth/local_auth.dart';
import 'package:path/path.dart'; import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import 'package:rate_my_app/rate_my_app.dart'; import 'package:rate_my_app/rate_my_app.dart';
import 'package:share_plus/share_plus.dart';
import 'package:sqflite/sqflite.dart'; import 'package:sqflite/sqflite.dart';
import 'package:warp_api/warp_api.dart'; import 'package:warp_api/warp_api.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
@ -64,9 +68,13 @@ Future<void> initUniLinks(BuildContext context) async {
try { try {
final initialLink = await getInitialLink(); final initialLink = await getInitialLink();
if (initialLink != null) if (initialLink != null)
Navigator.of(context).pushNamed('/send', arguments: SendPageArgs(uri: initialLink)); Navigator.of(context).pushNamed('/send', arguments: SendPageArgs(uri: initialLink));
} on PlatformException { } on PlatformException {
} }
subUniLinks = linkStream.listen((String? uri) {
Navigator.of(context).pushNamed('/send', arguments: SendPageArgs(uri: uri));
});
} }
void handleQuickAction(BuildContext context, String shortcut) { void handleQuickAction(BuildContext context, String shortcut) {
@ -163,11 +171,20 @@ class ZWalletAppState extends State<ZWalletApp> {
await syncStatus.init(); await syncStatus.init();
await initUniLinks(context); await initUniLinks(context);
final quickActions = QuickActions(); final quickActions = QuickActions();
quickActions.setShortcutItems(<ShortcutItem>[ quickActions.initialize((type) {
ShortcutItem(type: 'receive', localizedTitle: s.receive(coin.ticker), icon: 'receive'), handleQuickAction(this.context, type);
ShortcutItem(type: 'send', localizedTitle: s.sendCointicker(coin.ticker), icon: 'send'), });
]); if (!settings.linkHooksInitialized) {
quickActions.initialize((type) { handleQuickAction(this.context, type); }); quickActions.setShortcutItems(<ShortcutItem>[
ShortcutItem(type: 'receive',
localizedTitle: s.receive(coin.ticker),
icon: 'receive'),
ShortcutItem(type: 'send',
localizedTitle: s.sendCointicker(coin.ticker),
icon: 'send'),
]);
await settings.setLinkHooksInitialized();
}
} }
return true; return true;
} }
@ -420,3 +437,13 @@ Future<void> shieldTAddr(BuildContext context) async {
); );
} }
Future<void> shareCsv(List<List> data, String filename, String title) async {
final csvConverter = ListToCsvConverter();
final csv = csvConverter.convert(data);
Directory tempDir = await getTemporaryDirectory();
String fn = "${tempDir.path}/$filename";
final file = File(fn);
await file.writeAsString(csv);
await Share.shareFiles([fn], subject: title);
}

View File

@ -52,8 +52,11 @@ class SendState extends State<SendPage> {
if (widget.args?.contact != null) if (widget.args?.contact != null)
_addressController.text = widget.args!.contact!.address; _addressController.text = widget.args!.contact!.address;
if (widget.args?.uri != null) final uri = widget.args?.uri;
_setPaymentURI(widget.args!.uri!); if (uri != null)
Future.microtask(() {
_setPaymentURI(uri);
});
super.initState(); super.initState();

View File

@ -24,6 +24,9 @@ part 'store.g.dart';
class Settings = _Settings with _$Settings; class Settings = _Settings with _$Settings;
abstract class _Settings with Store { abstract class _Settings with Store {
@observable
bool linkHooksInitialized = false;
@observable @observable
String ldUrl = ""; String ldUrl = "";
@ -78,6 +81,7 @@ abstract class _Settings with Store {
@action @action
Future<bool> restore() async { Future<bool> restore() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
linkHooksInitialized = prefs.getBool('link_hooks') ?? false;
ldUrlChoice = prefs.getString('lightwalletd_choice') ?? "Lightwalletd"; ldUrlChoice = prefs.getString('lightwalletd_choice') ?? "Lightwalletd";
ldUrl = prefs.getString('lightwalletd_custom') ?? ""; ldUrl = prefs.getString('lightwalletd_custom') ?? "";
prefs.setString('lightwalletd_choice', ldUrlChoice); prefs.setString('lightwalletd_choice', ldUrlChoice);
@ -100,6 +104,13 @@ abstract class _Settings with Store {
return true; return true;
} }
@action
Future<void> setLinkHooksInitialized() async {
final prefs = await SharedPreferences.getInstance();
linkHooksInitialized = true;
prefs.setBool('link_hooks', true);
}
@action @action
Future<void> setURLChoice(String choice) async { Future<void> setURLChoice(String choice) async {
ldUrlChoice = choice; ldUrlChoice = choice;