Merge pull request #712 from ente-io/action-sheet-add-on
Return ButtonAction from ActionSheet
This commit is contained in:
commit
14feb64609
|
@ -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,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue