Merge pull request #712 from ente-io/action-sheet-add-on

Return ButtonAction from ActionSheet
This commit is contained in:
Ashil 2022-12-16 16:59:19 +05:30 committed by GitHub
commit 14feb64609
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 28 deletions

View file

@ -6,6 +6,7 @@ import 'package:photos/core/constants.dart';
import 'package:photos/theme/colors.dart'; import 'package:photos/theme/colors.dart';
import 'package:photos/theme/effects.dart'; import 'package:photos/theme/effects.dart';
import 'package:photos/theme/ente_theme.dart'; import 'package:photos/theme/ente_theme.dart';
import 'package:photos/ui/components/button_widget.dart';
import 'package:photos/utils/separators_util.dart'; import 'package:photos/utils/separators_util.dart';
enum ActionSheetType { enum ActionSheetType {
@ -13,15 +14,15 @@ enum ActionSheetType {
iconOnly, iconOnly,
} }
void showActionSheet({ Future<dynamic> showActionSheet({
required BuildContext context, required BuildContext context,
required List<Widget> buttons, required List<ButtonWidget> buttons,
required ActionSheetType actionSheetType, required ActionSheetType actionSheetType,
bool isCheckIconGreen = false, bool isCheckIconGreen = false,
String? title, String? title,
String? body, String? body,
}) { }) {
showMaterialModalBottomSheet( return showMaterialModalBottomSheet(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
barrierColor: backdropMutedDark, barrierColor: backdropMutedDark,
useRootNavigator: true, useRootNavigator: true,
@ -35,13 +36,15 @@ void showActionSheet({
isCheckIconGreen: isCheckIconGreen, isCheckIconGreen: isCheckIconGreen,
); );
}, },
isDismissible: false,
enableDrag: false,
); );
} }
class ActionSheetWidget extends StatelessWidget { class ActionSheetWidget extends StatelessWidget {
final String? title; final String? title;
final String? body; final String? body;
final List<Widget> actionButtons; final List<ButtonWidget> actionButtons;
final ActionSheetType actionSheetType; final ActionSheetType actionSheetType;
final bool isCheckIconGreen; final bool isCheckIconGreen;
@ -153,11 +156,13 @@ class ContentContainerWidget extends StatelessWidget {
style: textTheme.body style: textTheme.body
.copyWith(color: textMutedDark), //constant color .copyWith(color: textMutedDark), //constant color
) )
: Icon(Icons.check_outlined, : Icon(
Icons.check_outlined,
size: 48, size: 48,
color: isCheckIconGreen color: isCheckIconGreen
? getEnteColorScheme(context).primary700 ? getEnteColorScheme(context).primary700
: strokeBaseDark) : strokeBaseDark,
)
], ],
); );
} }

View file

