zwallet/lib/account.dart

319 lines
10 KiB
Dart
Raw Normal View History

2021-06-26 07:30:12 -07:00
import 'dart:async';
import 'package:flutter/material.dart';
2021-07-10 22:20:53 -07:00
import 'package:flutter/services.dart';
2021-06-26 07:30:12 -07:00
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
2021-06-26 07:30:12 -07:00
import 'package:qr_flutter/qr_flutter.dart';
2022-06-16 03:16:32 -07:00
import 'package:animated_text_kit/animated_text_kit.dart';
2021-06-26 07:30:12 -07:00
2021-08-15 09:18:09 -07:00
import 'generated/l10n.dart';
2022-03-07 06:53:18 -08:00
import 'main.dart';
import 'store.dart';
2021-06-26 07:30:12 -07:00
2022-04-18 23:49:46 -07:00
class AccountPage extends StatefulWidget {
2021-06-26 07:30:12 -07:00
@override
2022-03-07 06:53:18 -08:00
_AccountState createState() => _AccountState();
2021-06-26 07:30:12 -07:00
}
2022-04-18 23:49:46 -07:00
class _AccountState extends State<AccountPage> with AutomaticKeepAliveClientMixin {
2021-06-26 07:30:12 -07:00
@override
2022-03-07 06:53:18 -08:00
bool get wantKeepAlive => true; //Set to true
2021-06-26 07:30:12 -07:00
@override
2022-03-07 06:53:18 -08:00
Widget build(BuildContext context) {
super.build(context);
return SingleChildScrollView(
2022-03-30 22:25:52 -07:00
child: Column(children: [
2022-03-07 06:53:18 -08:00
SyncStatusWidget(),
QRAddressWidget(),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
BalanceWidget(),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
MemPoolWidget(),
ProgressWidget(),
2022-03-30 22:25:52 -07:00
])
);
2021-06-26 07:30:12 -07:00
}
2022-03-07 06:53:18 -08:00
}
2021-06-26 07:30:12 -07:00
2022-03-07 06:53:18 -08:00
class SyncStatusWidget extends StatelessWidget {
2021-06-26 07:30:12 -07:00
@override
Widget build(BuildContext context) {
2022-03-07 06:53:18 -08:00
final s = S.of(context);
final theme = Theme.of(context);
2022-02-22 21:20:45 -08:00
final simpleMode = settings.simpleMode;
2022-03-07 06:53:18 -08:00
return Column(children: [
2022-03-16 09:12:05 -07:00
if (simpleMode) Padding(padding: EdgeInsets.fromLTRB(0, 8, 0, 0), child: Text(s.simpleMode)),
2022-03-07 06:53:18 -08:00
Observer(builder: (context) {
final time = eta.eta;
final syncedHeight = syncStatus.syncedHeight;
final latestHeight = syncStatus.latestHeight;
2022-06-16 03:16:32 -07:00
final percent = latestHeight > 0 ? 100 * (syncedHeight ?? 0) ~/ latestHeight : 0;
2022-03-16 21:03:37 -07:00
final text = latestHeight == 0 ? Text(s.disconnected)
: syncedHeight == null
2022-03-07 06:53:18 -08:00
? Text(s.rescanNeeded)
: syncStatus.isSynced()
? Text('$syncedHeight', style: theme.textTheme.caption)
2022-06-16 03:16:32 -07:00
: AnimatedTextKit(
key: ValueKey(syncedHeight),
repeatForever: true,
animatedTexts: [
2022-06-17 17:40:25 -07:00
WavyAnimatedText('$syncedHeight / $latestHeight',
2022-06-16 03:16:32 -07:00
textStyle: theme.textTheme.caption!
.apply(color: theme.primaryColor)),
2022-06-17 17:40:25 -07:00
WavyAnimatedText('SYNCING $percent %',
2022-06-16 03:16:32 -07:00
textStyle: theme.textTheme.caption!
.apply(color: theme.primaryColor)),
2022-06-17 17:40:25 -07:00
WavyAnimatedText('$time',
2022-06-16 03:16:32 -07:00
textStyle: theme.textTheme.caption!
.apply(color: theme.primaryColor)),
]);
2022-07-08 18:51:23 -07:00
return TextButton(onPressed: () => _onSync(context), child: text);
2022-03-07 06:53:18 -08:00
})
]);
2021-07-12 04:32:49 -07:00
}
2022-03-16 00:43:38 -07:00
2022-07-08 18:51:23 -07:00
_onSync(BuildContext context) {
if (syncStatus.syncedHeight != null)
Future.microtask(syncStatus.sync);
else
rescan(context);
2022-03-16 00:43:38 -07:00
}
2022-03-07 06:53:18 -08:00
}
2021-07-12 04:32:49 -07:00
2022-03-07 06:53:18 -08:00
class QRAddressWidget extends StatefulWidget {
@override
QRAddressState createState() => QRAddressState();
}
2021-08-27 02:51:34 -07:00
2022-03-07 06:53:18 -08:00
class QRAddressState extends State<QRAddressWidget> {
bool _useSnapAddress = false;
String _snapAddress = "";
2021-07-10 22:20:53 -07:00
2022-03-07 06:53:18 -08:00
@override
Widget build(BuildContext context) {
return Observer(builder: (context) {
final s = S.of(context);
final theme = Theme.of(context);
final simpleMode = settings.simpleMode;
final address = _address();
2022-04-15 23:51:13 -07:00
final shortAddress = centerTrim(address);
2022-03-07 06:53:18 -08:00
final showTAddr = active.showTAddr;
final hasTAddr = active.taddress.isNotEmpty;
final flat = settings.flat;
final qrSize = getScreenSize(context) / 2.5;
final hide = settings.autoHide && flat;
final coinDef = active.coinDef;
return Column(children: [
if (hasTAddr)
Text(showTAddr
? s.tapQrCodeForShieldedAddress
: s.tapQrCodeForTransparentAddress),
Padding(padding: EdgeInsets.symmetric(vertical: 4)),
GestureDetector(
onTap: hasTAddr ? _onQRTap : null,
child: RotatedBox(
quarterTurns: hide ? 2 : 0,
child: QrImage(
data: address,
size: qrSize,
embeddedImage: coinDef.image,
backgroundColor: Colors.white))),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
RichText(
text: TextSpan(children: [
TextSpan(text: '$shortAddress ', style: theme.textTheme.bodyText2),
WidgetSpan(
child: GestureDetector(
child: Icon(Icons.content_copy), onTap: _onAddressCopy)),
WidgetSpan(
child: Padding(padding: EdgeInsets.symmetric(horizontal: 4))),
WidgetSpan(
child: GestureDetector(
child: Icon(MdiIcons.qrcodeScan), onTap: _onReceive)),
])),
Padding(padding: EdgeInsets.symmetric(vertical: 4)),
if (!simpleMode && !showTAddr)
OutlinedButton(
child: Text(s.newSnapAddress),
style: OutlinedButton.styleFrom(
side: BorderSide(width: 1, color: theme.primaryColor)),
onPressed: _onSnapAddress),
if (!simpleMode && showTAddr)
OutlinedButton(
child: Text(s.shieldTranspBalance),
style: OutlinedButton.styleFrom(
side: BorderSide(width: 1, color: theme.primaryColor)),
onPressed: () {
shieldTAddr(context);
},
)
]);
});
2021-06-26 07:30:12 -07:00
}
2021-07-09 06:33:39 -07:00
_onQRTap() {
2022-03-07 06:53:18 -08:00
active.toggleShowTAddr();
2021-07-09 06:33:39 -07:00
}
2021-07-10 22:20:53 -07:00
_onAddressCopy() {
Clipboard.setData(ClipboardData(text: _address()));
2021-08-23 19:04:45 -07:00
final snackBar =
SnackBar(content: Text(S.of(context).addressCopiedToClipboard));
2021-09-10 02:56:15 -07:00
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar);
2021-07-10 22:20:53 -07:00
}
2021-09-25 02:09:41 -07:00
_onReceive() async {
2021-10-08 23:12:51 -07:00
Navigator.of(context).pushNamed('/receive', arguments: _address());
}
2021-07-07 21:22:54 -07:00
_onSnapAddress() {
2022-03-07 06:53:18 -08:00
final address = active.newAddress();
2021-07-07 21:22:54 -07:00
setState(() {
_useSnapAddress = true;
_snapAddress = address;
});
Timer(Duration(seconds: 15), () {
setState(() {
_useSnapAddress = false;
});
});
}
2021-07-09 06:33:39 -07:00
2022-03-07 06:53:18 -08:00
String _address() {
final address = active.showTAddr
? active.taddress
: _useSnapAddress
? _snapAddress
: active.account.address;
return address;
}
2021-06-26 07:30:12 -07:00
}
2022-03-07 06:53:18 -08:00
class BalanceWidget extends StatelessWidget {
2021-07-12 04:32:49 -07:00
@override
2022-03-07 06:53:18 -08:00
Widget build(BuildContext context) => Observer(builder: (context) {
final s = S.of(context);
final theme = Theme.of(context);
final flat = settings.flat;
final hide = settings.autoHide && flat;
final showTAddr = active.showTAddr;
final balance = showTAddr ? active.tbalance : active.balances.balance;
final balanceColor = !showTAddr
? theme.colorScheme.primaryVariant
: theme.colorScheme.secondaryVariant;
final balanceHi = hide ? '-------' : _getBalanceHi(balance);
final deviceWidth = getWidth(context);
final digits = deviceWidth.index < DeviceWidth.sm.index ? 7 : 9;
final balanceStyle = (balanceHi.length > digits
? theme.textTheme.headline4
: theme.textTheme.headline2)!
.copyWith(color: balanceColor);
final fx = priceStore.coinPrice;
final balanceFX = balance * fx / ZECUNIT;
final coinDef = active.coinDef;
return Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.ideographic,
children: <Widget>[
if (!hide)
Text('${coinDef.symbol}', style: theme.textTheme.headline5),
Text(' $balanceHi', style: balanceStyle),
if (!hide) Text('${_getBalanceLo(balance)}'),
]),
if (hide) Text(s.tiltYourDeviceUpToRevealYourBalance),
if (!hide && fx != 0.0)
Text("${decimalFormat(balanceFX, 2, symbol: settings.currency)}",
style: theme.textTheme.headline6),
if (!hide && fx != 0.0)
Text(
"1 ${coinDef.ticker} = ${decimalFormat(
fx, 2, symbol: settings.currency)}"),
]);
});
2021-07-12 04:32:49 -07:00
}
2022-03-07 06:53:18 -08:00
class MemPoolWidget extends StatelessWidget {
2021-07-12 04:32:49 -07:00
@override
2022-03-07 06:53:18 -08:00
Widget build(BuildContext context) => Observer(builder: (context) {
final b = active.balances;
final theme = Theme.of(context);
final unconfirmedBalance = b.unconfirmedBalance;
if (unconfirmedBalance == 0) return Container();
final unconfirmedStyle = TextStyle(
color: amountColor(context, unconfirmedBalance));
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.ideographic,
children: <Widget>[
Text(
'${_sign(unconfirmedBalance)} ${_getBalanceHi(unconfirmedBalance)}',
style: theme.textTheme.headline4
?.merge(unconfirmedStyle)),
Text(
'${_getBalanceLo(unconfirmedBalance)}',
style: unconfirmedStyle),
]);
});
2021-07-12 04:32:49 -07:00
}
2021-07-18 08:59:02 -07:00
2022-03-07 06:53:18 -08:00
class ProgressWidget extends StatefulWidget {
2021-08-09 07:13:42 -07:00
@override
2022-03-07 06:53:18 -08:00
ProgressState createState() => ProgressState();
2021-08-09 07:13:42 -07:00
}
2022-03-07 06:53:18 -08:00
class ProgressState extends State<ProgressWidget> {
int _progress = 0;
StreamSubscription? _progressDispose;
2021-08-09 07:13:42 -07:00
@override
2022-03-07 06:53:18 -08:00
void initState() {
super.initState();
_progressDispose = progressStream.listen((percent) {
setState(() {
_progress = percent;
});
});
2021-08-09 07:13:42 -07:00
}
@override
2022-03-07 06:53:18 -08:00
void dispose() {
_progressDispose?.cancel();
super.dispose();
2021-08-09 07:13:42 -07:00
}
@override
Widget build(BuildContext context) {
2022-06-16 18:30:10 -07:00
final theme = Theme.of(context);
2022-06-16 03:16:32 -07:00
return Observer(builder: (context) => Column(children: [
if (active.banner.isNotEmpty) DefaultTextStyle(
2022-06-16 18:30:10 -07:00
style: theme.textTheme.titleLarge!,
2022-06-16 03:16:32 -07:00
child: AnimatedTextKit(
repeatForever: true,
animatedTexts: [
TypewriterAnimatedText(active.banner)]
)),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
if (_progress != 0) LinearProgressIndicator(value: _progress / 100.0),
]));
2021-08-09 07:13:42 -07:00
}
}
2022-03-07 06:53:18 -08:00
_getBalanceHi(int b) => decimalFormat((b.abs() ~/ 100000) / 1000.0, 3);
2021-08-09 07:13:42 -07:00
2022-03-07 06:53:18 -08:00
_getBalanceLo(int b) => (b.abs() % 100000).toString().padLeft(5, '0');
2021-08-09 07:13:42 -07:00
2022-03-07 06:53:18 -08:00
_sign(int b) => b < 0 ? '-' : '+';