tasq/lib/screens/update_check_screen.dart

128 lines
3.2 KiB
Dart

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
/// Simple binary rain animation with a label for the update check splash.
class UpdateCheckingScreen extends StatefulWidget {
const UpdateCheckingScreen({super.key});
@override
State<UpdateCheckingScreen> createState() => _UpdateCheckingScreenState();
}
class _UpdateCheckingScreenState extends State<UpdateCheckingScreen> {
static const int cols = 20;
final List<_Drop> _drops = [];
Timer? _timer;
final Random _rng = Random();
@override
void initState() {
super.initState();
_timer = Timer.periodic(const Duration(milliseconds: 50), (_) {
_tick();
});
}
void _tick() {
setState(() {
if (_rng.nextDouble() < 0.3 || _drops.isEmpty) {
_drops.add(
_Drop(
col: _rng.nextInt(cols),
y: 0.0,
speed: _rng.nextDouble() * 4 + 2,
),
);
}
_drops.removeWhere((d) => d.y > MediaQuery.of(context).size.height);
for (final d in _drops) {
d.y += d.speed;
}
});
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: cs.surface,
body: SafeArea(
child: Column(
children: [
const SizedBox(height: 40),
Hero(
tag: 'tasq-logo',
child: Image.asset('assets/tasq_ico.png', height: 80, width: 80),
),
const SizedBox(height: 24),
Expanded(
child: CustomPaint(
size: Size.infinite,
painter: _BinaryRainPainter(_drops, cols, cs.primary),
),
),
const SizedBox(height: 24),
Text(
'Checking for updates...',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: cs.onSurface.withAlpha((0.75 * 255).round()),
),
),
const SizedBox(height: 40),
],
),
),
);
}
}
class _Drop {
int col;
double y;
double speed;
_Drop({required this.col, required this.y, required this.speed});
}
class _BinaryRainPainter extends CustomPainter {
static const double fontSize = 16;
final List<_Drop> drops;
final int cols;
final Color textColor;
_BinaryRainPainter(this.drops, this.cols, this.textColor);
@override
void paint(Canvas canvas, Size size) {
// paint variable not needed when drawing text
final textStyle = TextStyle(
color: textColor,
fontSize: fontSize,
fontFeatures: const [FontFeature.tabularFigures()],
);
final cellW = size.width / cols;
for (final d in drops) {
final text = (Random().nextBool() ? '1' : '0');
final tp = TextPainter(
text: TextSpan(text: text, style: textStyle),
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
)..layout();
final x = d.col * cellW + (cellW - tp.width) / 2;
final y = d.y;
tp.paint(canvas, Offset(x, y));
}
}
@override
bool shouldRepaint(covariant _BinaryRainPainter old) => true;
}