Skip to content

Conversation

@yjbanov
Copy link
Contributor

@yjbanov yjbanov commented Oct 15, 2017

Fixes #12548
Fixes #12550
See also #12537

This adds decoration property to TextStyles vended by Theme.of.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's too bad there's no way to force this test to be updated if any properties are added to TextStyle...

Copy link
Contributor

Choose a reason for hiding this comment

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

There is one way. Have a class in this file that "implements" TextStyle. The analyzer will flag this file whenever we add a member.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wow, this trick is so devious that I implemented it.

@tvolkert
Copy link
Contributor

LGTM, but I'd wait for @Hixie to confirm that this is the right way to go before merging.

@Hixie
Copy link
Contributor

Hixie commented Oct 16, 2017

I would prefer the output of Theme.of to be a ThemeData whose text styles are all inherit:false. That way, if we add anything else to TextStyle, we don't have to keep updating ThemeData.

@yjbanov
Copy link
Contributor Author

yjbanov commented Oct 17, 2017

I would prefer the output of Theme.of to be a ThemeData whose text styles are all inherit:false.

Done (see 6885e8a). I wonder, however, if people would want to get ThemeData from Theme.of, alter it a bit, then feed it back to a Theme widget. We currently expect that ThemeData supplied to Theme is inherit:true so we can localize it.

Test case:

var original = Theme.of(context);
return new Theme(
  // This will fail during localization.
  theme: original.copyWith(
    accentTextTheme: someOtherTextTheme,
  ),
  child: someWidget,
);

One way to solve this is to not localize text styles that are inherit:false. Then in the example above we will localize someOtherTextTheme (if it's inherit:true), but not others.

@Hixie
Copy link
Contributor

Hixie commented Oct 17, 2017

Discussion:

  • TextStyle.merge should return other if other.inherit is false (rather than asserting)
  • TextStyle should sprout a debugLabel (and have merge, lerp et al update it accordingly)
  • update docs everywhere to be the right way round for inherit wrt Typography, ThemeData, etc.

@yjbanov yjbanov force-pushed the add-missing-text-style-props branch from 6885e8a to dd85edf Compare October 20, 2017 00:16
@yjbanov
Copy link
Contributor Author

yjbanov commented Oct 20, 2017

039a61f and dd85edf change the other.inherit logic, update docs and add a debugLabel field to TextStyle.

@yjbanov
Copy link
Contributor Author

yjbanov commented Oct 20, 2017

PTAL

accentTextTheme ??= accentIsDark ? typography.white : typography.black;
textTheme ??= (isDark ? typography.white : typography.black).apply(decoration: TextDecoration.none);
primaryTextTheme ??= (primaryIsDark ? typography.white : typography.black).apply(decoration: TextDecoration.none);
accentTextTheme ??= (accentIsDark ? typography.white : typography.black).apply(decoration: TextDecoration.none);
Copy link
Contributor

Choose a reason for hiding this comment

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

how would you feel about either removing these additions (relying on the way we inherit from a base that doesn't have an underline) or hard-coding them into the constants? It seems weird to have these done in the middle-ground manner.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, now that the result of Theme.of no longer inherits from text styles, this property is not strictly necessary. However, I added the value to the Typography constants to be explicit that by default we do not have decorations rather than not having them as a side-effect of never setting them.

String package,
}) : fontFamily = package == null ? fontFamily : 'packages/$package/$fontFamily',
assert(inherit != null);
debugLabel = debugLabel == null ? _kDefaultDebugLabel : debugLabel,
Copy link
Contributor

Choose a reason for hiding this comment

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

debugLabel = debugLabel ?? _kDefaultDebugLabel

Or, if it doesn't interfere with other logic, just make it a default and assert non-null.

Copy link
Contributor

Choose a reason for hiding this comment

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

Alternatively, default to null, which will be more efficient in release builds and in comparisons against the default value, and only bringing _kDefaultDebugLabel when you need to merge strings (using debugLabel ?? _kDefaultDebugLabel)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Went with the last option: default to null, only bring in the default label when merging strings.

assert(inherit != null);
debugLabel = debugLabel == null ? _kDefaultDebugLabel : debugLabel,
assert(inherit != null),
assert(debugLabel == null || debugLabel.length <= 100);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd avoid the maximum length. It's likely that we'll accidentally exceed it at some point when creating a lerp of a lerp of a lerp or some crazy thing.

