UI: Cyber/IT design overhaul with semantic status tokens (Material 3)

Re-theme TasQ with a refined enterprise "Cyber/IT" identity on Material 3.
Functionality is unchanged — only color/shape tokens and a few state widgets.

Foundation:
- Hand-tuned light + dark ColorSchemes (deep-slate surfaces, azure/teal/violet
  accents), tightened 12-16dp shape language, flat hairline-outlined cards.
- New AppStatusColors theme extension (success/warning/danger/info/neutral,
  per-brightness) replacing scattered raw Colors.green/orange/red/grey so status
  color is consistent and legible in dark mode.
- New TechChip mono primitive; StatusPill.kind; M3Card hairline variants;
  tightened AppSurfaces radii.

Per-screen:
- Tokenized status colors + radii across dashboard, tickets, tasks, IT service
  requests, attendance, whereabouts, network map, reports charts, auth, and
  shared/admin screens. Added _ticketStatusKind/_taskStatusKind/_isrStatusKind
  mappers so status carries meaning consistently.
- Fixed white pie-slice borders for dark mode; dropped ad-hoc dialog radius
  overrides in favor of the theme default. Categorical palettes (leave-type
  icons, team color picker, distribution charts) intentionally preserved.

Verified: flutter analyze lib clean; flutter build web green; visual QA in
light and dark (dashboard, tickets, attendance).

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-09-26 15:13:47 +08:00
parent 3cb980b629
commit 57377b1b21
28 changed files with 986 additions and 470 deletions
+30 -19
View File
@@ -1,4 +1,6 @@
import 'package:flutter/material.dart';
import '../../theme/app_status_colors.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:geolocator/geolocator.dart';
import 'package:flutter_map/flutter_map.dart';
@@ -111,8 +113,8 @@ class _GeofenceTestScreenState extends ConsumerState<GeofenceTestScreen> {
.check_circle
: Icons.cancel,
color: inside
? Colors.green
: Colors.red,
? AppStatusColors.of(context).success.color
: AppStatusColors.of(context).danger.color,
),
const SizedBox(
width: 8,
@@ -166,8 +168,8 @@ class _GeofenceTestScreenState extends ConsumerState<GeofenceTestScreen> {
? Icons.check_circle
: Icons.cancel,
color: inside
? Colors.green
: Colors.red,
? AppStatusColors.of(context).success.color
: AppStatusColors.of(context).danger.color,
),
const SizedBox(width: 8),
Text(
@@ -275,10 +277,10 @@ class _GeofenceTestScreenState extends ConsumerState<GeofenceTestScreen> {
width: 40,
height: 40,
// `child` is used by newer flutter_map Marker API.
child: const Icon(
child: Icon(
Icons.person_pin_circle,
size: 36,
color: Colors.blue,
color: Theme.of(context).colorScheme.primary,
),
),
);
@@ -289,10 +291,12 @@ class _GeofenceTestScreenState extends ConsumerState<GeofenceTestScreen> {
polygons: [
Polygon(
points: polygonPoints,
color: Colors.green.withValues(
alpha: 0.15,
),
borderColor: Colors.green,
color: AppStatusColors.of(context)
.success
.color
.withValues(alpha: 0.15),
borderColor:
AppStatusColors.of(context).success.color,
borderStrokeWidth: 2,
),
],
@@ -304,9 +308,10 @@ class _GeofenceTestScreenState extends ConsumerState<GeofenceTestScreen> {
circles: [
CircleMarker(
point: LatLng(cfg!.lat!, cfg.lng!),
color: Colors.green.withValues(
alpha: 0.10,
),
color: AppStatusColors.of(context)
.success
.color
.withValues(alpha: 0.10),
borderStrokeWidth: 2,
useRadiusInMeter: true,
radius: cfg.radiusMeters ?? 100,
@@ -387,11 +392,15 @@ class _GeofenceTestScreenState extends ConsumerState<GeofenceTestScreen> {
width: 12,
height: 12,
decoration: BoxDecoration(
color: Colors.green.withValues(
color: AppStatusColors.of(
context,
).success.color.withValues(
alpha: 0.25,
),
border: Border.all(
color: Colors.green,
color: AppStatusColors.of(
context,
).success.color,
),
),
),
@@ -420,14 +429,16 @@ class _GeofenceTestScreenState extends ConsumerState<GeofenceTestScreen> {
top: 6.0,
),
child: Row(
children: const [
children: [
Icon(
Icons.person_pin_circle,
size: 14,
color: Colors.blue,
color: Theme.of(
context,
).colorScheme.primary,
),
SizedBox(width: 8),
Text('You'),
const SizedBox(width: 8),
const Text('You'),
],
),
),