button static method
Implementation
static String button() => r'''
import 'package:flutter/material.dart';
import '../styles/design_style_config.dart';
import '../tokens/app_colors.dart';
import '../tokens/app_gradients.dart';
import '../tokens/app_motion.dart';
import '../tokens/app_radius.dart';
import '../tokens/app_shadows.dart';
import '../tokens/app_sizes.dart';
import '../tokens/app_spacing.dart';
import '../tokens/app_typography.dart';
enum AppButtonVariant {
primary,
secondary,
tertiary,
outline,
text,
destructive,
}
class AppButton extends StatelessWidget {
const AppButton({
super.key,
required this.label,
required this.onPressed,
this.variant = AppButtonVariant.primary,
this.loading = false,
this.icon,
this.expanded = false,
});
final String label;
final VoidCallback? onPressed;
final AppButtonVariant variant;
final bool loading;
final IconData? icon;
final bool expanded;
bool get _enabled => onPressed != null && !loading;
@override
Widget build(BuildContext context) {
final child = _content(context);
return Semantics(
button: true,
enabled: _enabled,
label: label,
child: ConstrainedBox(
constraints: const BoxConstraints(
minHeight: AppSizes.minTapTarget,
minWidth: AppSizes.minTapTarget,
),
child: child,
),
);
}
Widget _content(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final bg = _background(isDark);
final fg = _foreground(isDark);
Widget body = Row(
mainAxisSize: expanded ? MainAxisSize.max : MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (loading)
SizedBox(
width: AppSizes.iconSm,
height: AppSizes.iconSm,
child: CircularProgressIndicator(
strokeWidth: 2,
color: fg,
),
)
else if (icon != null) ...<Widget>[
Icon(icon, size: AppSizes.iconSm, color: fg),
const SizedBox(width: AppSpacing.sm),
],
if (!loading)
Flexible(
child: Text(
label,
style: AppTypography.button.copyWith(color: fg),
overflow: TextOverflow.ellipsis,
),
),
],
);
body = Padding(
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
vertical: AppSpacing.sm,
),
child: body,
);
final shape = RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
AppStyleConfig.usesHardOffsetShadow ? AppRadius.none : AppRadius.md,
),
side: variant == AppButtonVariant.outline ||
AppStyleConfig.usesHardOffsetShadow
? BorderSide(
color: variant == AppButtonVariant.destructive
? AppColors.error
: (isDark ? AppColorsDark.outline : AppColors.outline),
width: AppStyleConfig.usesHardOffsetShadow ? 3 : 1.5,
)
: BorderSide.none,
);
return AnimatedOpacity(
duration: AppMotion.fast,
opacity: _enabled ? 1 : 0.5,
child: Material(
color: AppStyleConfig.prefersGradientButtons &&
variant == AppButtonVariant.primary
? Colors.transparent
: bg,
shape: shape,
clipBehavior: Clip.antiAlias,
elevation: 0,
child: InkWell(
onTap: _enabled ? onPressed : null,
customBorder: shape,
child: Ink(
decoration: AppStyleConfig.prefersGradientButtons &&
variant == AppButtonVariant.primary
? BoxDecoration(
gradient: AppGradients.primary,
borderRadius: BorderRadius.circular(AppRadius.md),
boxShadow: AppStyleConfig.usesClayInflation
? AppShadows.clay
: AppStyleConfig.usesNeoShadows
? AppShadows.neoRaised
: null,
)
: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(
AppStyleConfig.usesHardOffsetShadow
? AppRadius.none
: AppRadius.md,
),
boxShadow: _shadows(),
),
child: body,
),
),
),
);
}
List<BoxShadow>? _shadows() {
if (variant == AppButtonVariant.text ||
variant == AppButtonVariant.tertiary) {
return null;
}
if (AppStyleConfig.usesNeoShadows) {
return AppShadows.neoRaised;
}
if (AppStyleConfig.usesHardOffsetShadow) {
return AppShadows.hardOffset;
}
if (AppStyleConfig.usesClayInflation) {
return AppShadows.clay;
}
return AppShadows.low;
}
Color _background(bool isDark) {
switch (variant) {
case AppButtonVariant.primary:
return isDark ? AppColorsDark.primary : AppColors.primary;
case AppButtonVariant.secondary:
return isDark
? AppColorsDark.surfaceVariant
: AppColors.surfaceVariant;
case AppButtonVariant.tertiary:
case AppButtonVariant.text:
case AppButtonVariant.outline:
return Colors.transparent;
case AppButtonVariant.destructive:
return isDark ? AppColorsDark.error : AppColors.error;
}
}
Color _foreground(bool isDark) {
switch (variant) {
case AppButtonVariant.primary:
return isDark ? AppColorsDark.onPrimary : AppColors.onPrimary;
case AppButtonVariant.destructive:
return isDark ? AppColorsDark.onPrimary : AppColors.onPrimary;
case AppButtonVariant.secondary:
case AppButtonVariant.tertiary:
case AppButtonVariant.outline:
case AppButtonVariant.text:
return isDark ? AppColorsDark.textPrimary : AppColors.textPrimary;
}
}
}
''';