new broadcast tx progress animation

This commit is contained in:
julian 2023-04-20 17:39:16 -06:00
parent b527583a40
commit 89cc47525d
7 changed files with 148 additions and 36 deletions

View 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}]}

File diff suppressed because one or more lines are too long

View file

@ -66,6 +66,9 @@ class _ConfirmChangeNowSendViewState
Future<void> _attemptSend(BuildContext context) async {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
final sendProgressController = ProgressAndSuccessController();
unawaited(
showDialog<void>(
context: context,
@ -74,6 +77,7 @@ class _ConfirmChangeNowSendViewState
builder: (context) {
return SendingTransactionDialog(
coin: manager.coin,
controller: sendProgressController,
);
},
),
@ -105,6 +109,9 @@ class _ConfirmChangeNowSendViewState
time,
]);
sendProgressController.triggerSuccess();
await Future<void>.delayed(const Duration(seconds: 5));
txid = results.first as String;
// save note

View file

@ -80,6 +80,9 @@ class _ConfirmTransactionViewState
Future<void> _attemptSend(BuildContext context) async {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
final sendProgressController = ProgressAndSuccessController();
unawaited(
showDialog<dynamic>(
context: context,
@ -88,6 +91,7 @@ class _ConfirmTransactionViewState
builder: (context) {
return SendingTransactionDialog(
coin: manager.coin,
controller: sendProgressController,
);
},
),
@ -131,6 +135,9 @@ class _ConfirmTransactionViewState
time,
]);
sendProgressController.triggerSuccess();
await Future<void>.delayed(const Duration(seconds: 5));
txid = results.first as String;
ref.refresh(desktopUseUTXOs);

View file

@ -1,5 +1,5 @@
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/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
@ -13,38 +13,29 @@ class SendingTransactionDialog extends StatefulWidget {
const SendingTransactionDialog({
Key? key,
required this.coin,
required this.controller,
}) : super(key: key);
final Coin coin;
final ProgressAndSuccessController controller;
@override
State<SendingTransactionDialog> createState() => _RestoringDialogState();
}
class _RestoringDialogState extends State<SendingTransactionDialog>
with TickerProviderStateMixin {
late AnimationController? _spinController;
late Animation<double> _spinAnimation;
class _RestoringDialogState extends State<SendingTransactionDialog> {
late ProgressAndSuccessController? _progressAndSuccessController;
@override
void initState() {
_spinController = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat();
_spinAnimation = CurvedAnimation(
parent: _spinController!,
curve: Curves.linear,
);
_progressAndSuccessController = widget.controller;
super.initState();
}
@override
void dispose() {
_spinController?.dispose();
_spinController = null;
_progressAndSuccessController = null;
super.dispose();
}
@ -76,16 +67,8 @@ class _RestoringDialogState extends State<SendingTransactionDialog>
Assets.gif.kiss(widget.coin),
),
)
: RotationTransition(
turns: _spinAnimation,
child: SvgPicture.asset(
Assets.svg.arrowRotate,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 24,
height: 24,
),
: ProgressAndSuccess(
controller: _progressAndSuccessController!,
),
],
),
@ -120,19 +103,128 @@ class _RestoringDialogState extends State<SendingTransactionDialog>
)
: StackDialog(
title: "Sending transaction",
icon: RotationTransition(
turns: _spinAnimation,
child: SvgPicture.asset(
Assets.svg.arrowRotate,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 24,
height: 24,
),
icon: ProgressAndSuccess(
controller: _progressAndSuccessController!,
),
),
);
}
}
}
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),
);
}
}

View file

@ -415,6 +415,8 @@ class _ANIMATIONS {
const _ANIMATIONS();
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 {

View file

@ -381,6 +381,8 @@ flutter:
# lottie animations
# basic
- assets/lottie/test2.json
- assets/lottie/icon_send.json
- assets/lottie/loader_and_checkmark.json
# gifs
- assets/gif/