139 lines
3.6 KiB
Dart
139 lines
3.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'package:worker/core/theme/colors.dart';
|
|
|
|
/// Button variant types for different use cases.
|
|
enum ButtonVariant {
|
|
/// Primary button with filled background color
|
|
primary,
|
|
|
|
/// Secondary button with outlined border
|
|
secondary,
|
|
}
|
|
|
|
/// Custom button widget following the Worker app design system.
|
|
///
|
|
/// Supports primary and secondary variants, loading states, and disabled states.
|
|
///
|
|
/// Example usage:
|
|
/// ```dart
|
|
/// CustomButton(
|
|
/// text: 'Login',
|
|
/// onPressed: () => _handleLogin(),
|
|
/// variant: ButtonVariant.primary,
|
|
/// isLoading: _isLoading,
|
|
/// )
|
|
/// ```
|
|
class CustomButton extends StatelessWidget {
|
|
/// The text to display on the button
|
|
final String text;
|
|
|
|
/// Callback when button is pressed. If null, button is disabled.
|
|
final VoidCallback? onPressed;
|
|
|
|
/// Visual variant of the button (primary or secondary)
|
|
final ButtonVariant variant;
|
|
|
|
/// Whether to show loading indicator instead of text
|
|
final bool isLoading;
|
|
|
|
/// Optional icon to display before the text
|
|
final IconData? icon;
|
|
|
|
/// Custom width for the button. If null, uses parent constraints.
|
|
final double? width;
|
|
|
|
/// Custom height for the button. Defaults to 48.
|
|
final double? height;
|
|
|
|
const CustomButton({
|
|
super.key,
|
|
required this.text,
|
|
required this.onPressed,
|
|
this.variant = ButtonVariant.primary,
|
|
this.isLoading = false,
|
|
this.icon,
|
|
this.width,
|
|
this.height,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final isDisabled = onPressed == null || isLoading;
|
|
|
|
if (variant == ButtonVariant.primary) {
|
|
return SizedBox(
|
|
width: width,
|
|
height: height ?? 48,
|
|
child: ElevatedButton(
|
|
onPressed: isDisabled ? null : onPressed,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColors.primaryBlue,
|
|
foregroundColor: Colors.white,
|
|
disabledBackgroundColor: AppColors.grey500,
|
|
disabledForegroundColor: Colors.white70,
|
|
elevation: 2,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
),
|
|
child: _buildContent(),
|
|
),
|
|
);
|
|
} else {
|
|
return SizedBox(
|
|
width: width,
|
|
height: height ?? 48,
|
|
child: OutlinedButton(
|
|
onPressed: isDisabled ? null : onPressed,
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: AppColors.primaryBlue,
|
|
disabledForegroundColor: AppColors.grey500,
|
|
side: BorderSide(
|
|
color: isDisabled ? AppColors.grey500 : AppColors.primaryBlue,
|
|
width: 1.5,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
),
|
|
child: _buildContent(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Builds the button content (text, icon, or loading indicator)
|
|
Widget _buildContent() {
|
|
if (isLoading) {
|
|
return const SizedBox(
|
|
width: 20,
|
|
height: 20,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2,
|
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
|
),
|
|
);
|
|
}
|
|
|
|
if (icon != null) {
|
|
return Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(icon, size: 20),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
text,
|
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
return Text(
|
|
text,
|
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
|
);
|
|
}
|
|
}
|