mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 23:57:54 +00:00
218 lines
7.3 KiB
Dart
218 lines
7.3 KiB
Dart
import 'package:flutter/widgets.dart';
|
|
|
|
import '../theme/app_palette.dart';
|
|
|
|
enum AppEmptyIllustrationType { inbox, puzzle, search, connectionError, documentError }
|
|
|
|
/// Context-specific drawings share the same muted colors and rounded strokes.
|
|
class AppEmptyIllustration extends StatelessWidget {
|
|
const AppEmptyIllustration({super.key, required this.type});
|
|
|
|
final AppEmptyIllustrationType type;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final palette = AppPalette.of(context);
|
|
return CustomPaint(
|
|
size: const Size(148, 108),
|
|
painter: type == AppEmptyIllustrationType.inbox
|
|
? _InboxIllustrationPainter(palette: palette)
|
|
: _ContextIllustrationPainter(palette: palette, type: type),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _ContextIllustrationPainter extends CustomPainter {
|
|
const _ContextIllustrationPainter({required this.palette, required this.type});
|
|
|
|
final AppPalette palette;
|
|
final AppEmptyIllustrationType type;
|
|
|
|
Paint get _outline => Paint()
|
|
..color = palette.textSecondary.withValues(alpha: 0.72)
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 1.8
|
|
..strokeCap = StrokeCap.round
|
|
..strokeJoin = StrokeJoin.round;
|
|
|
|
Paint get _detail => Paint()
|
|
..color = palette.textMuted.withValues(alpha: 0.34)
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 2
|
|
..strokeCap = StrokeCap.round;
|
|
|
|
Paint get _fill => Paint()..color = palette.surfaceSoft;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
canvas.save();
|
|
canvas.scale(size.width / 148, size.height / 108);
|
|
switch (type) {
|
|
case AppEmptyIllustrationType.puzzle:
|
|
_paintPuzzle(canvas);
|
|
case AppEmptyIllustrationType.search:
|
|
_paintSearch(canvas);
|
|
case AppEmptyIllustrationType.connectionError:
|
|
_paintConnectionError(canvas);
|
|
case AppEmptyIllustrationType.documentError:
|
|
_paintDocumentError(canvas);
|
|
case AppEmptyIllustrationType.inbox:
|
|
break;
|
|
}
|
|
canvas.restore();
|
|
}
|
|
|
|
void _paintPuzzle(Canvas canvas) {
|
|
canvas.translate(9, 0);
|
|
final piece = Path()
|
|
..moveTo(42, 29)
|
|
..lineTo(62, 29)
|
|
..cubicTo(55, 10, 86, 10, 79, 29)
|
|
..lineTo(98, 29)
|
|
..quadraticBezierTo(104, 29, 104, 35)
|
|
..lineTo(104, 49)
|
|
..cubicTo(84, 42, 84, 73, 104, 66)
|
|
..lineTo(104, 86)
|
|
..quadraticBezierTo(104, 92, 98, 92)
|
|
..lineTo(79, 92)
|
|
..cubicTo(86, 73, 55, 73, 62, 92)
|
|
..lineTo(42, 92)
|
|
..quadraticBezierTo(36, 92, 36, 86)
|
|
..lineTo(36, 66)
|
|
..cubicTo(17, 73, 17, 42, 36, 49)
|
|
..lineTo(36, 35)
|
|
..quadraticBezierTo(36, 29, 42, 29)
|
|
..close();
|
|
canvas.drawPath(piece, _fill);
|
|
canvas.drawPath(piece, _outline);
|
|
}
|
|
|
|
void _paintSearch(Canvas canvas) {
|
|
final lens = const Offset(64, 45);
|
|
canvas.drawCircle(lens, 29, _fill);
|
|
canvas.drawCircle(lens, 29, _outline);
|
|
canvas.drawLine(const Offset(85, 67), const Offset(115, 96), _outline..strokeWidth = 4);
|
|
canvas.drawLine(const Offset(53, 45), const Offset(75, 45), _detail);
|
|
canvas.drawLine(const Offset(27, 85), const Offset(41, 85), _detail);
|
|
canvas.drawCircle(const Offset(112, 23), 3, Paint()..color = palette.border);
|
|
}
|
|
|
|
void _paintConnectionError(Canvas canvas) {
|
|
final cloud = Path()
|
|
..moveTo(40, 70)
|
|
..cubicTo(21, 70, 19, 43, 39, 41)
|
|
..cubicTo(40, 14, 77, 8, 91, 32)
|
|
..cubicTo(111, 23, 129, 40, 121, 56)
|
|
..cubicTo(133, 66, 119, 79, 108, 74)
|
|
..lineTo(40, 74)
|
|
..close();
|
|
canvas.drawPath(cloud, _fill);
|
|
canvas.drawPath(cloud, _outline);
|
|
canvas.drawLine(const Offset(74, 74), const Offset(74, 82), _detail);
|
|
canvas.drawLine(const Offset(48, 96), const Offset(63, 96), _outline);
|
|
canvas.drawLine(const Offset(86, 96), const Offset(101, 96), _outline);
|
|
canvas.drawLine(const Offset(71, 91), const Offset(77, 101), _detail);
|
|
canvas.drawCircle(const Offset(45, 96), 2, _fill);
|
|
canvas.drawCircle(const Offset(104, 96), 2, _fill);
|
|
}
|
|
|
|
void _paintDocumentError(Canvas canvas) {
|
|
final document = Path()
|
|
..moveTo(47, 12)
|
|
..lineTo(89, 12)
|
|
..lineTo(107, 30)
|
|
..lineTo(107, 89)
|
|
..quadraticBezierTo(107, 96, 100, 96)
|
|
..lineTo(47, 96)
|
|
..quadraticBezierTo(40, 96, 40, 89)
|
|
..lineTo(40, 19)
|
|
..quadraticBezierTo(40, 12, 47, 12)
|
|
..close();
|
|
canvas.drawPath(document, _fill);
|
|
canvas.drawPath(document, _outline);
|
|
canvas.drawPath(
|
|
Path()
|
|
..moveTo(89, 12)
|
|
..lineTo(89, 30)
|
|
..lineTo(107, 30),
|
|
_detail,
|
|
);
|
|
for (final y in [43.0, 56.0, 69.0]) {
|
|
canvas.drawLine(Offset(53, y), Offset(y == 69 ? 74 : 91, y), _detail);
|
|
}
|
|
canvas.drawCircle(const Offset(107, 85), 16, Paint()..color = palette.cardBg);
|
|
canvas.drawCircle(const Offset(107, 85), 16, _outline);
|
|
canvas.drawLine(const Offset(107, 77), const Offset(107, 86), _outline);
|
|
canvas.drawCircle(const Offset(107, 92), 1.2, Paint()..color = palette.textSecondary.withValues(alpha: 0.72));
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(_ContextIllustrationPainter oldDelegate) =>
|
|
oldDelegate.palette != palette || oldDelegate.type != type;
|
|
}
|
|
|
|
class _InboxIllustrationPainter extends CustomPainter {
|
|
const _InboxIllustrationPainter({required this.palette});
|
|
|
|
final AppPalette palette;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final borderPaint = Paint()
|
|
..color = palette.border
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 1.4;
|
|
final sheetRect = RRect.fromRectAndRadius(Rect.fromLTWH(size.width / 2 - 34, 6, 68, 72), const Radius.circular(7));
|
|
|
|
canvas.drawRRect(sheetRect.shift(const Offset(0, 3)), Paint()..color = palette.textMuted.withValues(alpha: 0.06));
|
|
canvas.drawRRect(sheetRect, Paint()..color = palette.cardBg);
|
|
canvas.drawRRect(sheetRect, borderPaint);
|
|
|
|
final rowPaint = Paint()
|
|
..color = palette.textMuted.withValues(alpha: 0.34)
|
|
..strokeWidth = 2
|
|
..strokeCap = StrokeCap.round;
|
|
final centerX = size.width / 2;
|
|
for (var row = 0; row < 2; row++) {
|
|
final y = 20.0 + row * 14;
|
|
canvas.drawCircle(Offset(centerX - 22, y), 2.5, Paint()..color = palette.surfaceSoft);
|
|
canvas.drawLine(Offset(centerX - 14, y), Offset(centerX + 21, y), rowPaint);
|
|
}
|
|
|
|
final emptyBadgePaint = Paint()
|
|
..color = palette.surfaceSoft
|
|
..style = PaintingStyle.fill;
|
|
canvas.drawCircle(Offset(centerX, 56), 11, emptyBadgePaint);
|
|
canvas.drawCircle(Offset(centerX, 56), 11, borderPaint);
|
|
canvas.drawLine(Offset(centerX - 4, 56), Offset(centerX + 4, 56), rowPaint);
|
|
|
|
final trayPath = Path()
|
|
..moveTo(26, 63)
|
|
..lineTo(49, 63)
|
|
..lineTo(57, 75)
|
|
..quadraticBezierTo(59, 78, 63, 78)
|
|
..lineTo(85, 78)
|
|
..quadraticBezierTo(89, 78, 91, 75)
|
|
..lineTo(99, 63)
|
|
..lineTo(122, 63)
|
|
..lineTo(115, 96)
|
|
..quadraticBezierTo(114, 101, 108, 101)
|
|
..lineTo(40, 101)
|
|
..quadraticBezierTo(34, 101, 33, 96)
|
|
..close();
|
|
canvas.drawPath(trayPath, Paint()..color = palette.surfaceSoft);
|
|
final trayPaint = Paint()
|
|
..color = palette.textSecondary.withValues(alpha: 0.72)
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 1.8
|
|
..strokeCap = StrokeCap.round
|
|
..strokeJoin = StrokeJoin.round;
|
|
canvas.drawPath(trayPath, trayPaint);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(_InboxIllustrationPainter oldDelegate) {
|
|
return oldDelegate.palette != palette;
|
|
}
|
|
}
|