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:
@@ -29,6 +29,7 @@ import '../../widgets/gemini_animated_text_field.dart';
|
||||
import '../../widgets/m3_card.dart';
|
||||
import '../../widgets/mono_text.dart';
|
||||
import '../../widgets/responsive_body.dart';
|
||||
import '../../theme/app_status_colors.dart';
|
||||
import '../../widgets/status_pill.dart';
|
||||
import 'it_service_request_pdf.dart';
|
||||
|
||||
@@ -411,13 +412,13 @@ class _ItServiceRequestDetailScreenState
|
||||
),
|
||||
)
|
||||
: _hasRecentSave
|
||||
? const Padding(
|
||||
key: ValueKey('isr_saved'),
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
? Padding(
|
||||
key: const ValueKey('isr_saved'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Icon(
|
||||
Icons.check_circle,
|
||||
size: 18,
|
||||
color: Colors.green,
|
||||
color: AppStatusColors.of(context).success.color,
|
||||
),
|
||||
)
|
||||
: const SizedBox(key: ValueKey('isr_idle')),
|
||||
@@ -555,7 +556,10 @@ class _ItServiceRequestDetailScreenState
|
||||
if (request.requestNumber != null)
|
||||
MonoText(request.requestNumber!),
|
||||
const SizedBox(width: 12),
|
||||
StatusPill(label: ItServiceRequestStatus.label(request.status)),
|
||||
StatusPill.kind(
|
||||
_isrStatusKind(request.status),
|
||||
label: ItServiceRequestStatus.label(request.status),
|
||||
),
|
||||
const Spacer(),
|
||||
Text(
|
||||
'Created ${AppTime.formatDate(request.createdAt)}',
|
||||
@@ -1231,10 +1235,10 @@ class _ItServiceRequestDetailScreenState
|
||||
child: const Icon(Icons.save, size: 14),
|
||||
)
|
||||
: isSaved
|
||||
? const Icon(
|
||||
? Icon(
|
||||
Icons.check_circle,
|
||||
key: ValueKey('label_saved'),
|
||||
color: Colors.green,
|
||||
key: const ValueKey('label_saved'),
|
||||
color: AppStatusColors.of(context).success.color,
|
||||
size: 14,
|
||||
)
|
||||
: const SizedBox(key: ValueKey('label_idle')),
|
||||
@@ -1584,9 +1588,6 @@ class _ItServiceRequestDetailScreenState
|
||||
final controller = TextEditingController();
|
||||
return AlertDialog(
|
||||
title: const Text('Cancellation Reason'),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
),
|
||||
content: TextField(
|
||||
controller: controller,
|
||||
decoration: const InputDecoration(
|
||||
@@ -1836,7 +1837,6 @@ class _StaffPickerDialogState extends State<_StaffPickerDialog> {
|
||||
.toList();
|
||||
return AlertDialog(
|
||||
title: const Text('Select IT Staff'),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(28)),
|
||||
content: SizedBox(
|
||||
width: 350,
|
||||
height: 400,
|
||||
@@ -2245,3 +2245,16 @@ class _EvidenceSectionState extends ConsumerState<_EvidenceSection> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps an IT service request status to a semantic [StatusKind]
|
||||
/// (amber=pending approval, blue=scheduled/in-progress, green=completed,
|
||||
/// grey=cancelled).
|
||||
StatusKind _isrStatusKind(String status) => switch (status) {
|
||||
ItServiceRequestStatus.pendingApproval => StatusKind.warning,
|
||||
ItServiceRequestStatus.scheduled => StatusKind.info,
|
||||
ItServiceRequestStatus.inProgress => StatusKind.info,
|
||||
ItServiceRequestStatus.inProgressDryRun => StatusKind.info,
|
||||
ItServiceRequestStatus.completed => StatusKind.success,
|
||||
ItServiceRequestStatus.cancelled => StatusKind.neutral,
|
||||
_ => StatusKind.neutral,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ import '../../providers/tickets_provider.dart';
|
||||
import '../../theme/m3_motion.dart';
|
||||
import '../../utils/app_time.dart';
|
||||
import '../../utils/snackbar.dart';
|
||||
import '../../theme/app_status_colors.dart';
|
||||
import '../../widgets/m3_card.dart';
|
||||
import '../../widgets/mono_text.dart';
|
||||
import '../../widgets/reconnect_overlay.dart';
|
||||
@@ -381,9 +382,6 @@ class _ItServiceRequestsListScreenState
|
||||
builder: (ctx, setDialogState) {
|
||||
return AlertDialog(
|
||||
title: const Text('New IT Service Request'),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
),
|
||||
content: SizedBox(
|
||||
width: 400,
|
||||
child: SingleChildScrollView(
|
||||
@@ -538,6 +536,7 @@ class _StatusSummaryRow extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
final status = AppStatusColors.of(context);
|
||||
final pending = requests
|
||||
.where((r) => r.status == ItServiceRequestStatus.pendingApproval)
|
||||
.length;
|
||||
@@ -563,7 +562,7 @@ class _StatusSummaryRow extends StatelessWidget {
|
||||
_SummaryChip(
|
||||
label: 'Pending',
|
||||
count: pending,
|
||||
color: cs.tertiary,
|
||||
color: status.warning.color,
|
||||
selected: selectedStatus == ItServiceRequestStatus.pendingApproval,
|
||||
onTap: () => onStatusTap(ItServiceRequestStatus.pendingApproval),
|
||||
),
|
||||
@@ -571,7 +570,7 @@ class _StatusSummaryRow extends StatelessWidget {
|
||||
_SummaryChip(
|
||||
label: 'Scheduled',
|
||||
count: scheduled,
|
||||
color: cs.primary,
|
||||
color: status.info.color,
|
||||
selected: selectedStatus == ItServiceRequestStatus.scheduled,
|
||||
onTap: () => onStatusTap(ItServiceRequestStatus.scheduled),
|
||||
),
|
||||
@@ -587,7 +586,7 @@ class _StatusSummaryRow extends StatelessWidget {
|
||||
_SummaryChip(
|
||||
label: 'Completed',
|
||||
count: completed,
|
||||
color: Colors.green,
|
||||
color: status.success.color,
|
||||
selected: selectedStatus == ItServiceRequestStatus.completed,
|
||||
onTap: () => onStatusTap(ItServiceRequestStatus.completed),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user