refactor: add shared StoplightColors for consistent status colors

- Add StoplightColors class with green/orange/red pastel colors
- Update dashboard gauges to use StoplightColors.forPercent()
- Update air quality levels to use shared stoplight colors
- Provides consistent color scheme for all threshold-based indicators

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeroen Schweitzer
2026-01-03 18:33:42 +01:00
co-authored by Claude Opus 4.5
parent 67fed18cb0
commit 6c271489a9
3 changed files with 47 additions and 20 deletions
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:tatlock_ui/features/front_hall/data/models/system_stats_model.dart';
import 'package:tatlock_ui/features/front_hall/presentation/providers/system_stats_provider.dart';
import 'package:tatlock_ui/shared/theme/stoplight_colors.dart';
import 'package:tatlock_ui/shared/widgets/widgets.dart';
import 'package:tatlock_ui/version.g.dart';
@@ -197,18 +198,6 @@ class _SystemStatsCard extends StatelessWidget {
final SystemStats stats;
/// Pastel colors based on usage percentage.
static const _pastelGreen = Color(0xFF81C784);
static const _pastelOrange = Color(0xFFFFB74D);
static const _pastelRed = Color(0xFFE57373);
/// Returns color based on usage: green ≤50%, orange 51-75%, red >75%.
Color _colorForUsage(double percent) {
if (percent <= 50) return _pastelGreen;
if (percent <= 75) return _pastelOrange;
return _pastelRed;
}
@override
Widget build(BuildContext context) {
// Build gauges list: CPU, Memory, GPU (if available), then all disks
@@ -217,20 +206,20 @@ class _SystemStatsCard extends StatelessWidget {
value: stats.cpu.usagePercent / 100,
label: 'CPU',
icon: Icons.memory,
color: _colorForUsage(stats.cpu.usagePercent),
color: StoplightColors.forPercent(stats.cpu.usagePercent),
),
GaugeData(
value: stats.memory.usagePercent / 100,
label: 'RAM',
icon: Icons.storage,
color: _colorForUsage(stats.memory.usagePercent),
color: StoplightColors.forPercent(stats.memory.usagePercent),
),
if (stats.gpu.available && stats.gpu.usagePercent != null)
GaugeData(
value: stats.gpu.usagePercent! / 100,
label: 'VRAM',
icon: Icons.videocam,
color: _colorForUsage(stats.gpu.usagePercent!),
color: StoplightColors.forPercent(stats.gpu.usagePercent!),
),
// Add a gauge for each disk
...stats.disks.map(
@@ -238,7 +227,7 @@ class _SystemStatsCard extends StatelessWidget {
value: disk.usagePercent / 100,
label: _formatDiskLabel(disk),
icon: Icons.disc_full,
color: _colorForUsage(disk.usagePercent),
color: StoplightColors.forPercent(disk.usagePercent),
),
),
];
+37
View File
@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
/// Pastel stoplight colors for consistent status indication across the app.
///
/// Use these colors for any green/yellow/red status flows:
/// - System stats (CPU, RAM, disk usage)
/// - Air quality levels
/// - Container health status
/// - Any other threshold-based indicators
abstract final class StoplightColors {
/// Good/healthy/low usage (0-50%)
static const green = Color(0xFF81C784);
/// Warning/moderate/medium usage (51-75%)
static const orange = Color(0xFFFFB74D);
/// Critical/unhealthy/high usage (76-100%)
static const red = Color(0xFFE57373);
/// Returns appropriate color based on percentage (0-100).
///
/// - ≤50%: green
/// - 51-75%: orange
/// - >75%: red
static Color forPercent(double percent) {
if (percent <= 50) return green;
if (percent <= 75) return orange;
return red;
}
/// Returns appropriate color based on value (0.0-1.0).
///
/// - ≤0.5: green
/// - 0.51-0.75: orange
/// - >0.75: red
static Color forValue(double value) => forPercent(value * 100);
}
+5 -4
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:tatlock_ui/shared/theme/stoplight_colors.dart';
/// Air Quality Index widget displaying current AQI.
///
@@ -203,28 +204,28 @@ enum AqiLevel {
good(
label: 'Good',
description: 'Air quality is satisfactory',
color: Colors.green,
color: StoplightColors.green,
minIndex: 0,
maxIndex: 50,
),
moderate(
label: 'Moderate',
description: 'Acceptable for most people',
color: Colors.amber,
color: StoplightColors.orange,
minIndex: 51,
maxIndex: 100,
),
unhealthySensitive(
label: 'Unhealthy for Sensitive',
description: 'May affect sensitive groups',
color: Colors.orange,
color: StoplightColors.orange,
minIndex: 101,
maxIndex: 150,
),
unhealthy(
label: 'Unhealthy',
description: 'Health effects for everyone',
color: Colors.red,
color: StoplightColors.red,
minIndex: 151,
maxIndex: 200,
),