| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import 'package:flutter/material.dart';
- import '../../../core/theme/app_colors.dart';
- import '../../../core/widgets/app_icon.dart';
- import '../../../core/widgets/pressable.dart';
- import '../../../core/widgets/surface_card.dart';
- import '../../../data/models/system_status.dart';
- /// Quiet battery / Wi-Fi readout. It is information, not a toolbar.
- class StatusCluster extends StatelessWidget {
- const StatusCluster({
- super.key,
- required this.status,
- this.compact = false,
- this.showBattery = true,
- this.onOpenSettings,
- });
- final SystemStatus status;
- final bool compact;
- final bool showBattery;
- final VoidCallback? onOpenSettings;
- @override
- Widget build(BuildContext context) {
- final colors = context.colors;
- final theme = Theme.of(context);
- final batteryColor = status.batteryLevel <= 15 && !status.charging
- ? colors.danger
- : (status.charging ? colors.accent : colors.ink);
- return SurfaceCard(
- padding: EdgeInsets.symmetric(
- horizontal: compact ? 16 : 20,
- vertical: compact ? 10 : 12,
- ),
- radius: 999,
- color: colors.surface.withValues(alpha: 0.82),
- showShadow: false,
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Semantics(
- label: status.wifi ? 'Wi-Fi connected' : 'Wi-Fi disconnected',
- child: AppIcon(
- status.wifi
- ? 'assets/icons/wifi.svg'
- : 'assets/icons/wifi-off.svg',
- size: compact ? 18 : 20,
- color: status.wifi ? colors.ink : colors.inkFaint,
- ),
- ),
- if (onOpenSettings != null) ...[
- SizedBox(width: compact ? 10 : 12),
- Pressable(
- onTap: onOpenSettings!,
- semanticLabel: 'Open settings',
- pressedScale: 0.92,
- child: Container(
- width: compact ? 28 : 30,
- height: compact ? 28 : 30,
- decoration: BoxDecoration(
- color: colors.surfaceStrong,
- shape: BoxShape.circle,
- border: Border.all(color: colors.border),
- ),
- alignment: Alignment.center,
- child: AppIcon(
- 'assets/icons/settings.svg',
- size: compact ? 15 : 17,
- color: colors.inkMuted,
- ),
- ),
- ),
- ],
- if (showBattery) ...[
- SizedBox(width: compact ? 12 : 16),
- _BatteryGlyph(
- level: status.batteryLevel,
- charging: status.charging,
- color: batteryColor,
- ),
- const SizedBox(width: 8),
- Text(
- '${status.batteryLevel}%',
- style: theme.textTheme.labelLarge?.copyWith(
- color: colors.ink,
- fontSize: compact ? 13 : 14,
- ),
- ),
- if (status.charging) ...[
- const SizedBox(width: 6),
- Icon(
- Icons.bolt_rounded,
- size: compact ? 16 : 18,
- color: colors.accent,
- ),
- ],
- ],
- ],
- ),
- );
- }
- }
- class _BatteryGlyph extends StatelessWidget {
- const _BatteryGlyph({
- required this.level,
- required this.charging,
- required this.color,
- });
- final int level;
- final bool charging;
- final Color color;
- @override
- Widget build(BuildContext context) {
- return SizedBox(
- width: 28,
- height: 15,
- child: CustomPaint(
- painter: _BatteryPainter(
- level: level,
- color: color,
- charging: charging,
- ),
- ),
- );
- }
- }
- class _BatteryPainter extends CustomPainter {
- _BatteryPainter({
- required this.level,
- required this.color,
- required this.charging,
- });
- final int level;
- final Color color;
- final bool charging;
- @override
- void paint(Canvas canvas, Size size) {
- final body = Rect.fromLTWH(0, 1, size.width - 4, size.height - 2);
- final radius = Radius.circular(body.height / 2);
- final outline = Paint()
- ..color = color.withValues(alpha: 0.52)
- ..style = PaintingStyle.stroke
- ..strokeWidth = 1.3;
- final cap = Paint()..color = color.withValues(alpha: 0.52);
- canvas.drawRRect(RRect.fromRectAndRadius(body, radius), outline);
- canvas.drawRRect(
- RRect.fromRectAndRadius(
- Rect.fromLTWH(
- size.width - 3.5,
- size.height * 0.34,
- 2.5,
- size.height * 0.32,
- ),
- const Radius.circular(1),
- ),
- cap,
- );
- final inset = body.deflate(2.4);
- final fillWidth = inset.width * (level.clamp(0, 100) / 100);
- if (fillWidth > 0) {
- final fill = Paint()..color = color;
- canvas.drawRRect(
- RRect.fromRectAndRadius(
- Rect.fromLTWH(inset.left, inset.top, fillWidth, inset.height),
- const Radius.circular(2.4),
- ),
- fill,
- );
- }
- }
- @override
- bool shouldRepaint(covariant _BatteryPainter oldDelegate) {
- return oldDelegate.level != level ||
- oldDelegate.color != color ||
- oldDelegate.charging != charging;
- }
- }
|