Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add ResponsiveChild. #342

Merged
merged 8 commits into from
Mar 26, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import 'package:catalyst_voices_shared/src/responsive_builder/responsive_breakpoint_key.dart';
import 'package:catalyst_voices_shared/src/responsive_builder/responsive_builder.dart';
import 'package:flutter/material.dart';

// A [ResponsiveChild] is a StatelessWidget that displays a Widget based on the
// current screen size.
// This is a simple wrapper around ResponsiveBuilder to simplify development and
// make it explicit for a reader.
//
// The possible arguments are [xs], [sm], [md], [lg], [other] following the
// the ResponsiveBuilder arguments.
// [other] is required and acts as fallback.
//
// Example usage:
//
// ```dart
// ResponsiveChild(
// xs: const Text('Simple text for extra small screens.'),
// sm: const Padding(
// padding: EdgeInsets.all(50),
// child: Text('Text with padding for small screens.'),
// ),
// md: const Column(
// children: [
// Text('This is'),
// Text('a set'),
// Text('of Texts'),
// Text('for medium screens.'),
// ],
// ),
// other: const Text('The fallback widget.'),
// );
// ```

class ResponsiveChild extends StatelessWidget {
final Map<ResponsiveBreakpointKey, Widget?> _widgets;

ResponsiveChild({
super.key,
Widget? xs,
minikin marked this conversation as resolved.
Show resolved Hide resolved
Widget? sm,
Widget? md,
Widget? lg,
required Widget other,
}) : _widgets = {
ResponsiveBreakpointKey.xs: xs,
ResponsiveBreakpointKey.sm: sm,
ResponsiveBreakpointKey.md: md,
ResponsiveBreakpointKey.lg: lg,
ResponsiveBreakpointKey.other: other,
};

@override
Widget build(BuildContext context) {
return ResponsiveBuilder<Widget>(
builder: (context, child) => child!,
xs: _widgets[ResponsiveBreakpointKey.xs],
sm: _widgets[ResponsiveBreakpointKey.sm],
md: _widgets[ResponsiveBreakpointKey.md],
lg: _widgets[ResponsiveBreakpointKey.lg],
other: _widgets[ResponsiveBreakpointKey.other]!,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import 'package:catalyst_voices_shared/src/responsive_child/responsive_child.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
Widget buildApp(Size size) => MediaQuery(
data: MediaQueryData(size: size),
child: MaterialApp(
home: Scaffold(
body: ResponsiveChild(
xs: const Text('Simple text for extra small screens.'),
sm: const Padding(
padding: EdgeInsets.all(50),
child: Text('Text with padding for small screens.'),
),
md: const Column(
children: [
Text('This is'),
Text('a set'),
Text('of Texts'),
Text('for medium screens.'),
],
),
other: const Text('The fallback widget.'),
),
),
),
);

group('Test screen sizes', () {
testWidgets(
'ResponsiveChild outputs a text for extra-small screens',
(tester) async {
await tester.pumpWidget(
buildApp(const Size.fromWidth(280)),
);
final testedElement = find.byType(Text);
expect(testedElement, findsOneWidget);
expect(
find.text('Simple text for extra small screens.'),
findsOneWidget,
);
}
);
testWidgets(
'ResponsiveChild outputs a text with padding for small screens',
(tester) async {
await tester.pumpWidget(
buildApp(const Size.fromWidth(620)),
);
final testedElement = find.byType(Text);
expect(testedElement, findsOneWidget);
expect(
find.text('Text with padding for small screens.'),
findsOneWidget,
);
final paddingWidget = tester.widget<Padding>(
find.ancestor(
of: testedElement,
matching: find.byType(Padding),
),
);
expect(paddingWidget.padding, const EdgeInsets.all(50));
}
);
testWidgets(
'ResponsiveChild outputs four texts for medium screens',
(tester) async {
await tester.pumpWidget(
buildApp(const Size.fromWidth(1280)),
);
final testedElements = find.byType(Text);
expect(testedElements, findsExactly(4));
expect(find.text('This is'), findsOneWidget);
expect(find.text('a set'), findsOneWidget);
expect(find.text('of Texts'), findsOneWidget);
expect(find.text('for medium screens.'), findsOneWidget);
}
);
testWidgets(
'ResponsiveChild fallback to other for large screens',
(tester) async {
await tester.pumpWidget(
buildApp(const Size.fromWidth(1600)),
);
final testedElements = find.byType(Text);
expect(testedElements, findsOneWidget);
expect(find.text('The fallback widget.'), findsOneWidget);
}
);
});
}
Loading