Files
retail/lib/shared/widgets/badge_widget.dart
Phuoc Nguyen b94c158004 runable
2025-10-10 16:38:07 +07:00

221 lines
4.9 KiB
Dart

import 'package:flutter/material.dart';
/// A Material 3 badge widget
class BadgeWidget extends StatelessWidget {
final Widget child;
final String? label;
final int? count;
final Color? backgroundColor;
final Color? textColor;
final Alignment alignment;
final bool show;
const BadgeWidget({
super.key,
required this.child,
this.label,
this.count,
this.backgroundColor,
this.textColor,
this.alignment = Alignment.topRight,
this.show = true,
});
@override
Widget build(BuildContext context) {
if (!show) return child;
return Badge(
label: _buildLabel(context),
alignment: alignment,
backgroundColor: backgroundColor,
textColor: textColor,
child: child,
);
}
Widget? _buildLabel(BuildContext context) {
if (count != null) {
return Text(count! > 99 ? '99+' : '$count');
}
if (label != null) {
return Text(label!);
}
return null;
}
}
/// A status badge for products
class StatusBadge extends StatelessWidget {
final String label;
final StatusBadgeType type;
final IconData? icon;
const StatusBadge({
super.key,
required this.label,
required this.type,
this.icon,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
final Color backgroundColor;
final Color textColor;
switch (type) {
case StatusBadgeType.success:
backgroundColor = const Color(0xFF4CAF50);
textColor = Colors.white;
break;
case StatusBadgeType.warning:
backgroundColor = Colors.orange;
textColor = Colors.white;
break;
case StatusBadgeType.error:
backgroundColor = colorScheme.error;
textColor = colorScheme.onError;
break;
case StatusBadgeType.info:
backgroundColor = colorScheme.primaryContainer;
textColor = colorScheme.onPrimaryContainer;
break;
case StatusBadgeType.neutral:
backgroundColor = colorScheme.surfaceContainerHighest;
textColor = colorScheme.onSurface;
break;
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null) ...[
Icon(
icon,
size: 14,
color: textColor,
),
const SizedBox(width: 4),
],
Text(
label,
style: theme.textTheme.labelSmall?.copyWith(
color: textColor,
fontWeight: FontWeight.bold,
),
),
],
),
);
}
}
enum StatusBadgeType {
success,
warning,
error,
info,
neutral,
}
/// A count badge for displaying numbers
class CountBadge extends StatelessWidget {
final int count;
final Color? backgroundColor;
final Color? textColor;
final double size;
const CountBadge({
super.key,
required this.count,
this.backgroundColor,
this.textColor,
this.size = 20,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
return Container(
constraints: BoxConstraints(
minWidth: size,
minHeight: size,
),
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: backgroundColor ?? colorScheme.primary,
shape: BoxShape.circle,
),
child: Center(
child: Text(
count > 99 ? '99+' : '$count',
style: theme.textTheme.labelSmall?.copyWith(
color: textColor ?? colorScheme.onPrimary,
fontWeight: FontWeight.bold,
fontSize: size * 0.4,
),
textAlign: TextAlign.center,
),
),
);
}
}
/// A notification badge (simple dot)
class NotificationBadge extends StatelessWidget {
final Widget child;
final bool show;
final Color? color;
final double size;
const NotificationBadge({
super.key,
required this.child,
this.show = true,
this.color,
this.size = 8,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
if (!show) return child;
return Stack(
clipBehavior: Clip.none,
children: [
child,
Positioned(
right: 0,
top: 0,
child: Container(
width: size,
height: size,
decoration: BoxDecoration(
color: color ?? colorScheme.error,
shape: BoxShape.circle,
border: Border.all(
color: theme.scaffoldBackgroundColor,
width: 1.5,
),
),
),
),
],
);
}
}