@ -11,7 +11,8 @@ import 'package:photos/utils/debouncer.dart';
enum ExecutionState { enum ExecutionState {
idle, idle,
inProgress, inProgress,
successful, error,
successful;
} }
enum ButtonSize { enum ButtonSize {
@ -19,6 +20,14 @@ enum ButtonSize {
large; large;
} }
enum ButtonAction {
first,
second,
third,
cancel,
error;
}
typedef FutureVoidCallback = Future<void> Function(); typedef FutureVoidCallback = Future<void> Function();
class ButtonWidget extends StatelessWidget { class ButtonWidget extends StatelessWidget {
@ -29,30 +38,40 @@ class ButtonWidget extends StatelessWidget {
final bool isDisabled; final bool isDisabled;
final ButtonSize buttonSize; final ButtonSize buttonSize;
///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 ///setting this flag to true will make the button appear like how it would
///on dark theme irrespective of the app's theme. ///on dark theme irrespective of the app's theme.
final bool isInActionSheet; 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;
const ButtonWidget({ const ButtonWidget({
required this.buttonType, required this.buttonType,
required this.buttonSize, required this.buttonSize,
this.icon, this.icon,
this.labelText, this.labelText,
this.onTap, this.onTap,
this.isInActionSheet = false, this.shouldStickToDarkTheme = false,
this.isDisabled = false, this.isDisabled = false,
this.buttonAction,
this.isInAlert = false,
super.key, super.key,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final colorScheme = final colorScheme =
isInActionSheet ? darkScheme : getEnteColorScheme(context); shouldStickToDarkTheme ? darkScheme : getEnteColorScheme(context);
final inverseColorScheme = isInActionSheet final inverseColorScheme = shouldStickToDarkTheme
? lightScheme ? lightScheme
: getEnteColorScheme(context, inverse: true); : getEnteColorScheme(context, inverse: true);
final textTheme = final textTheme =
isInActionSheet ? darkTextTheme : getEnteTextTheme(context); shouldStickToDarkTheme ? darkTextTheme : getEnteTextTheme(context);
final inverseTextTheme = isInActionSheet final inverseTextTheme = shouldStickToDarkTheme
? lightTextTheme ? lightTextTheme
: getEnteTextTheme(context, inverse: true); : getEnteTextTheme(context, inverse: true);
final buttonStyle = CustomButtonStyle( final buttonStyle = CustomButtonStyle(
@ -93,19 +112,21 @@ class ButtonWidget extends StatelessWidget {
buttonType.disabledLabelStyle(textTheme, colorScheme); buttonType.disabledLabelStyle(textTheme, colorScheme);
buttonStyle.checkIconColor = buttonType.checkIconColor(colorScheme); buttonStyle.checkIconColor = buttonType.checkIconColor(colorScheme);
return LargeButtonChildWidget( return ButtonChildWidget(
buttonStyle: buttonStyle, buttonStyle: buttonStyle,
buttonType: buttonType, buttonType: buttonType,
isDisabled: isDisabled, isDisabled: isDisabled,
buttonSize: buttonSize, buttonSize: buttonSize,
isInAlert: isInAlert,
onTap: onTap, onTap: onTap,
labelText: labelText, labelText: labelText,
icon: icon, icon: icon,
buttonAction: buttonAction,
); );
} }
} }
class LargeButtonChildWidget extends StatefulWidget { class ButtonChildWidget extends StatefulWidget {
final CustomButtonStyle buttonStyle; final CustomButtonStyle buttonStyle;
final FutureVoidCallback? onTap; final FutureVoidCallback? onTap;
final ButtonType buttonType; final ButtonType buttonType;
@ -113,22 +134,26 @@ class LargeButtonChildWidget extends StatefulWidget {
final IconData? icon; final IconData? icon;
final bool isDisabled; final bool isDisabled;
final ButtonSize buttonSize; final ButtonSize buttonSize;
const LargeButtonChildWidget({ final ButtonAction? buttonAction;
final bool isInAlert;
const ButtonChildWidget({
required this.buttonStyle, required this.buttonStyle,
required this.buttonType, required this.buttonType,
required this.isDisabled, required this.isDisabled,
required this.buttonSize, required this.buttonSize,
required this.isInAlert,
this.onTap, this.onTap,
this.labelText, this.labelText,
this.icon, this.icon,
this.buttonAction,
super.key, super.key,
}); });
@override @override
State<LargeButtonChildWidget> createState() => _LargeButtonChildWidgetState(); State<ButtonChildWidget> createState() => _ButtonChildWidgetState();
} }
class _LargeButtonChildWidgetState extends State<LargeButtonChildWidget> { class _ButtonChildWidgetState extends State<ButtonChildWidget> {
late Color buttonColor; late Color buttonColor;
late Color borderColor; late Color borderColor;
late Color iconColor; late Color iconColor;
@ -303,9 +328,10 @@ class _LargeButtonChildWidgetState extends State<LargeButtonChildWidget> {
}); });
}), }),
); );
await widget.onTap! await widget.onTap!.call().onError((error, stackTrace) {
.call() executionState = ExecutionState.error;
.onError((error, stackTrace) => _debouncer.cancelDebounce()); _debouncer.cancelDebounce();
});
_debouncer.cancelDebounce(); _debouncer.cancelDebounce();
// when the time taken by widget.onTap is approximately equal to the debounce // when the time taken by widget.onTap is approximately equal to the debounce
// time, the callback is getting executed when/after the if condition // time, the callback is getting executed when/after the if condition
@ -313,15 +339,41 @@ class _LargeButtonChildWidgetState extends State<LargeButtonChildWidget> {
// idle state. This Future is for delaying the execution of the if // idle state. This Future is for delaying the execution of the if
// condition so that the calback in the debouncer finishes execution before. // condition so that the calback in the debouncer finishes execution before.
await Future.delayed(const Duration(milliseconds: 5)); await Future.delayed(const Duration(milliseconds: 5));
if (executionState == ExecutionState.inProgress) { if (executionState == ExecutionState.inProgress ||
setState(() { executionState == ExecutionState.error) {
executionState = ExecutionState.successful; if (executionState == ExecutionState.inProgress) {
Future.delayed(const Duration(seconds: 2), () { setState(() {
setState(() { executionState = ExecutionState.successful;
executionState = ExecutionState.idle; Future.delayed(Duration(seconds: widget.isInAlert ? 1 : 2), () {
widget.isInAlert
? Navigator.of(context, rootNavigator: true)
.pop(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),
() => Navigator.of(context, rootNavigator: true).pop(
ButtonAction.error,
),
)
: null;
});
}
} else {
if (widget.isInAlert) {
Navigator.of(context).pop(widget.buttonAction);
}
} }
} }