frosty/lib/widgets/alert_message.dart
Tommy Chow 96bce87a0e add FrostyColors ThemeExtension, align hardcoded colors with M3 roles
Introduce FrostyColors ThemeExtension with 7 semantic color fields
(highlightedMessage, emoteOnly, followersOnly, slowMode, subOnly,
uniqueMode, overlayOnSurface) and brightness-aware light/dark variants.

Replace hardcoded colors across 15 files:
- Links use colorScheme.primary instead of Colors.blue
- Mentions use colorScheme.error instead of Colors.red
- First-time chatters share highlightedMessage (Twitch purple)
- Chat mode indicators use frostyColors fields
- Overlay text uses frostyColors.overlayOnSurface

Remove Provider<FrostyThemes> pattern from main.dart, channel.dart,
video_overlay.dart, and frosty_photo_view_dialog.dart.

Replace manual onSurface.withValues(alpha: 0.6) with M3's built-in
onSurfaceVariant for secondary text in section headers, chat modes,
alerts, loading indicators, and input hints. Fix double-muted
onSurfaceVariant.withValues(alpha: 0.6) in navigation icons and
notification dismiss button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 19:01:44 -08:00

82 lines
2.3 KiB
Dart

import 'package:flutter/material.dart';
/// A simple widget that displays an alert message in the center.
class AlertMessage extends StatelessWidget {
final String message;
final Color? color;
final bool centered;
final EdgeInsetsGeometry? padding;
final bool vertical;
final IconData? trailingIcon;
final VoidCallback? onTrailingIconPressed;
const AlertMessage({
super.key,
required this.message,
this.centered = true,
this.color,
this.padding,
this.vertical = false,
this.trailingIcon,
this.onTrailingIconPressed,
});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final defaultColor =
vertical ? colorScheme.onSurfaceVariant : colorScheme.onSurface;
final Widget widget;
if (vertical) {
widget = Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
Icon(Icons.info_outline_rounded, color: color ?? defaultColor),
Text(
message,
textAlign: centered ? TextAlign.center : TextAlign.start,
style: TextStyle(color: color ?? defaultColor),
),
],
);
} else {
widget = Row(
mainAxisAlignment: centered
? MainAxisAlignment.center
: MainAxisAlignment.start,
spacing: 8,
children: [
Icon(Icons.info_outline_rounded, color: color ?? defaultColor),
Flexible(
child: Text(
message,
style: TextStyle(color: color ?? defaultColor),
),
),
if (trailingIcon != null) ...[
const SizedBox(width: 8),
IconButton(
icon: Icon(trailingIcon, color: color ?? defaultColor),
onPressed: onTrailingIconPressed,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
iconSize: 20,
),
],
],
);
}
final effectivePadding =
padding ??
(vertical ? const EdgeInsets.symmetric(horizontal: 24) : null);
return effectivePadding != null
? Padding(padding: effectivePadding, child: widget)
: widget;
}
}