M3 Overhaul

This commit is contained in:
2026-03-06 20:03:32 +08:00
parent 82fe619f22
commit 73dc735cce
32 changed files with 1940 additions and 682 deletions
+31 -20
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../theme/m3_motion.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:permission_handler/permission_handler.dart';
@@ -319,7 +320,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
final seen = prefs.getBool('has_seen_notif_showcase') ?? false;
if (!seen) {
if (!mounted) return;
await showDialog<void>(
await m3ShowDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Never miss an update'),
@@ -469,9 +470,10 @@ class _DashboardScreenState extends State<DashboardScreen> {
padding: const EdgeInsets.only(bottom: 12),
child: Text(
title,
style: Theme.of(
context,
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700),
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w700,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
);
}
@@ -571,6 +573,7 @@ class _MetricCard extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final cs = Theme.of(context).colorScheme;
// Only watch the single string value for this card so unrelated metric
// updates don't rebuild the whole card. This makes updates feel much
// smoother and avoids full-page refreshes.
@@ -584,37 +587,42 @@ class _MetricCard extends ConsumerWidget {
),
);
// M3 Expressive: tonal surface container with 16 dp radius, no hard border.
return AnimatedContainer(
duration: const Duration(milliseconds: 220),
padding: const EdgeInsets.all(16),
duration: const Duration(milliseconds: 400),
curve: Curves.easeOutCubic,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Theme.of(context).colorScheme.outlineVariant),
color: cs.surfaceContainerLow,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: Theme.of(
context,
).textTheme.labelLarge?.copyWith(fontWeight: FontWeight.w600),
style: Theme.of(context).textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w600,
color: cs.onSurfaceVariant,
),
),
const SizedBox(height: 10),
const SizedBox(height: 12),
// Animate only the metric text (not the whole card) for a
// subtle, smooth update.
AnimatedSwitcher(
duration: const Duration(milliseconds: 220),
duration: const Duration(milliseconds: 400),
switchInCurve: Curves.easeOutCubic,
switchOutCurve: Curves.easeInCubic,
transitionBuilder: (child, anim) =>
FadeTransition(opacity: anim, child: child),
child: MonoText(
value,
key: ValueKey(value),
style: Theme.of(
context,
).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w700),
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w700,
color: cs.onSurface,
),
),
),
],
@@ -628,12 +636,15 @@ class _StaffTable extends StatelessWidget {
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
// M3 Expressive: tonal surface container, 28 dp radius for large containers.
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(AppSurfaces.of(context).cardRadius),
border: Border.all(color: Theme.of(context).colorScheme.outlineVariant),
color: cs.surfaceContainerLow,
borderRadius: BorderRadius.circular(
AppSurfaces.of(context).containerRadius,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,