Copy link
Contributor

Choose a reason for hiding this comment

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

(...but need to see the whole length because it's meaningful in some way to what we're debugging, or something)

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess maybe you added this because in regular operation we generate 1000-long messages? I defer to your judgement on this. If we do generate ridiculous chains in normal operation, let me know, though. That seems surprising.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the cap. I was just paranoid. Easy to add later if we find a legitimate use-case for infinite chains of styles.

/// A human-readable description of this text style.
///
/// This property is not considered when comparing text styles using `==` or
/// [compareTo], and it does not affect [hashCode].
Copy link
Contributor

Choose a reason for hiding this comment

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

say something about it only being managed in debug builds.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

/// Creates a copy of this text style but with the numeric fields multiplied
/// by the given factors and then incremented by the given deltas.
static String _capDebugLabelLength(String label) {
const int maxLabelLength = 100;
Copy link
Contributor

Choose a reason for hiding this comment

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

i'd probably remove this entire function but if you do keep it:

  • use the same constant everywhere (here and in the assert above)
  • remove excessive braces

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Removed.

/// replaced by the non-null parameters of the given text style. If the given
/// text style is null, simply returns this text style.
/// Returns a new text style that is a combination of this style and the given
/// [other] style, following the following rules.
Copy link
Contributor

Choose a reason for hiding this comment

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

remove "following the following rules" because the first sentence needs to be able to stand alone.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

///
/// If the given [other] text style has its [TextStyle.inherit] set to true,
/// its null properties are replaced with the non-null properties of this text
/// style. It is said that the [other] style inherits properties of this
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd probably strike "It is said that", it's one of those phrases that when you really get down to it doesn't add anything meaningful to the docs (like my personal nemesis, "Note that...").

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, but the sentence still doesn't quite sound right. Here I am trying introduce our nouns and verbs around the "inherit" flag and "merge" method. When you "a.merge(b)" you can say "b inherits properties of a".

/// simply returns the given [other] style unchanged. It is said that the
/// [other] style does not inherit properties of this style.
///
/// If the given text style is null, simply returns this text style.
Copy link
Contributor

Choose a reason for hiding this comment

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

similarly with "simply". It just leads to people muttering "doesn't seem so simple to me" to themselves.

Copy link
Contributor

Choose a reason for hiding this comment

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

not that i ever mutter to myself when reading documentation. no sir.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. This was there already. I just reformatted the sentence.

void debugFillProperties(DiagnosticPropertiesBuilder properties, { String prefix: '' }) {
super.debugFillProperties(properties);
if (debugLabel != _kDefaultDebugLabel)
properties.add(new StringProperty('${prefix}debugLabel', debugLabel, defaultValue: null));
Copy link
Contributor

Choose a reason for hiding this comment

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

probably showName: false? Or maybe this is a MessageProperty? Check to see what @jacob314 did with the other debugLabels.

Copy link
Contributor

Choose a reason for hiding this comment

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

showName: false sounds reasonable. I don't see any other debugLabel properties added as diagnosticProperty. Generally, if you thing debugLabel does conceptually represent a property name, StringProperty is what you want. If debugLabel is just a debugging message you want to show than MessageProperty is what you want.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Switched to MessageProperty.

TextStyle cappedCopy = foo;
TextStyle cappedApply = foo;
TextStyle cappedLerp = foo;
for (int i = 0; i < 50; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

i += 1 (my preference) or ++i

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is gone now.

expect(TextStyle.lerp(foo, bar, 0.5).debugLabel, 'lerp(foo, bar)');
expect(TextStyle.lerp(foo.merge(bar), baz, 0.5).copyWith().debugLabel, 'copy of lerp(bar < foo, baz)');

expect(() => new TextStyle(debugLabel: 'a' * 300), throwsA(const isInstanceOf<AssertionError>()));
Copy link
Contributor

Choose a reason for hiding this comment

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

you can import flutter_test and use throwsAssertionError

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is gone now.

@Hixie
Copy link
Contributor

Hixie commented Oct 20, 2017

LGTM

@yjbanov yjbanov merged commit 67d16cd into flutter:master Oct 21, 2017
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 12, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Typography text styles aren't fully specified, yielding unexpected behavior Tooltip text underlined twice with yellow color

5 participants