Skip to content

Commit

Permalink
feat: dialog added loading indicators, loading indicator added color
Browse files Browse the repository at this point in the history
  • Loading branch information
vanlooverenkoen committed Aug 29, 2024
1 parent 4ffd6b8 commit 0b9053b
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 70 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 0.10.0

## Feat

- ImpaktfullDialog now has loading states for the actions
- ImpaktfullLoadingIndicator now has a `color` parameter

# 0.9.0

## Breaking
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.8.0"
version: "0.9.0"
integration_test:
dependency: "direct dev"
description: flutter
Expand Down
78 changes: 39 additions & 39 deletions lib/src/components/button/impaktfull_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,50 +62,50 @@ class _ImpaktfullButtonState extends State<ImpaktfullButton> {
Widget build(BuildContext context) {
final hasOnTap = widget.onTap != null || widget.onAsyncTap != null;
return ImpaktfullThemeLocalizer(
builder: (context, theme) => Opacity(
opacity: hasOnTap ? 1 : 0.3,
child: IgnorePointer(
ignoring: !hasOnTap,
child: Stack(
alignment: Alignment.center,
children: [
Visibility.maintain(
visible: !_isLoading,
child: ImpaktfullTouchFeedback(
onTap: hasOnTap ? _onTap : null,
color: _getBackground(theme),
shadow: [
if (theme.shadows.button != null &&
widget._type != _ButtonType.secondary)
theme.shadows.button!,
],
borderRadius:
BorderRadius.circular(theme.dimens.generalBorderRadius),
child: Container(
constraints: const BoxConstraints(
minWidth: 48,
minHeight: 48,
),
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 16,
),
child: Text(
widget.label,
style: _getTextStyle(theme).title,
textAlign: TextAlign.center,
builder: (context, theme) {
final background = _getBackground(theme);
return Opacity(
opacity: hasOnTap ? 1 : 0.3,
child: IgnorePointer(
ignoring: !hasOnTap,
child: Stack(
alignment: Alignment.center,
children: [
Visibility.maintain(
visible: !_isLoading,
child: ImpaktfullTouchFeedback(
onTap: hasOnTap ? _onTap : null,
color: background,
shadow: [
if (theme.shadows.button != null && widget._type != _ButtonType.secondary) theme.shadows.button!,
],
borderRadius: BorderRadius.circular(theme.dimens.generalBorderRadius),
child: Container(
constraints: const BoxConstraints(
minWidth: 48,
minHeight: 48,
),
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 16,
),
child: Text(
widget.label,
style: _getTextStyle(theme).title,
textAlign: TextAlign.center,
),
),
),
),
),
if (_isLoading) ...[
const ImpaktfullLoadingIndicator(),
if (_isLoading) ...[
ImpaktfullLoadingIndicator(color: background),
],
],
],
),
),
),
),
);
},
);
}

Expand Down
45 changes: 20 additions & 25 deletions lib/src/components/dialog/impaktfull_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:impaktfull_ui/impaktfull_ui.dart';
import 'package:impaktfull_ui/src/util/future/async_or_callback.dart';

class ImpaktfullDialog extends StatelessWidget {
final String? title;
Expand All @@ -7,8 +9,8 @@ class ImpaktfullDialog extends StatelessWidget {
final String? secondaryLabel;
final String? primaryLabel;
final ImpaktfullDialogPrimaryButtonType primaryButtonType;
final VoidCallback? onSecondaryTapped;
final VoidCallback? onPrimaryTapped;
final AsyncOrCallback? onSecondaryTapped;
final AsyncOrCallback? onPrimaryTapped;
final EdgeInsetsGeometry? margin;
final EdgeInsetsGeometry? padding;

Expand Down Expand Up @@ -38,8 +40,7 @@ class ImpaktfullDialog extends StatelessWidget {
padding: padding,
decoration: BoxDecoration(
color: theme.colors.card,
borderRadius:
BorderRadius.circular(theme.dimens.generalBorderRadius),
borderRadius: BorderRadius.circular(theme.dimens.generalBorderRadius),
),
child: Column(
mainAxisSize: MainAxisSize.min,
Expand All @@ -66,41 +67,35 @@ class ImpaktfullDialog extends StatelessWidget {
if (onSecondaryTapped != null) ...[
Expanded(
child: ImpaktfullButton.secondary(
label: secondaryLabel ??
theme.localizations.current.generalLabelCancel,
onTap: onSecondaryTapped,
label: secondaryLabel ?? theme.localizations.current.generalLabelCancel,
onTap: onSecondaryTapped is AsyncCallback ? null : onSecondaryTapped as VoidCallback,
onAsyncTap: onSecondaryTapped is AsyncCallback ? onSecondaryTapped as AsyncCallback : null,
),
),
],
if (onPrimaryTapped != null) ...[
if (primaryButtonType ==
ImpaktfullDialogPrimaryButtonType.primary) ...[
if (primaryButtonType == ImpaktfullDialogPrimaryButtonType.primary) ...[
Expanded(
child: ImpaktfullButton.primary(
label: primaryLabel ??
theme
.localizations.current.generalLabelAccept,
onTap: onPrimaryTapped,
label: primaryLabel ?? theme.localizations.current.generalLabelAccept,
onTap: onPrimaryTapped is AsyncCallback ? null : onPrimaryTapped as VoidCallback,
onAsyncTap: onPrimaryTapped is AsyncCallback ? onPrimaryTapped as AsyncCallback : null,
),
),
] else if (primaryButtonType ==
ImpaktfullDialogPrimaryButtonType.accent) ...[
] else if (primaryButtonType == ImpaktfullDialogPrimaryButtonType.accent) ...[
Expanded(
child: ImpaktfullButton.accent(
label: primaryLabel ??
theme
.localizations.current.generalLabelAccept,
onTap: onPrimaryTapped,
label: primaryLabel ?? theme.localizations.current.generalLabelAccept,
onTap: onPrimaryTapped is AsyncCallback ? null : onPrimaryTapped as VoidCallback,
onAsyncTap: onPrimaryTapped is AsyncCallback ? onPrimaryTapped as AsyncCallback : null,
),
),
] else if (primaryButtonType ==
ImpaktfullDialogPrimaryButtonType.danger) ...[
] else if (primaryButtonType == ImpaktfullDialogPrimaryButtonType.danger) ...[
Expanded(
child: ImpaktfullButton.danger(
label: primaryLabel ??
theme
.localizations.current.generalLabelAccept,
onTap: onPrimaryTapped,
label: primaryLabel ?? theme.localizations.current.generalLabelAccept,
onTap: onPrimaryTapped is AsyncCallback ? null : onPrimaryTapped as VoidCallback,
onAsyncTap: onPrimaryTapped is AsyncCallback ? onPrimaryTapped as AsyncCallback : null,
),
),
],
Expand Down
23 changes: 18 additions & 5 deletions lib/src/components/loading/impaktfull_loading.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,38 @@ import 'package:impaktfull_ui/src/theme/impaktfull_theme_localizer.dart';
import 'package:lottie/lottie.dart';

class ImpaktfullLoadingIndicator extends StatelessWidget {
final Color? color;
final String? asset;

const ImpaktfullLoadingIndicator({
this.color,
super.key,
}) : asset = null;

const ImpaktfullLoadingIndicator.custom({
required this.asset,
this.color,
super.key,
});

@override
Widget build(BuildContext context) {
return ImpaktfullThemeLocalizer(
builder: (context, theme) => Lottie.asset(
asset ?? theme.assets.lottie.loading,
width: 48,
height: 48,
),
builder: (context, theme) {
final lottie = Lottie.asset(
asset ?? theme.assets.lottie.loading,
width: 48,
height: 48,
);
if (color == null) return lottie;
return ColorFiltered(
colorFilter: ColorFilter.mode(
color!,
BlendMode.srcATop,
),
child: lottie,
);
},
);
}
}
3 changes: 3 additions & 0 deletions lib/src/util/future/async_or_callback.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import 'dart:async';

typedef AsyncOrCallback = FutureOr<void> Function();
20 changes: 20 additions & 0 deletions test/src/util/future/async_or_callback_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ignore_for_file: prefer_function_declarations_over_variables, unnecessary_type_check

import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:impaktfull_ui/src/util/future/async_or_callback.dart';

void main() {
test('AsyncCallback', () {
final AsyncOrCallback callback = () async {};
expect(callback is Future<void> Function(), true);
expect(callback is AsyncCallback, true);
});
test('VoidCallback', () {
final AsyncOrCallback callback = () {};
expect(callback is Future<void> Function(), false);
expect(callback is AsyncCallback, false);
expect(callback is void Function(), true);
expect(callback is VoidCallback, true);
});
}

0 comments on commit 0b9053b

Please sign in to comment.