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

app_bar [nfc]: Centralize _getEffectiveCenterTitle in our wrapper #1141

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

chrisbobbe
Copy link
Collaborator

And make TestZulipApp more helpful, too, since I noticed an opportunity for that.

ZulipAppBar({
super.key,
super.titleSpacing,
required super.title,
required Widget? Function(bool Function(ThemeData) willCenterTitle) buildTitle,
Copy link
Member

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.

Copy link
Collaborator Author

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.

@PIG208
Copy link
Member

PIG208 commented Dec 12, 2024

Thanks for working on this! Left a comment on the proposed buildTitle API. Otherwise this looks good to me.

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.
@chrisbobbe chrisbobbe force-pushed the pr-centralize-will-center-app-bar-title branch from 8633634 to c097bec Compare December 12, 2024 23:22
@chrisbobbe
Copy link
Collaborator Author

chrisbobbe commented Dec 12, 2024

Thanks for the review! Revision pushed. I arranged it so it includes an exact copy of AppBar._getEffectiveCenterTitle, to make it as easy as possible to verify that it behaves the same.

@PIG208 PIG208 assigned gnprice and unassigned PIG208 Dec 13, 2024
@PIG208 PIG208 requested a review from gnprice December 13, 2024 00:33
@PIG208 PIG208 added the integration review Added by maintainers when PR may be ready for integration label Dec 13, 2024
@chrisbobbe
Copy link
Collaborator Author

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.

Copy link
Member

@gnprice gnprice left a 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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Comment on lines +48 to +51
if (accountId != null && skipAssertAccountExists != true) {
final account = GlobalStoreWidget.of(context).getAccount(accountId!);
assert(account != null,
'TestZulipApp() was called with [accountId] but a corresponding '
Copy link
Member

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)

Comment on lines +51 to +58
'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.');
Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
// 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)),
Copy link
Member

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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration review Added by maintainers when PR may be ready for integration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants