-
Notifications
You must be signed in to change notification settings - Fork 214
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
app_bar [nfc]: Centralize _getEffectiveCenterTitle in our wrapper #1141
base: main
Are you sure you want to change the base?
app_bar [nfc]: Centralize _getEffectiveCenterTitle in our wrapper #1141
Conversation
lib/widgets/app_bar.dart
Outdated
ZulipAppBar({ | ||
super.key, | ||
super.titleSpacing, | ||
required super.title, | ||
required Widget? Function(bool Function(ThemeData) willCenterTitle) buildTitle, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a while to parse how this works. Maybe we can try to implement this as a widget? A concept would be like:
class _TitleBuilder extends StatelessWidget {
const _TitleBuilder({
required this.centerTitle,
required this.actionsCount,
required this.buildTitle,
});
final bool? centerTitle;
final int actionsCount;
final Widget Function(bool centerTitle) buildTitle;
// Copied from [AppBar._getEffectiveCenterTitle].
bool willCenterTitle(BuildContext context) {
final theme = Theme.of(context);
bool platformCenter() {
switch (theme.platform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
return false;
case TargetPlatform.iOS:
case TargetPlatform.macOS:
return actionsCount == 0 || actionsCount < 2;
}
}
return centerTitle
?? theme.appBarTheme.centerTitle
?? platformCenter();
}
@override
Widget build(BuildContext context) {
return buildTitle(willCenterTitle(context));
}
}
Letting buildTitle
take a bool
simplifies the API a bit and with a widget we can replace the callback constructed below with a method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh nice, this is great! Thanks for the idea.
Thanks for working on this! Left a comment on the proposed |
This is nice and explicit compared to the behavior I got when I simply forgot to call `testBinding.globalStore.add` when working on some upcoming tests.
This logic is sort of complicated, and duplicated from upstream. Better to put it centrally in our ZulipAppBar wrapper, instead of in message_list.dart. As a bonus, we also have it handle `actions` instead of assuming there are none.
8633634
to
c097bec
Compare
Thanks for the review! Revision pushed. I arranged it so it includes an exact copy of |
Note to self; I think there's a comment in the message-list code I've forgotten to remove in this revision: // The helper [_getEffectiveCenterTitle] relies on the fact that we
// have at most one action here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks to you both!
Some small comments below, and then a further adjustment to the API.
@@ -9,12 +9,29 @@ class TestZulipApp extends StatelessWidget { | |||
const TestZulipApp({ | |||
super.key, | |||
this.accountId, | |||
this.skipAssertAccountExists, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.skipAssertAccountExists, | |
this.skipAssertAccountExists = false, |
(and make the field non-nullable)
This is meant to treat null and false the same, right? So may as well make that more explicit by defaulting straight to false.
if (accountId != null && skipAssertAccountExists != true) { | ||
final account = GlobalStoreWidget.of(context).getAccount(accountId!); | ||
assert(account != null, | ||
'TestZulipApp() was called with [accountId] but a corresponding ' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: put these conditionals inside the assert (with an IIFE)
'TestZulipApp() was called with [accountId] but a corresponding ' | ||
'Account was not found in the GlobalStore. ' | ||
'If [child] needs per-account data, consider calling ' | ||
'`testBinding.globalStore.add` before pumping `TestZulipApp`. ' | ||
'If [child] is not specific to an account, omit [accountId]. ' | ||
'If you are testing behavior when an account is logged out, ' | ||
'consider building ZulipApp instead of TestZulipApp ' | ||
'or passing skipAssertAccountExists.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: for a long dev-facing error message like this, use FlutterError.fromParts
— grep our code for a few examples
/// based on [centerTitle], the theme, the platform, and [actions]. | ||
/// Useful if [title] is a container whose children should align the same way, | ||
/// such as a [Column] with multiple lines of text. | ||
// TODO send a PR upstream to replace our `willCenterTitle` code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
// TODO send a PR upstream to replace our `willCenterTitle` code | |
// TODO(upstream) send a PR to replace our `willCenterTitle` code |
I think the TODO(upstream)
form is helpful for grepping.
appBar: ZulipAppBar(title: Text(user.fullName)), | ||
appBar: ZulipAppBar(buildTitle: (_) => Text(user.fullName)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These diff hunks are kind of unfortunate, and I think an upstream PR for this would need to avoid them. Instead the new more-complex way of building a title should be opt-in.
ZulipAppBar({ | ||
super.key, | ||
super.titleSpacing, | ||
required super.title, | ||
required Widget Function(bool willCenterTitle) buildTitle, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
required Widget Function(bool willCenterTitle) buildTitle, | |
Widget? title, | |
Widget Function(bool willCenterTitle)? buildTitle, |
Then assert exactly one of those is non-null; and use that one. Much like hint
and hintText
etc. on upstream's InputDecoration
.
And make
TestZulipApp
more helpful, too, since I noticed an opportunity for that.