Skip to content

Commit

Permalink
Merge branch 'main' into feat/seed-phrase-utils
Browse files Browse the repository at this point in the history
  • Loading branch information
apskhem authored Sep 20, 2024
2 parents 9594c20 + 05c5c9c commit f529ab6
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 37 deletions.
17 changes: 13 additions & 4 deletions catalyst_voices/lib/widgets/avatars/voices_avatar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class VoicesAvatar extends StatelessWidget {
/// The size of the avatar, expressed as the radius (half the diameter).
final double radius;

/// The border around the widget.
final Border? border;

/// The callback called when the widget is tapped.
final VoidCallback? onTap;

Expand All @@ -32,15 +35,21 @@ class VoicesAvatar extends StatelessWidget {
this.backgroundColor,
this.padding = const EdgeInsets.all(8),
this.radius = 20,
this.border,
this.onTap,
});

@override
Widget build(BuildContext context) {
return CircleAvatar(
radius: radius,
backgroundColor:
backgroundColor ?? Theme.of(context).colorScheme.primaryContainer,
return Container(
width: radius * 2,
height: radius * 2,
decoration: BoxDecoration(
color:
backgroundColor ?? Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(radius),
border: border,
),
child: Material(
type: MaterialType.transparency,
child: InkWell(
Expand Down
163 changes: 163 additions & 0 deletions catalyst_voices/lib/widgets/modals/voices_alert_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import 'package:catalyst_voices/widgets/widgets.dart';
import 'package:catalyst_voices_shared/catalyst_voices_shared.dart';
import 'package:flutter/material.dart';

/// An alert dialog similar to [AlertDialog]
/// but customized to the project needs.
///
/// On extra small screens (mobile) it will fill the whole screen width,
/// on larger screens it will take [_width] amount
/// of horizontal space and be centered.
///
/// The close (x) button will appear if the dialog [isDismissible].
class VoicesAlertDialog extends StatelessWidget {
static const double _width = 360;

/// The widget which appears at the top of the dialog next to the (x) button.
/// Usually a [Text] widget.
final Widget? title;

/// The widget which appears below the [title],
/// usually a [VoicesAvatar] widget.
final Widget? icon;

/// The widget appears below the [icon], is less prominent than the [title].
/// Usually a [Text] widget.
final Widget? subtitle;

/// The widget appears below the [subtitle], usually a [Text] widget,
/// can be multiline.
final Widget? content;

/// The list of widgets which appear at the bottom of the dialog,
/// usually [VoicesFilledButton] or [VoicesTextButton].
///
/// [buttons] are separated with 8px of padding between each other
/// so you don't need to add your own padding.
final List<Widget> buttons;

/// Whether to show a (x) close button.
final bool isDismissible;

const VoicesAlertDialog({
super.key,
this.title,
this.icon,
this.subtitle,
this.content,
this.buttons = const [],
this.isDismissible = true,
});

@override
Widget build(BuildContext context) {
final title = this.title;
final icon = this.icon;
final subtitle = this.subtitle;
final content = this.content;

return ResponsiveBuilder<double>(
xs: double.infinity,
other: _width,
builder: (context, width) {
return Dialog(
alignment: Alignment.center,
child: SizedBox(
width: width,
child: Padding(
padding: const EdgeInsets.only(top: 10, bottom: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (title != null || isDismissible)
Row(
children: [
// if widget is dismissible then show an invisible
// close button to reserve space on this side of the
// row so that the title is centered
if (isDismissible)
const Visibility(
visible: false,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
child: _CloseButton(),
),
Expanded(
child: DefaultTextStyle(
style: Theme.of(context).textTheme.titleLarge!,
textAlign: TextAlign.center,
child: title ?? const SizedBox.shrink(),
),
),
if (isDismissible) const _CloseButton(),
],
),
if (icon != null)
Padding(
padding: const EdgeInsets.only(
top: 24,
left: 20,
right: 20,
),
child: Center(child: icon),
),
if (subtitle != null)
Padding(
padding: const EdgeInsets.only(
top: 16,
left: 20,
right: 20,
),
child: DefaultTextStyle(
style: Theme.of(context).textTheme.titleSmall!,
textAlign: TextAlign.center,
child: subtitle,
),
),
if (content != null)
Padding(
padding: const EdgeInsets.only(
top: 16,
left: 20,
right: 20,
),
child: DefaultTextStyle(
style: Theme.of(context).textTheme.bodyMedium!,
textAlign: TextAlign.center,
child: content,
),
),
if (buttons.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 24),
...buttons.separatedBy(const SizedBox(height: 8)),
],
),
),
],
),
),
),
);
},
);
}
}

class _CloseButton extends StatelessWidget {
const _CloseButton();

@override
Widget build(BuildContext context) {
return XButton(
onTap: () => Navigator.of(context).pop(),
);
}
}
3 changes: 0 additions & 3 deletions catalyst_voices/lib/widgets/modals/voices_desktop_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@ class VoicesDesktopPanelsDialog extends StatelessWidget {
Expanded(
child: Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: theme.colors.elevationsOnSurfaceNeutralLv1White,
),
child: right,
),
),
Expand Down
8 changes: 6 additions & 2 deletions catalyst_voices/lib/widgets/modals/voices_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import 'package:flutter/material.dart';
/// meant to be extended.
abstract final class VoicesDialog {
/// Encapsulates single entry point.
static Future<T?> show<T>(
BuildContext context, {
static Future<T?> show<T>({
required BuildContext context,
required WidgetBuilder builder,
RouteSettings? routeSettings,
bool barrierDismissible = true,
}) {
return showDialog<T>(
context: context,
builder: builder,
routeSettings: routeSettings,
barrierDismissible: barrierDismissible,
);
}
}
10 changes: 5 additions & 5 deletions catalyst_voices/lib/widgets/modals/voices_info_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'package:flutter/material.dart';
/// Call [VoicesDialog.show] with [VoicesDesktopInfoDialog] in order
/// to show it.
class VoicesDesktopInfoDialog extends StatelessWidget {
final String title;
final Widget title;

const VoicesDesktopInfoDialog({
super.key,
Expand All @@ -26,10 +26,10 @@ class VoicesDesktopInfoDialog extends StatelessWidget {
left: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: theme.textTheme.titleLarge
?.copyWith(color: theme.colors.textOnPrimary),
DefaultTextStyle(
style: theme.textTheme.titleLarge!
.copyWith(color: theme.colors.textOnPrimary),
child: title,
),
],
),
Expand Down
1 change: 1 addition & 0 deletions catalyst_voices/lib/widgets/widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export 'menu/voices_list_tile.dart';
export 'menu/voices_menu.dart';
export 'menu/voices_node_menu.dart';
export 'menu/voices_wallet_tile.dart';
export 'modals/voices_alert_dialog.dart';
export 'modals/voices_desktop_dialog.dart';
export 'modals/voices_dialog.dart';
export 'modals/voices_info_dialog.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ ThemeData _buildThemeData(
barrierColor: const Color(0x612A3D61),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
clipBehavior: Clip.hardEdge,
backgroundColor: voicesColorScheme.onSurfaceNeutralOpaqueLv0,
backgroundColor: voicesColorScheme.elevationsOnSurfaceNeutralLv1White,
),
listTileTheme: ListTileThemeData(
shape: const StadiumBorder(),
Expand Down
40 changes: 21 additions & 19 deletions catalyst_voices/test/widgets/avatars/voices_avatar_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ void main() {
),
);

// Verify if CircleAvatar is rendered with the correct default radius.
final circleAvatarFinder = find.byType(CircleAvatar);
expect(circleAvatarFinder, findsOneWidget);
// Verify if Container is rendered with the correct default radius.
final containerFinder = find.byType(Container);
expect(containerFinder, findsOneWidget);

final circleAvatarWidget =
tester.widget<CircleAvatar>(circleAvatarFinder);
expect(circleAvatarWidget.radius, 20);
final containerWidget = tester.widget<Container>(containerFinder);
expect(containerWidget.constraints?.maxWidth, 40);

// Verify the icon is rendered.
expect(find.byIcon(Icons.person), findsOneWidget);
Expand All @@ -40,11 +39,10 @@ void main() {
),
);

// Verify if CircleAvatar is rendered with the correct custom radius.
final circleAvatarFinder = find.byType(CircleAvatar);
final circleAvatarWidget =
tester.widget<CircleAvatar>(circleAvatarFinder);
expect(circleAvatarWidget.radius, 30);
// Verify if Container is rendered with the correct custom radius.
final containerFinder = find.byType(Container);
final containerWidget = tester.widget<Container>(containerFinder);
expect(containerWidget.constraints?.maxWidth, 60);

// Verify the Padding is applied correctly.
final paddingFinder = find.ancestor(
Expand Down Expand Up @@ -73,10 +71,12 @@ void main() {
);

// Verify the background color is correctly applied.
final circleAvatarFinder = find.byType(CircleAvatar);
final circleAvatarWidget =
tester.widget<CircleAvatar>(circleAvatarFinder);
expect(circleAvatarWidget.backgroundColor, backgroundColor);
final containerFinder = find.byType(Container);
final containerWidget = tester.widget<Container>(containerFinder);
expect(
(containerWidget.decoration! as BoxDecoration).color,
backgroundColor,
);

// Verify the foreground color is correctly applied to the icon.
final iconThemeFinder = find.ancestor(
Expand Down Expand Up @@ -132,10 +132,12 @@ void main() {
);

// Verify the background color is from the theme's primaryContainer.
final circleAvatarFinder = find.byType(CircleAvatar);
final circleAvatarWidget =
tester.widget<CircleAvatar>(circleAvatarFinder);
expect(circleAvatarWidget.backgroundColor, Colors.blueGrey);
final containerFinder = find.byType(Container);
final containerWidget = tester.widget<Container>(containerFinder);
expect(
(containerWidget.decoration! as BoxDecoration).color,
Colors.blueGrey,
);

// Verify the foreground color is from the theme's primary.
final iconThemeFinder = find.byType(IconTheme);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ class VoicesAvatarExample extends StatelessWidget {
VoicesAvatar(
icon: VoicesAssets.icons.check.buildIcon(),
),
VoicesAvatar(
backgroundColor: Colors.transparent,
border: Border.all(
color: Theme.of(context).colorScheme.primary,
width: 2,
),
icon: VoicesAssets.icons.check.buildIcon(),
),
VoicesAvatar(
icon: const Text('A'),
onTap: () {},
Expand Down
Loading

0 comments on commit f529ab6

Please sign in to comment.