* Task/Ticket desktop dialogs — widened from 520 → 600dp, and tasks now uses SizedBox(width: 600) instead of ConstrainedBox(maxWidth:) which was the root cause of the "still small" issue (max-only never forced expansion)
* Pass Slip + Leave — both dialogs gained an isSheet flag; callers now branch on AppBreakpoints.tablet: bottom sheet on mobile, dialog on desktop
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/m3_motion.dart';
|
||||
import 'app_breakpoints.dart';
|
||||
|
||||
/// Standardized M3 Expressive page header with animated entrance.
|
||||
///
|
||||
@@ -18,7 +19,7 @@ class AppPageHeader extends StatelessWidget {
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.actions,
|
||||
this.padding = const EdgeInsets.only(top: 20, bottom: 12),
|
||||
this.padding,
|
||||
});
|
||||
|
||||
final String title;
|
||||
@@ -29,16 +30,18 @@ class AppPageHeader extends StatelessWidget {
|
||||
|
||||
/// Vertical padding around the header. Horizontal padding is handled by
|
||||
/// the parent [ResponsiveBody] so only top/bottom should be set here.
|
||||
final EdgeInsetsGeometry padding;
|
||||
/// When null, defaults to responsive bottom padding (24dp desktop / 12dp mobile).
|
||||
final EdgeInsetsGeometry? padding;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final tt = Theme.of(context).textTheme;
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
final isMobile = AppBreakpoints.isMobile(context);
|
||||
|
||||
final titleWidget = Text(
|
||||
title,
|
||||
style: tt.headlineSmall?.copyWith(
|
||||
style: (isMobile ? tt.titleLarge : tt.headlineSmall)?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.3,
|
||||
color: cs.onSurface,
|
||||
@@ -46,7 +49,7 @@ class AppPageHeader extends StatelessWidget {
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
|
||||
final subtitleWidget = subtitle == null
|
||||
final subtitleWidget = (subtitle == null || isMobile)
|
||||
? null
|
||||
: Text(
|
||||
subtitle!,
|
||||
@@ -93,9 +96,15 @@ class AppPageHeader extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
final effectivePadding = padding ??
|
||||
EdgeInsets.only(
|
||||
top: isMobile ? 12 : 20,
|
||||
bottom: AppBreakpoints.isDesktop(context) ? 24 : 12,
|
||||
);
|
||||
|
||||
return M3FadeSlideIn(
|
||||
duration: M3Motion.standard,
|
||||
child: Padding(padding: padding, child: content),
|
||||
child: Padding(padding: effectivePadding, child: content),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
@@ -27,7 +28,7 @@ class OfflineBanner extends ConsumerWidget {
|
||||
if (!isOnline) {
|
||||
final label = pendingCount > 0
|
||||
? 'Offline — $pendingCount item${pendingCount == 1 ? '' : 's'} queued'
|
||||
: 'No internet — changes saved locally';
|
||||
: kIsWeb ? 'No internet connection' : 'No internet — changes saved locally';
|
||||
banner = _BannerStrip(
|
||||
key: const ValueKey('offline'),
|
||||
backgroundColor: scheme.errorContainer,
|
||||
|
||||
Reference in New Issue
Block a user