190 lines
5.1 KiB
Dart
190 lines
5.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:mobile_monitoring/core/constants/colors.dart';
|
|
import 'package:mobile_monitoring/core/constants/app_settings.dart';
|
|
|
|
/// Custom Button - Berbagai jenis button yang reusable
|
|
class CustomButton extends StatelessWidget {
|
|
final String text;
|
|
final VoidCallback? onPressed;
|
|
final bool isLoading;
|
|
final ButtonType type;
|
|
final ButtonSize size;
|
|
final IconData? icon;
|
|
final Color? backgroundColor;
|
|
final Color? textColor;
|
|
final double? width;
|
|
final double? height;
|
|
|
|
const CustomButton({
|
|
super.key,
|
|
required this.text,
|
|
this.onPressed,
|
|
this.isLoading = false,
|
|
this.type = ButtonType.primary,
|
|
this.size = ButtonSize.medium,
|
|
this.icon,
|
|
this.backgroundColor,
|
|
this.textColor,
|
|
this.width,
|
|
this.height,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final isDisabled = onPressed == null || isLoading;
|
|
|
|
return SizedBox(
|
|
width: width,
|
|
height: height ?? _getHeight(),
|
|
child: _buildButton(context, isDisabled),
|
|
);
|
|
}
|
|
|
|
Widget _buildButton(BuildContext context, bool isDisabled) {
|
|
switch (type) {
|
|
case ButtonType.primary:
|
|
return ElevatedButton(
|
|
onPressed: isDisabled ? null : onPressed,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: backgroundColor ?? AppColors.primary,
|
|
foregroundColor: textColor ?? AppColors.white,
|
|
padding: _getPadding(),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(AppSettings.defaultBorderRadius),
|
|
),
|
|
elevation: 2,
|
|
),
|
|
child: _buildContent(),
|
|
);
|
|
case ButtonType.secondary:
|
|
return OutlinedButton(
|
|
onPressed: isDisabled ? null : onPressed,
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: backgroundColor ?? AppColors.primary,
|
|
side: BorderSide(
|
|
color: backgroundColor ?? AppColors.primary,
|
|
width: 1.5,
|
|
),
|
|
padding: _getPadding(),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(AppSettings.defaultBorderRadius),
|
|
),
|
|
),
|
|
child: _buildContent(),
|
|
);
|
|
case ButtonType.text:
|
|
return TextButton(
|
|
onPressed: isDisabled ? null : onPressed,
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: backgroundColor ?? AppColors.primary,
|
|
padding: _getPadding(),
|
|
),
|
|
child: _buildContent(),
|
|
);
|
|
case ButtonType.danger:
|
|
return ElevatedButton(
|
|
onPressed: isDisabled ? null : onPressed,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColors.error,
|
|
foregroundColor: AppColors.white,
|
|
padding: _getPadding(),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(AppSettings.defaultBorderRadius),
|
|
),
|
|
elevation: 2,
|
|
),
|
|
child: _buildContent(),
|
|
);
|
|
}
|
|
}
|
|
|
|
Widget _buildContent() {
|
|
if (isLoading) {
|
|
return SizedBox(
|
|
height: _getIndicatorSize(),
|
|
width: _getIndicatorSize(),
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2,
|
|
valueColor: AlwaysStoppedAnimation<Color>(
|
|
type == ButtonType.primary || type == ButtonType.danger
|
|
? AppColors.white
|
|
: AppColors.primary,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
if (icon != null) {
|
|
return Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(icon, size: _getIconSize()),
|
|
const SizedBox(width: 8),
|
|
Text(text, style: TextStyle(fontSize: _getFontSize())),
|
|
],
|
|
);
|
|
}
|
|
|
|
return Text(text, style: TextStyle(fontSize: _getFontSize()));
|
|
}
|
|
|
|
double _getHeight() {
|
|
switch (size) {
|
|
case ButtonSize.small:
|
|
return 36;
|
|
case ButtonSize.medium:
|
|
return 48;
|
|
case ButtonSize.large:
|
|
return 56;
|
|
}
|
|
}
|
|
|
|
EdgeInsets _getPadding() {
|
|
switch (size) {
|
|
case ButtonSize.small:
|
|
return const EdgeInsets.symmetric(horizontal: 16, vertical: 8);
|
|
case ButtonSize.medium:
|
|
return const EdgeInsets.symmetric(horizontal: 24, vertical: 12);
|
|
case ButtonSize.large:
|
|
return const EdgeInsets.symmetric(horizontal: 32, vertical: 16);
|
|
}
|
|
}
|
|
|
|
double _getFontSize() {
|
|
switch (size) {
|
|
case ButtonSize.small:
|
|
return 14;
|
|
case ButtonSize.medium:
|
|
return 16;
|
|
case ButtonSize.large:
|
|
return 18;
|
|
}
|
|
}
|
|
|
|
double _getIconSize() {
|
|
switch (size) {
|
|
case ButtonSize.small:
|
|
return 18;
|
|
case ButtonSize.medium:
|
|
return 20;
|
|
case ButtonSize.large:
|
|
return 24;
|
|
}
|
|
}
|
|
|
|
double _getIndicatorSize() {
|
|
switch (size) {
|
|
case ButtonSize.small:
|
|
return 16;
|
|
case ButtonSize.medium:
|
|
return 20;
|
|
case ButtonSize.large:
|
|
return 24;
|
|
}
|
|
}
|
|
}
|
|
|
|
enum ButtonType { primary, secondary, text, danger }
|
|
|
|
enum ButtonSize { small, medium, large }
|