Copy more common components
This commit is contained in:
parent
33b141916f
commit
537b3d2e4d
526
lib/ui/components/buttons/button_widget.dart
Normal file
526
lib/ui/components/buttons/button_widget.dart
Normal file
|
@ -0,0 +1,526 @@
|
|||
import 'package:ente_auth/models/execution_states.dart';
|
||||
import 'package:ente_auth/models/typedefs.dart';
|
||||
import 'package:ente_auth/theme/colors.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:ente_auth/theme/text_style.dart';
|
||||
import 'package:ente_auth/ui/common/loading_widget.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_result.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_type.dart';
|
||||
import 'package:ente_auth/ui/components/models/custom_button_style.dart';
|
||||
import 'package:ente_auth/utils/debouncer.dart';
|
||||
import "package:ente_auth/utils/dialog_util.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
enum ButtonSize { small, large }
|
||||
|
||||
enum ButtonAction { first, second, third, fourth, cancel, error }
|
||||
|
||||
class ButtonWidget extends StatelessWidget {
|
||||
final IconData? icon;
|
||||
final String? labelText;
|
||||
final ButtonType buttonType;
|
||||
final FutureVoidCallback? onTap;
|
||||
final bool isDisabled;
|
||||
final ButtonSize buttonSize;
|
||||
|
||||
///Setting this flag to true will show a success confirmation as a 'check'
|
||||
///icon once the onTap(). This is expected to be used only if time taken to
|
||||
///execute onTap() takes less than debouce time.
|
||||
final bool shouldShowSuccessConfirmation;
|
||||
|
||||
///Setting this flag to false will restrict the loading and success states of
|
||||
///the button from surfacing on the UI. The ExecutionState of the button will
|
||||
///change irrespective of the value of this flag. Only that it won't be
|
||||
///surfaced on the UI
|
||||
final bool shouldSurfaceExecutionStates;
|
||||
|
||||
/// iconColor should only be specified when we do not want to honor the default
|
||||
/// iconColor based on buttonType. Most of the items, default iconColor is what
|
||||
/// we need unless we want to pop out the icon in a non-primary button type
|
||||
final Color? iconColor;
|
||||
|
||||
///Button action will only work if isInAlert is true
|
||||
final ButtonAction? buttonAction;
|
||||
|
||||
///setting this flag to true will make the button appear like how it would
|
||||
///on dark theme irrespective of the app's theme.
|
||||
final bool shouldStickToDarkTheme;
|
||||
|
||||
///isInAlert is to dismiss the alert if the action on the button is completed.
|
||||
///This should be set to true if the alert which uses this button needs to
|
||||
///return the Button's action.
|
||||
final bool isInAlert;
|
||||
|
||||
/// progressStatus can be used to display information about the action
|
||||
/// progress when ExecutionState is in Progress.
|
||||
final ValueNotifier<String>? progressStatus;
|
||||
|
||||
const ButtonWidget({
|
||||
Key? key,
|
||||
required this.buttonType,
|
||||
this.buttonSize = ButtonSize.large,
|
||||
this.icon,
|
||||
this.labelText,
|
||||
this.onTap,
|
||||
this.shouldStickToDarkTheme = false,
|
||||
this.isDisabled = false,
|
||||
this.buttonAction,
|
||||
this.isInAlert = false,
|
||||
this.iconColor,
|
||||
this.shouldSurfaceExecutionStates = true,
|
||||
this.progressStatus,
|
||||
this.shouldShowSuccessConfirmation = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme =
|
||||
shouldStickToDarkTheme ? darkScheme : getEnteColorScheme(context);
|
||||
final inverseColorScheme = shouldStickToDarkTheme
|
||||
? lightScheme
|
||||
: getEnteColorScheme(context, inverse: true);
|
||||
final textTheme =
|
||||
shouldStickToDarkTheme ? darkTextTheme : getEnteTextTheme(context);
|
||||
final inverseTextTheme = shouldStickToDarkTheme
|
||||
? lightTextTheme
|
||||
: getEnteTextTheme(context, inverse: true);
|
||||
final buttonStyle = CustomButtonStyle(
|
||||
//Dummy default values since we need to keep these properties non-nullable
|
||||
defaultButtonColor: Colors.transparent,
|
||||
defaultBorderColor: Colors.transparent,
|
||||
defaultIconColor: Colors.transparent,
|
||||
defaultLabelStyle: textTheme.body,
|
||||
);
|
||||
buttonStyle.defaultButtonColor = buttonType.defaultButtonColor(colorScheme);
|
||||
buttonStyle.pressedButtonColor = buttonType.pressedButtonColor(colorScheme);
|
||||
buttonStyle.disabledButtonColor =
|
||||
buttonType.disabledButtonColor(colorScheme, buttonSize);
|
||||
buttonStyle.defaultBorderColor =
|
||||
buttonType.defaultBorderColor(colorScheme, buttonSize);
|
||||
buttonStyle.pressedBorderColor = buttonType.pressedBorderColor(
|
||||
colorScheme: colorScheme,
|
||||
buttonSize: buttonSize,
|
||||
);
|
||||
buttonStyle.disabledBorderColor =
|
||||
buttonType.disabledBorderColor(colorScheme, buttonSize);
|
||||
buttonStyle.defaultIconColor = iconColor ??
|
||||
buttonType.defaultIconColor(
|
||||
colorScheme: colorScheme,
|
||||
inverseColorScheme: inverseColorScheme,
|
||||
);
|
||||
buttonStyle.pressedIconColor =
|
||||
buttonType.pressedIconColor(colorScheme, buttonSize);
|
||||
buttonStyle.disabledIconColor =
|
||||
buttonType.disabledIconColor(colorScheme, buttonSize);
|
||||
buttonStyle.defaultLabelStyle = buttonType.defaultLabelStyle(
|
||||
textTheme: textTheme,
|
||||
inverseTextTheme: inverseTextTheme,
|
||||
);
|
||||
buttonStyle.pressedLabelStyle =
|
||||
buttonType.pressedLabelStyle(textTheme, colorScheme, buttonSize);
|
||||
buttonStyle.disabledLabelStyle =
|
||||
buttonType.disabledLabelStyle(textTheme, colorScheme);
|
||||
buttonStyle.checkIconColor = buttonType.checkIconColor(colorScheme);
|
||||
|
||||
return ButtonChildWidget(
|
||||
buttonStyle: buttonStyle,
|
||||
buttonType: buttonType,
|
||||
isDisabled: isDisabled,
|
||||
buttonSize: buttonSize,
|
||||
isInAlert: isInAlert,
|
||||
onTap: onTap,
|
||||
labelText: labelText,
|
||||
icon: icon,
|
||||
buttonAction: buttonAction,
|
||||
shouldSurfaceExecutionStates: shouldSurfaceExecutionStates,
|
||||
progressStatus: progressStatus,
|
||||
shouldShowSuccessConfirmation: shouldShowSuccessConfirmation,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ButtonChildWidget extends StatefulWidget {
|
||||
final CustomButtonStyle buttonStyle;
|
||||
final FutureVoidCallback? onTap;
|
||||
final ButtonType buttonType;
|
||||
final String? labelText;
|
||||
final IconData? icon;
|
||||
final bool isDisabled;
|
||||
final ButtonSize buttonSize;
|
||||
final ButtonAction? buttonAction;
|
||||
final bool isInAlert;
|
||||
final bool shouldSurfaceExecutionStates;
|
||||
final ValueNotifier<String>? progressStatus;
|
||||
final bool shouldShowSuccessConfirmation;
|
||||
|
||||
const ButtonChildWidget({
|
||||
Key? key,
|
||||
required this.buttonStyle,
|
||||
required this.buttonType,
|
||||
required this.isDisabled,
|
||||
required this.buttonSize,
|
||||
required this.isInAlert,
|
||||
required this.shouldSurfaceExecutionStates,
|
||||
required this.shouldShowSuccessConfirmation,
|
||||
this.progressStatus,
|
||||
this.onTap,
|
||||
this.labelText,
|
||||
this.icon,
|
||||
this.buttonAction,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ButtonChildWidget> createState() => _ButtonChildWidgetState();
|
||||
}
|
||||
|
||||
class _ButtonChildWidgetState extends State<ButtonChildWidget> {
|
||||
late Color buttonColor;
|
||||
late Color borderColor;
|
||||
late Color iconColor;
|
||||
late TextStyle labelStyle;
|
||||
late Color checkIconColor;
|
||||
late Color loadingIconColor;
|
||||
ValueNotifier<String>? progressStatus;
|
||||
|
||||
///This is used to store the width of the button in idle state (small button)
|
||||
///to be used as width for the button when the loading/succes states comes.
|
||||
double? widthOfButton;
|
||||
final _debouncer = Debouncer(const Duration(milliseconds: 300));
|
||||
ExecutionState executionState = ExecutionState.idle;
|
||||
Exception? _exception;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_setButtonTheme();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant ButtonChildWidget oldWidget) {
|
||||
_setButtonTheme();
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (executionState == ExecutionState.successful) {
|
||||
Future.delayed(Duration(seconds: widget.isInAlert ? 1 : 2), () {
|
||||
setState(() {
|
||||
executionState = ExecutionState.idle;
|
||||
});
|
||||
});
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: _shouldRegisterGestures ? _onTap : null,
|
||||
onTapDown: _shouldRegisterGestures ? _onTapDown : null,
|
||||
onTapUp: _shouldRegisterGestures ? _onTapUp : null,
|
||||
onTapCancel: _shouldRegisterGestures ? _onTapCancel : null,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||
border: widget.buttonType == ButtonType.tertiaryCritical
|
||||
? Border.all(color: borderColor)
|
||||
: null,
|
||||
),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 16),
|
||||
width: widget.buttonSize == ButtonSize.large ? double.infinity : null,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||
color: buttonColor,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 16),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 175),
|
||||
switchInCurve: Curves.easeInOutExpo,
|
||||
switchOutCurve: Curves.easeInOutExpo,
|
||||
child: executionState == ExecutionState.idle ||
|
||||
!widget.shouldSurfaceExecutionStates
|
||||
? widget.buttonType.hasTrailingIcon
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
widget.labelText == null
|
||||
? const SizedBox.shrink()
|
||||
: Flexible(
|
||||
child: Padding(
|
||||
padding: widget.icon == null
|
||||
? const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
)
|
||||
: const EdgeInsets.only(right: 16),
|
||||
child: Text(
|
||||
widget.labelText!,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
style: labelStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
widget.icon == null
|
||||
? const SizedBox.shrink()
|
||||
: Icon(
|
||||
widget.icon,
|
||||
size: 20,
|
||||
color: iconColor,
|
||||
),
|
||||
],
|
||||
)
|
||||
: Builder(
|
||||
builder: (context) {
|
||||
SchedulerBinding.instance.addPostFrameCallback(
|
||||
(timeStamp) {
|
||||
final box =
|
||||
context.findRenderObject() as RenderBox;
|
||||
widthOfButton = box.size.width;
|
||||
},
|
||||
);
|
||||
return Row(
|
||||
mainAxisSize:
|
||||
widget.buttonSize == ButtonSize.large
|
||||
? MainAxisSize.max
|
||||
: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
widget.icon == null
|
||||
? const SizedBox.shrink()
|
||||
: Icon(
|
||||
widget.icon,
|
||||
size: 20,
|
||||
color: iconColor,
|
||||
),
|
||||
widget.icon == null || widget.labelText == null
|
||||
? const SizedBox.shrink()
|
||||
: const SizedBox(width: 8),
|
||||
widget.labelText == null
|
||||
? const SizedBox.shrink()
|
||||
: Flexible(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
),
|
||||
child: Text(
|
||||
widget.labelText!,
|
||||
style: labelStyle,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
)
|
||||
: executionState == ExecutionState.inProgress
|
||||
? SizedBox(
|
||||
width: widthOfButton,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
progressStatus == null
|
||||
? const SizedBox.shrink()
|
||||
: ValueListenableBuilder<String>(
|
||||
valueListenable: progressStatus!,
|
||||
builder: (
|
||||
BuildContext context,
|
||||
String value,
|
||||
Widget? child,
|
||||
) {
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 8.0),
|
||||
child: Text(
|
||||
value,
|
||||
style: lightTextTheme.smallBold,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
EnteLoadingWidget(
|
||||
padding: 3,
|
||||
color: loadingIconColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: executionState == ExecutionState.successful
|
||||
? SizedBox(
|
||||
width: widthOfButton,
|
||||
child: Icon(
|
||||
Icons.check_outlined,
|
||||
size: 20,
|
||||
color: checkIconColor,
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(), //fallback
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _setButtonTheme() {
|
||||
progressStatus = widget.progressStatus;
|
||||
checkIconColor = widget.buttonStyle.checkIconColor ??
|
||||
widget.buttonStyle.defaultIconColor;
|
||||
loadingIconColor = widget.buttonStyle.defaultIconColor;
|
||||
if (widget.isDisabled) {
|
||||
buttonColor = widget.buttonStyle.disabledButtonColor ??
|
||||
widget.buttonStyle.defaultButtonColor;
|
||||
borderColor = widget.buttonStyle.disabledBorderColor ??
|
||||
widget.buttonStyle.defaultBorderColor;
|
||||
iconColor = widget.buttonStyle.disabledIconColor ??
|
||||
widget.buttonStyle.defaultIconColor;
|
||||
labelStyle = widget.buttonStyle.disabledLabelStyle ??
|
||||
widget.buttonStyle.defaultLabelStyle;
|
||||
} else {
|
||||
buttonColor = widget.buttonStyle.defaultButtonColor;
|
||||
borderColor = widget.buttonStyle.defaultBorderColor;
|
||||
iconColor = widget.buttonStyle.defaultIconColor;
|
||||
labelStyle = widget.buttonStyle.defaultLabelStyle;
|
||||
}
|
||||
}
|
||||
|
||||
bool get _shouldRegisterGestures =>
|
||||
!widget.isDisabled && executionState == ExecutionState.idle;
|
||||
|
||||
void _onTap() async {
|
||||
if (widget.onTap != null) {
|
||||
_debouncer.run(
|
||||
() => Future(() {
|
||||
setState(() {
|
||||
executionState = ExecutionState.inProgress;
|
||||
});
|
||||
}),
|
||||
);
|
||||
await widget.onTap!.call().then(
|
||||
(value) {
|
||||
_exception = null;
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
executionState = ExecutionState.error;
|
||||
_exception = error as Exception;
|
||||
_debouncer.cancelDebounce();
|
||||
},
|
||||
);
|
||||
widget.shouldShowSuccessConfirmation && _debouncer.isActive()
|
||||
? executionState = ExecutionState.successful
|
||||
: null;
|
||||
_debouncer.cancelDebounce();
|
||||
if (executionState == ExecutionState.successful) {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
// when the time taken by widget.onTap is approximately equal to the debounce
|
||||
// time, the callback is getting executed when/after the if condition
|
||||
// below is executing/executed which results in execution state stuck at
|
||||
// idle state. This Future is for delaying the execution of the if
|
||||
// condition so that the calback in the debouncer finishes execution before.
|
||||
await Future.delayed(const Duration(milliseconds: 5));
|
||||
}
|
||||
if (executionState == ExecutionState.inProgress ||
|
||||
executionState == ExecutionState.error) {
|
||||
if (executionState == ExecutionState.inProgress) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
executionState = ExecutionState.successful;
|
||||
Future.delayed(
|
||||
Duration(
|
||||
seconds: widget.shouldSurfaceExecutionStates
|
||||
? (widget.isInAlert ? 1 : 2)
|
||||
: 0,
|
||||
), () {
|
||||
widget.isInAlert
|
||||
? _popWithButtonAction(
|
||||
context,
|
||||
buttonAction: widget.buttonAction,
|
||||
)
|
||||
: null;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
executionState = ExecutionState.idle;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
if (executionState == ExecutionState.error) {
|
||||
setState(() {
|
||||
executionState = ExecutionState.idle;
|
||||
widget.isInAlert
|
||||
? Future.delayed(
|
||||
const Duration(seconds: 0),
|
||||
() => _popWithButtonAction(
|
||||
context,
|
||||
buttonAction: ButtonAction.error,
|
||||
exception: _exception,
|
||||
),
|
||||
)
|
||||
: null;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (widget.isInAlert) {
|
||||
Future.delayed(
|
||||
Duration(seconds: widget.shouldShowSuccessConfirmation ? 1 : 0),
|
||||
() =>
|
||||
_popWithButtonAction(context, buttonAction: widget.buttonAction),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _popWithButtonAction(
|
||||
BuildContext context, {
|
||||
required ButtonAction? buttonAction,
|
||||
Exception? exception,
|
||||
}) {
|
||||
if (Navigator.of(context).canPop()) {
|
||||
Navigator.of(context).pop(ButtonResult(widget.buttonAction, exception));
|
||||
} else if (exception != null) {
|
||||
//This is to show the execution was unsuccessful if the dialog is manually
|
||||
//closed before the execution completes.
|
||||
showGenericErrorDialog(context: context);
|
||||
}
|
||||
}
|
||||
|
||||
void _onTapDown(details) {
|
||||
setState(() {
|
||||
buttonColor = widget.buttonStyle.pressedButtonColor ??
|
||||
widget.buttonStyle.defaultButtonColor;
|
||||
borderColor = widget.buttonStyle.pressedBorderColor ??
|
||||
widget.buttonStyle.defaultBorderColor;
|
||||
iconColor = widget.buttonStyle.pressedIconColor ??
|
||||
widget.buttonStyle.defaultIconColor;
|
||||
labelStyle = widget.buttonStyle.pressedLabelStyle ??
|
||||
widget.buttonStyle.defaultLabelStyle;
|
||||
});
|
||||
}
|
||||
|
||||
void _onTapUp(details) {
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 84),
|
||||
() => setState(() {
|
||||
setAllStylesToDefault();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
void _onTapCancel() {
|
||||
setState(() {
|
||||
setAllStylesToDefault();
|
||||
});
|
||||
}
|
||||
|
||||
void setAllStylesToDefault() {
|
||||
buttonColor = widget.buttonStyle.defaultButtonColor;
|
||||
borderColor = widget.buttonStyle.defaultBorderColor;
|
||||
iconColor = widget.buttonStyle.defaultIconColor;
|
||||
labelStyle = widget.buttonStyle.defaultLabelStyle;
|
||||
}
|
||||
}
|
11
lib/ui/components/models/button_result.dart
Normal file
11
lib/ui/components/models/button_result.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
||||
|
||||
class ButtonResult {
|
||||
///action can be null when action for the button that is returned when popping
|
||||
///the widget (dialog, actionSheet) which uses a ButtonWidget isn't
|
||||
///relevant/useful and so is not assigned a value when an instance of
|
||||
///ButtonWidget is created.
|
||||
final ButtonAction? action;
|
||||
final Exception? exception;
|
||||
ButtonResult([this.action, this.exception]);
|
||||
}
|
205
lib/ui/components/models/button_type.dart
Normal file
205
lib/ui/components/models/button_type.dart
Normal file
|
@ -0,0 +1,205 @@
|
|||
import 'package:ente_auth/theme/colors.dart';
|
||||
import 'package:ente_auth/theme/text_style.dart';
|
||||
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum ButtonType {
|
||||
primary,
|
||||
secondary,
|
||||
neutral,
|
||||
trailingIcon,
|
||||
critical,
|
||||
tertiaryCritical,
|
||||
trailingIconPrimary,
|
||||
trailingIconSecondary,
|
||||
tertiary;
|
||||
|
||||
bool get isPrimary =>
|
||||
this == ButtonType.primary || this == ButtonType.trailingIconPrimary;
|
||||
|
||||
bool get hasTrailingIcon =>
|
||||
this == ButtonType.trailingIcon ||
|
||||
this == ButtonType.trailingIconPrimary ||
|
||||
this == ButtonType.trailingIconSecondary;
|
||||
|
||||
bool get isSecondary =>
|
||||
this == ButtonType.secondary || this == ButtonType.trailingIconSecondary;
|
||||
|
||||
bool get isCritical =>
|
||||
this == ButtonType.critical || this == ButtonType.tertiaryCritical;
|
||||
|
||||
bool get isNeutral =>
|
||||
this == ButtonType.neutral || this == ButtonType.trailingIcon;
|
||||
|
||||
Color defaultButtonColor(EnteColorScheme colorScheme) {
|
||||
if (isPrimary) {
|
||||
return colorScheme.primary500;
|
||||
}
|
||||
if (isSecondary) {
|
||||
return colorScheme.fillFaint;
|
||||
}
|
||||
if (this == ButtonType.neutral || this == ButtonType.trailingIcon) {
|
||||
return colorScheme.fillBase;
|
||||
}
|
||||
if (this == ButtonType.critical) {
|
||||
return colorScheme.warning700;
|
||||
}
|
||||
if (this == ButtonType.tertiaryCritical) {
|
||||
return Colors.transparent;
|
||||
}
|
||||
return Colors.transparent;
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
Color? pressedButtonColor(EnteColorScheme colorScheme) {
|
||||
if (isPrimary) {
|
||||
return colorScheme.primary700;
|
||||
}
|
||||
if (isSecondary) {
|
||||
return colorScheme.fillFaintPressed;
|
||||
}
|
||||
if (isNeutral) {
|
||||
return colorScheme.fillBasePressed;
|
||||
}
|
||||
if (this == ButtonType.critical) {
|
||||
return colorScheme.warning800;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
Color? disabledButtonColor(
|
||||
EnteColorScheme colorScheme,
|
||||
ButtonSize buttonSize,
|
||||
) {
|
||||
if (buttonSize == ButtonSize.small &&
|
||||
(this == ButtonType.primary ||
|
||||
this == ButtonType.neutral ||
|
||||
this == ButtonType.critical)) {
|
||||
return colorScheme.fillMuted;
|
||||
}
|
||||
if (isPrimary || this == ButtonType.critical || isNeutral) {
|
||||
return colorScheme.fillFaint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Color defaultBorderColor(EnteColorScheme colorScheme, ButtonSize buttonSize) {
|
||||
if (this == ButtonType.tertiaryCritical && buttonSize == ButtonSize.large) {
|
||||
return colorScheme.warning700;
|
||||
}
|
||||
return Colors.transparent;
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
Color? pressedBorderColor({
|
||||
required EnteColorScheme colorScheme,
|
||||
required ButtonSize buttonSize,
|
||||
}) {
|
||||
if (this == ButtonType.tertiaryCritical && buttonSize == ButtonSize.large) {
|
||||
return colorScheme.warning700;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
Color? disabledBorderColor(
|
||||
EnteColorScheme colorScheme,
|
||||
ButtonSize buttonSize,
|
||||
) {
|
||||
if (this == ButtonType.tertiaryCritical && buttonSize == ButtonSize.large) {
|
||||
return colorScheme.strokeMuted;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Color defaultIconColor({
|
||||
required EnteColorScheme colorScheme,
|
||||
required EnteColorScheme inverseColorScheme,
|
||||
}) {
|
||||
if (isPrimary || this == ButtonType.critical) {
|
||||
return strokeBaseDark;
|
||||
}
|
||||
if (this == ButtonType.neutral || this == ButtonType.trailingIcon) {
|
||||
return inverseColorScheme.strokeBase;
|
||||
}
|
||||
if (this == ButtonType.tertiaryCritical) {
|
||||
return colorScheme.warning500;
|
||||
}
|
||||
//fallback
|
||||
return colorScheme.strokeBase;
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
Color? pressedIconColor(EnteColorScheme colorScheme, ButtonSize buttonSize) {
|
||||
if (this == ButtonType.tertiaryCritical) {
|
||||
return colorScheme.warning700;
|
||||
}
|
||||
if (this == ButtonType.tertiary && buttonSize == ButtonSize.small) {
|
||||
return colorScheme.fillBasePressed;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
Color? disabledIconColor(EnteColorScheme colorScheme, ButtonSize buttonSize) {
|
||||
if (isPrimary ||
|
||||
isSecondary ||
|
||||
isNeutral ||
|
||||
buttonSize == ButtonSize.small) {
|
||||
return colorScheme.strokeMuted;
|
||||
}
|
||||
if (isCritical) {
|
||||
return colorScheme.strokeFaint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
TextStyle defaultLabelStyle({
|
||||
required EnteTextTheme textTheme,
|
||||
required EnteTextTheme inverseTextTheme,
|
||||
}) {
|
||||
if (isPrimary || this == ButtonType.critical) {
|
||||
return textTheme.bodyBold.copyWith(color: textBaseDark);
|
||||
}
|
||||
if (this == ButtonType.neutral || this == ButtonType.trailingIcon) {
|
||||
return inverseTextTheme.bodyBold;
|
||||
}
|
||||
if (this == ButtonType.tertiaryCritical) {
|
||||
return textTheme.bodyBold.copyWith(color: warning500);
|
||||
}
|
||||
//fallback
|
||||
return textTheme.bodyBold;
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
TextStyle? pressedLabelStyle(
|
||||
EnteTextTheme textTheme,
|
||||
EnteColorScheme colorScheme,
|
||||
ButtonSize buttonSize,
|
||||
) {
|
||||
if (this == ButtonType.tertiaryCritical) {
|
||||
return textTheme.bodyBold.copyWith(color: colorScheme.warning700);
|
||||
}
|
||||
if (this == ButtonType.tertiary && buttonSize == ButtonSize.small) {
|
||||
return textTheme.bodyBold.copyWith(color: colorScheme.fillBasePressed);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
TextStyle? disabledLabelStyle(
|
||||
EnteTextTheme textTheme,
|
||||
EnteColorScheme colorScheme,
|
||||
) {
|
||||
return textTheme.bodyBold.copyWith(color: colorScheme.textFaint);
|
||||
}
|
||||
|
||||
//Returning null to fallback to default color
|
||||
Color? checkIconColor(EnteColorScheme colorScheme) {
|
||||
if (isSecondary) {
|
||||
return colorScheme.primary500;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
33
lib/ui/components/models/custom_button_style.dart
Normal file
33
lib/ui/components/models/custom_button_style.dart
Normal file
|
@ -0,0 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomButtonStyle {
|
||||
Color defaultButtonColor;
|
||||
Color? pressedButtonColor;
|
||||
Color? disabledButtonColor;
|
||||
Color defaultBorderColor;
|
||||
Color? pressedBorderColor;
|
||||
Color? disabledBorderColor;
|
||||
Color defaultIconColor;
|
||||
Color? pressedIconColor;
|
||||
Color? disabledIconColor;
|
||||
TextStyle defaultLabelStyle;
|
||||
TextStyle? pressedLabelStyle;
|
||||
TextStyle? disabledLabelStyle;
|
||||
Color? checkIconColor;
|
||||
|
||||
CustomButtonStyle({
|
||||
required this.defaultButtonColor,
|
||||
this.pressedButtonColor,
|
||||
this.disabledButtonColor,
|
||||
required this.defaultBorderColor,
|
||||
this.pressedBorderColor,
|
||||
this.disabledBorderColor,
|
||||
required this.defaultIconColor,
|
||||
this.pressedIconColor,
|
||||
this.disabledIconColor,
|
||||
required this.defaultLabelStyle,
|
||||
this.pressedLabelStyle,
|
||||
this.disabledLabelStyle,
|
||||
this.checkIconColor,
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue