mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-03 17:29:23 +00:00
new broadcast tx progress animation
This commit is contained in:
parent
b527583a40
commit
89cc47525d
7 changed files with 148 additions and 36 deletions
1
assets/lottie/icon_send.json
Normal file
1
assets/lottie/icon_send.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"v":"5.10.2","fr":30,"ip":0,"op":100,"w":24,"h":24,"nm":"icon-send","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"MASK","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0.125,0.125,0],"ix":1,"l":2},"s":{"a":0,"k":[87.368,87.368,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[23.75,23.75],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.125,0.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Arrow","tt":1,"tp":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[-1.009,25.009,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[11.695,12.306,0],"to":[0,0,0],"ti":[0,0,0]},{"t":53,"s":[24.398,-0.397,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-0.69],[-0.69,0],[0,0],[0,0],[-0.488,-0.488],[-0.488,0.488],[0,0],[0,0],[-0.69,0],[0,0.69],[0,0],[0.234,0.234],[0.332,0]],"o":[[-0.69,0],[0,0.69],[0,0],[0,0],[-0.488,0.488],[0.488,0.488],[0,0],[0,0],[0,0.69],[0.69,0],[0,0],[0,-0.332],[-0.234,-0.234],[0,0]],"v":[[-2,-5.25],[-3.25,-4],[-2,-2.75],[0.982,-2.75],[-4.884,3.116],[-4.884,4.884],[-3.116,4.884],[2.75,-0.982],[2.75,2],[4,3.25],[5.25,2],[5.25,-4],[4.884,-4.884],[4,-5.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254908681,0.137254908681,0.137254908681,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Outline","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[12,0.063,0],"ix":1,"l":2},"s":{"a":0,"k":[90.104,90.104,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24,24],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.137254901961,0.137254901961,0.137254901961,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2.5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[12,0.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":58,"s":[0]},{"t":97,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":58,"s":[100]},{"t":97,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":100,"st":0,"ct":1,"bm":0}],"markers":[{"tm":0,"cm":"{\r\n\"name\":\"SEGMENT 1\"\r\n}","dr":0},{"tm":53,"cm":"{\r\n\"name\":\"SEGMENT 2\"\r\n}","dr":0},{"tm":97,"cm":"{\r\n\"name\":\"SEGMENT 3\"\r\n}","dr":0}]}
|
1
assets/lottie/loader_and_checkmark.json
Normal file
1
assets/lottie/loader_and_checkmark.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -66,6 +66,9 @@ class _ConfirmChangeNowSendViewState
|
||||||
Future<void> _attemptSend(BuildContext context) async {
|
Future<void> _attemptSend(BuildContext context) async {
|
||||||
final manager =
|
final manager =
|
||||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||||
|
|
||||||
|
final sendProgressController = ProgressAndSuccessController();
|
||||||
|
|
||||||
unawaited(
|
unawaited(
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -74,6 +77,7 @@ class _ConfirmChangeNowSendViewState
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return SendingTransactionDialog(
|
return SendingTransactionDialog(
|
||||||
coin: manager.coin,
|
coin: manager.coin,
|
||||||
|
controller: sendProgressController,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -105,6 +109,9 @@ class _ConfirmChangeNowSendViewState
|
||||||
time,
|
time,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
sendProgressController.triggerSuccess();
|
||||||
|
await Future<void>.delayed(const Duration(seconds: 5));
|
||||||
|
|
||||||
txid = results.first as String;
|
txid = results.first as String;
|
||||||
|
|
||||||
// save note
|
// save note
|
||||||
|
|
|
@ -80,6 +80,9 @@ class _ConfirmTransactionViewState
|
||||||
Future<void> _attemptSend(BuildContext context) async {
|
Future<void> _attemptSend(BuildContext context) async {
|
||||||
final manager =
|
final manager =
|
||||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||||
|
|
||||||
|
final sendProgressController = ProgressAndSuccessController();
|
||||||
|
|
||||||
unawaited(
|
unawaited(
|
||||||
showDialog<dynamic>(
|
showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -88,6 +91,7 @@ class _ConfirmTransactionViewState
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return SendingTransactionDialog(
|
return SendingTransactionDialog(
|
||||||
coin: manager.coin,
|
coin: manager.coin,
|
||||||
|
controller: sendProgressController,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -131,6 +135,9 @@ class _ConfirmTransactionViewState
|
||||||
time,
|
time,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
sendProgressController.triggerSuccess();
|
||||||
|
await Future<void>.delayed(const Duration(seconds: 5));
|
||||||
|
|
||||||
txid = results.first as String;
|
txid = results.first as String;
|
||||||
ref.refresh(desktopUseUTXOs);
|
ref.refresh(desktopUseUTXOs);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:lottie/lottie.dart';
|
||||||
import 'package:stackwallet/utilities/assets.dart';
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
@ -13,38 +13,29 @@ class SendingTransactionDialog extends StatefulWidget {
|
||||||
const SendingTransactionDialog({
|
const SendingTransactionDialog({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.coin,
|
required this.coin,
|
||||||
|
required this.controller,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Coin coin;
|
final Coin coin;
|
||||||
|
final ProgressAndSuccessController controller;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SendingTransactionDialog> createState() => _RestoringDialogState();
|
State<SendingTransactionDialog> createState() => _RestoringDialogState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RestoringDialogState extends State<SendingTransactionDialog>
|
class _RestoringDialogState extends State<SendingTransactionDialog> {
|
||||||
with TickerProviderStateMixin {
|
late ProgressAndSuccessController? _progressAndSuccessController;
|
||||||
late AnimationController? _spinController;
|
|
||||||
late Animation<double> _spinAnimation;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_spinController = AnimationController(
|
_progressAndSuccessController = widget.controller;
|
||||||
duration: const Duration(seconds: 2),
|
|
||||||
vsync: this,
|
|
||||||
)..repeat();
|
|
||||||
|
|
||||||
_spinAnimation = CurvedAnimation(
|
|
||||||
parent: _spinController!,
|
|
||||||
curve: Curves.linear,
|
|
||||||
);
|
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_spinController?.dispose();
|
_progressAndSuccessController = null;
|
||||||
_spinController = null;
|
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
@ -76,16 +67,8 @@ class _RestoringDialogState extends State<SendingTransactionDialog>
|
||||||
Assets.gif.kiss(widget.coin),
|
Assets.gif.kiss(widget.coin),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: RotationTransition(
|
: ProgressAndSuccess(
|
||||||
turns: _spinAnimation,
|
controller: _progressAndSuccessController!,
|
||||||
child: SvgPicture.asset(
|
|
||||||
Assets.svg.arrowRotate,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.accentColorDark,
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -120,19 +103,128 @@ class _RestoringDialogState extends State<SendingTransactionDialog>
|
||||||
)
|
)
|
||||||
: StackDialog(
|
: StackDialog(
|
||||||
title: "Sending transaction",
|
title: "Sending transaction",
|
||||||
icon: RotationTransition(
|
icon: ProgressAndSuccess(
|
||||||
turns: _spinAnimation,
|
controller: _progressAndSuccessController!,
|
||||||
child: SvgPicture.asset(
|
|
||||||
Assets.svg.arrowRotate,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.accentColorDark,
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ProgressAndSuccessController {
|
||||||
|
late VoidCallback triggerSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProgressAndSuccess extends StatefulWidget {
|
||||||
|
const ProgressAndSuccess({
|
||||||
|
Key? key,
|
||||||
|
this.height = 24,
|
||||||
|
this.width = 24,
|
||||||
|
required this.controller,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final double height;
|
||||||
|
final double width;
|
||||||
|
final ProgressAndSuccessController controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ProgressAndSuccess> createState() => _ProgressAndSuccessState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ProgressAndSuccessState extends State<ProgressAndSuccess>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
late final AnimationController controller1;
|
||||||
|
late final AnimationController controller2;
|
||||||
|
|
||||||
|
CrossFadeState _crossFadeState = CrossFadeState.showFirst;
|
||||||
|
|
||||||
|
bool _triggered = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
controller1 = AnimationController(vsync: this);
|
||||||
|
controller2 = AnimationController(vsync: this);
|
||||||
|
|
||||||
|
controller1.addListener(() => setState(() {}));
|
||||||
|
controller2.addListener(() => setState(() {}));
|
||||||
|
|
||||||
|
controller1.addStatusListener((status) {
|
||||||
|
if (status == AnimationStatus.completed && _triggered) {
|
||||||
|
controller2.forward();
|
||||||
|
setState(() {
|
||||||
|
_crossFadeState = CrossFadeState.showSecond;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
widget.controller.triggerSuccess = () {
|
||||||
|
controller1.forward();
|
||||||
|
_triggered = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
controller1.dispose();
|
||||||
|
controller2.dispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedCrossFade(
|
||||||
|
crossFadeState: _crossFadeState,
|
||||||
|
firstChild: Lottie.asset(
|
||||||
|
Assets.lottie.iconSend,
|
||||||
|
controller: controller1,
|
||||||
|
width: widget.width,
|
||||||
|
delegates: LottieDelegates(
|
||||||
|
values: [
|
||||||
|
ValueDelegate.color(
|
||||||
|
const ["**"],
|
||||||
|
value:
|
||||||
|
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||||
|
),
|
||||||
|
ValueDelegate.strokeColor(
|
||||||
|
const ["**"],
|
||||||
|
value:
|
||||||
|
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
height: widget.height,
|
||||||
|
onLoaded: (composition) {
|
||||||
|
final start = composition.markers[0].start;
|
||||||
|
final end = composition.markers[1].start;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
controller1.duration = composition.duration;
|
||||||
|
});
|
||||||
|
controller1.repeat(
|
||||||
|
min: start,
|
||||||
|
max: end,
|
||||||
|
period: composition.duration * (end - start),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
secondChild: Lottie.asset(
|
||||||
|
Assets.lottie.loaderAndCheckmark,
|
||||||
|
controller: controller2,
|
||||||
|
width: widget.width,
|
||||||
|
height: widget.height,
|
||||||
|
onLoaded: (composition) {
|
||||||
|
setState(() {
|
||||||
|
controller2.duration = composition.duration *
|
||||||
|
(composition.markers.last.end - composition.markers[1].start);
|
||||||
|
controller2.value = composition.markers[1].start;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
duration: const Duration(microseconds: 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -415,6 +415,8 @@ class _ANIMATIONS {
|
||||||
const _ANIMATIONS();
|
const _ANIMATIONS();
|
||||||
|
|
||||||
String get test2 => "assets/lottie/test2.json";
|
String get test2 => "assets/lottie/test2.json";
|
||||||
|
String get iconSend => "assets/lottie/icon_send.json";
|
||||||
|
String get loaderAndCheckmark => "assets/lottie/loader_and_checkmark.json";
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GIF {
|
class _GIF {
|
||||||
|
|
|
@ -381,6 +381,8 @@ flutter:
|
||||||
# lottie animations
|
# lottie animations
|
||||||
# basic
|
# basic
|
||||||
- assets/lottie/test2.json
|
- assets/lottie/test2.json
|
||||||
|
- assets/lottie/icon_send.json
|
||||||
|
- assets/lottie/loader_and_checkmark.json
|
||||||
|
|
||||||
# gifs
|
# gifs
|
||||||
- assets/gif/
|
- assets/gif/
|
||||||
|
|
Loading…
Reference in a new issue