mirror of
https://github.com/krille-chan/fluffychat
synced 2024-10-05 13:12:44 +00:00
refactor: new flutter only typing animation
This commit is contained in:
parent
4fca106a51
commit
a8606f18b6
3 changed files with 67 additions and 88 deletions
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
|
@ -1,80 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64"
|
||||
height="30"
|
||||
viewBox="0 0 64 30"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="typing.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
id="namedview10"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="9.9296875"
|
||||
inkscape:cx="24.018883"
|
||||
inkscape:cy="15.307632"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1012"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg8" />
|
||||
<circle
|
||||
style="fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:normal"
|
||||
cx="10"
|
||||
cy="15"
|
||||
r="9"
|
||||
id="circle2">
|
||||
<animate
|
||||
attributeName="fill"
|
||||
dur="2s"
|
||||
values="#000000; #efefef; #000000"
|
||||
calcMode="spline"
|
||||
keyTimes="0; 0.5; 1"
|
||||
keySplines="0 .75 .25 1; .5 0 .5 1"
|
||||
begin="0s" />
|
||||
</circle>
|
||||
<circle
|
||||
style="fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:normal"
|
||||
cx="32"
|
||||
cy="15"
|
||||
r="9"
|
||||
id="circle4">
|
||||
<animate
|
||||
attributeName="fill"
|
||||
dur="2s"
|
||||
values="#000000; #efefef; #000000"
|
||||
calcMode="spline"
|
||||
keyTimes="0; 0.5; 1"
|
||||
keySplines="0 .75 .25 1; .5 0 .5 1"
|
||||
begin="0.25s" />
|
||||
</circle>
|
||||
<circle
|
||||
style="fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:normal"
|
||||
cx="54"
|
||||
cy="15"
|
||||
r="9"
|
||||
id="circle6">
|
||||
<animate
|
||||
attributeName="fill"
|
||||
dur="2s"
|
||||
values="#000000; #efefef; #000000"
|
||||
calcMode="spline"
|
||||
keyTimes="0; 0.5; 1"
|
||||
keySplines="0 .75 .25 1; .5 0 .5 1"
|
||||
begin="0.5s" />
|
||||
</circle>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.3 KiB |
|
@ -1,3 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
|
@ -78,14 +80,8 @@ class TypingIndicators extends StatelessWidget {
|
|||
bottomRight: Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: typingUsers.isEmpty
|
||||
? null
|
||||
: Image.asset(
|
||||
'assets/typing.gif',
|
||||
height: 30,
|
||||
filterQuality: FilterQuality.high,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: typingUsers.isEmpty ? null : const _TypingDots(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -95,3 +91,66 @@ class TypingIndicators extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TypingDots extends StatefulWidget {
|
||||
const _TypingDots();
|
||||
|
||||
@override
|
||||
State<_TypingDots> createState() => __TypingDotsState();
|
||||
}
|
||||
|
||||
class __TypingDotsState extends State<_TypingDots> {
|
||||
int _tick = 0;
|
||||
|
||||
late final Timer _timer;
|
||||
|
||||
static const Duration animationDuration = Duration(milliseconds: 300);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_timer = Timer.periodic(
|
||||
animationDuration,
|
||||
(_) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_tick = (_tick + 1) % 4;
|
||||
});
|
||||
},
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const size = 8.0;
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (var i = 1; i <= 3; i++)
|
||||
AnimatedContainer(
|
||||
duration: animationDuration * 1.5,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
width: size,
|
||||
height: _tick == i ? size * 2 : size,
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 2,
|
||||
vertical: _tick == i ? 4 : 8,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(size * 2),
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue