Skip to content

Commit ec6715b

Browse files
committed
button: Implement the "icon button" component in the Figma
1 parent 1cdaee1 commit ec6715b

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

lib/widgets/button.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,45 @@ enum ZulipWebUiKitButtonSize {
213213
normal,
214214
}
215215

216+
/// The "icon button" component in the Figma.
217+
///
218+
/// See Figma:
219+
/// https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=7728-10468&m=dev
220+
class ZulipIconButton extends StatelessWidget {
221+
const ZulipIconButton({
222+
super.key,
223+
required this.icon,
224+
required this.onPressed,
225+
});
226+
227+
final IconData icon;
228+
final VoidCallback onPressed;
229+
230+
@override
231+
Widget build(BuildContext context) {
232+
final designVariables = DesignVariables.of(context);
233+
234+
// Really `fg-05` from the Zulip Web UI Kit palette,
235+
// but this seems at least as good as that.
236+
final touchFeedbackColor = designVariables.foreground.withFadedAlpha(0.05);
237+
238+
return IconButton(
239+
color: designVariables.icon,
240+
iconSize: 24,
241+
icon: Icon(icon),
242+
onPressed: onPressed,
243+
style: IconButton.styleFrom(
244+
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
245+
fixedSize: Size.square(40),
246+
247+
// TODO(#417): Disable splash effects for all buttons globally.
248+
splashFactory: NoSplash.splashFactory,
249+
highlightColor: touchFeedbackColor,
250+
shape: const RoundedRectangleBorder(
251+
borderRadius: BorderRadius.all(Radius.circular(4)))));
252+
}
253+
}
254+
216255
/// Apply [Transform.scale] to the child widget when tapped, and reset its scale
217256
/// when released, while animating the transitions.
218257
class AnimatedScaleOnTap extends StatefulWidget {

test/widgets/button_test.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:flutter_test/flutter_test.dart';
55
import 'package:flutter/material.dart';
66
import 'package:legacy_checks/legacy_checks.dart';
77
import 'package:zulip/widgets/button.dart';
8+
import 'package:zulip/widgets/icons.dart';
89

910
import '../flutter_checks.dart';
1011
import '../model/binding.dart';
@@ -96,4 +97,23 @@ void main() {
9697
testVerticalOuterPadding(sizeVariant: ZulipWebUiKitButtonSize.small);
9798
testVerticalOuterPadding(sizeVariant: ZulipWebUiKitButtonSize.normal);
9899
});
100+
101+
group('ZulipIconButton', () {
102+
testWidgets('occupies a 40px square', (tester) async {
103+
addTearDown(testBinding.reset);
104+
105+
await tester.pumpWidget(TestZulipApp(
106+
child: UnconstrainedBox(
107+
child: ZulipIconButton(
108+
icon: ZulipIcons.follow,
109+
onPressed: () {}))));
110+
await tester.pump();
111+
112+
final element = tester.element(find.byType(ZulipIconButton));
113+
final renderObject = element.renderObject as RenderBox;
114+
check(renderObject).size.equals(Size.square(40));
115+
});
116+
117+
// TODO test that the touch feedback fills the whole square
118+
});
99119
}

0 commit comments

Comments
 (0)