Skip to content

Commit 8669c4a

Browse files
chrisbobbegnprice
authored andcommitted
content [nfc]: Put plain-paragraph text style in a ThemeExtension
See dartdoc for rationale.
1 parent 7ef745f commit 8669c4a

File tree

8 files changed

+77
-17
lines changed

8 files changed

+77
-17
lines changed

lib/widgets/content.dart

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,67 @@ import 'message_list.dart';
2020
import 'store.dart';
2121
import 'text.dart';
2222

23+
/// A central place for styles for Zulip content (rendered Zulip Markdown).
24+
///
25+
/// These styles will animate on theme changes (with help from [lerp]),
26+
/// so styles that differ between light and dark theme belong here.
27+
///
28+
/// Styles also belong here if we want to centralize computing them,
29+
/// for performance. (The message list is particularly performance-sensitive.)
30+
///
31+
/// Content elements are assumed to be painted on a theme-appropriate
32+
/// background. For what this is in the message list, see
33+
/// widgets/message_list.dart.
34+
class ContentTheme extends ThemeExtension<ContentTheme> {
35+
ContentTheme() :
36+
textStylePlainParagraph = TextStyle(
37+
color: const HSLColor.fromAHSL(1, 0, 0, 0.15).toColor(),
38+
fontSize: kBaseFontSize,
39+
height: (22 / kBaseFontSize),
40+
);
41+
42+
ContentTheme._({
43+
required this.textStylePlainParagraph,
44+
});
45+
46+
/// The [ContentTheme] from the context's active theme.
47+
///
48+
/// The [ThemeData] must include [ContentTheme] in [ThemeData.extensions].
49+
static ContentTheme of(BuildContext context) {
50+
final theme = Theme.of(context);
51+
final extension = theme.extension<ContentTheme>();
52+
assert(extension != null);
53+
return extension!;
54+
}
55+
56+
/// The [TextStyle] we use for plain, unstyled paragraphs.
57+
///
58+
/// Also the base style that all other text content should inherit from.
59+
final TextStyle textStylePlainParagraph;
60+
61+
@override
62+
ContentTheme copyWith({
63+
TextStyle? textStylePlainParagraph,
64+
}) {
65+
return ContentTheme._(
66+
textStylePlainParagraph: textStylePlainParagraph ?? this.textStylePlainParagraph,
67+
);
68+
}
69+
70+
@override
71+
ContentTheme lerp(ContentTheme? other, double t) {
72+
if (identical(this, other)) {
73+
return this;
74+
}
75+
return ContentTheme._(
76+
textStylePlainParagraph: TextStyle.lerp(textStylePlainParagraph, other?.textStylePlainParagraph, t)!,
77+
);
78+
}
79+
}
80+
2381
/// The font size for message content in a plain unstyled paragraph.
2482
const double kBaseFontSize = 17;
2583

26-
/// The [TextStyle] we use for plain, unstyled paragraphs.
27-
///
28-
/// Also the base style that all other text content should inherit from.
29-
final plainParagraphContentTextStyle = TextStyle(
30-
color: const HSLColor.fromAHSL(1, 0, 0, 0.15).toColor(),
31-
fontSize: kBaseFontSize,
32-
height: (22 / kBaseFontSize),
33-
);
34-
3584
/// The entire content of a message, aka its body.
3685
///
3786
/// This does not include metadata like the sender's name and avatar, the time,
@@ -46,7 +95,7 @@ class MessageContent extends StatelessWidget {
4695
Widget build(BuildContext context) {
4796
return InheritedMessage(message: message,
4897
child: DefaultTextStyle.merge(
49-
style: plainParagraphContentTextStyle,
98+
style: ContentTheme.of(context).textStylePlainParagraph,
5099
child: BlockContentList(nodes: content.nodes)));
51100
}
52101
}

lib/widgets/profile.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ class _LinkWidget extends StatelessWidget {
218218
Widget build(BuildContext context) {
219219
final linkNode = LinkNode(url: url, nodes: [TextNode(text)]);
220220
final paragraph = DefaultTextStyle.merge(
221-
style: plainParagraphContentTextStyle,
221+
style: ContentTheme.of(context).textStylePlainParagraph,
222222
child: Paragraph(node: ParagraphNode(nodes: [linkNode], links: [linkNode])));
223223
return Padding(
224224
padding: const EdgeInsets.symmetric(horizontal: 8),

lib/widgets/theme.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import 'package:flutter/material.dart';
22

3+
import 'content.dart';
34
import 'text.dart';
45

56
ThemeData zulipThemeData(BuildContext context) {
67
return ThemeData(
78
typography: zulipTypography(context),
9+
extensions: [ContentTheme()],
810
appBarTheme: const AppBarTheme(
911
// Set these two fields to prevent a color change in [AppBar]s when
1012
// there is something scrolled under it. If an app bar hasn't been

test/widgets/action_sheet_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Future<void> setupToMessageActionSheet(WidgetTester tester, {
5959

6060
await tester.pumpWidget(
6161
MaterialApp(
62+
theme: ThemeData(extensions: [ContentTheme()]),
6263
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
6364
supportedLocales: ZulipLocalizations.supportedLocales,
6465
home: GlobalStoreWidget(

test/widgets/autocomplete_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:zulip/api/route/messages.dart';
77
import 'package:zulip/model/compose.dart';
88
import 'package:zulip/model/narrow.dart';
99
import 'package:zulip/model/store.dart';
10+
import 'package:zulip/widgets/content.dart';
1011
import 'package:zulip/widgets/message_list.dart';
1112
import 'package:zulip/widgets/store.dart';
1213

@@ -50,6 +51,7 @@ Future<Finder> setupToComposeInput(WidgetTester tester, {
5051

5152
await tester.pumpWidget(
5253
MaterialApp(
54+
theme: ThemeData(extensions: [ContentTheme()]),
5355
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
5456
supportedLocales: ZulipLocalizations.supportedLocales,
5557
home: GlobalStoreWidget(

test/widgets/content_test.dart

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,10 @@ void main() {
9393
TestZulipBinding.ensureInitialized();
9494

9595
Widget plainContent(String html) {
96-
return DefaultTextStyle.merge(
97-
style: plainParagraphContentTextStyle,
98-
child: BlockContentList(nodes: parseContent(html).nodes));
96+
return Builder(builder: (context) =>
97+
DefaultTextStyle.merge(
98+
style: ContentTheme.of(context).textStylePlainParagraph,
99+
child: BlockContentList(nodes: parseContent(html).nodes)));
99100
}
100101

101102
Widget messageContent(String html) {
@@ -125,7 +126,10 @@ void main() {
125126
await tester.pumpWidget(
126127
Builder(builder: (context) =>
127128
MaterialApp(
128-
theme: ThemeData(typography: zulipTypography(context)),
129+
theme: ThemeData(
130+
typography: zulipTypography(context),
131+
extensions: [ContentTheme()],
132+
),
129133
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
130134
supportedLocales: ZulipLocalizations.supportedLocales,
131135
navigatorObservers: navObservers,
@@ -540,7 +544,7 @@ void main() {
540544
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
541545

542546
testWidgets('multiple links in paragraph', (tester) async {
543-
final fontSize = plainParagraphContentTextStyle.fontSize!;
547+
const fontSize = kBaseFontSize;
544548

545549
await prepare(tester,
546550
'<p><a href="https://a/">foo</a> bar <a href="https://b/">baz</a></p>');
@@ -568,7 +572,7 @@ void main() {
568572
});
569573

570574
testWidgets('link containing other spans', (tester) async {
571-
final fontSize = plainParagraphContentTextStyle.fontSize!;
575+
const fontSize = kBaseFontSize;
572576

573577
await prepare(tester,
574578
'<p><a href="https://a/">two <strong><em><code>words</code></em></strong></a></p>');

test/widgets/message_list_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ void main() {
6868

6969
await tester.pumpWidget(
7070
MaterialApp(
71+
theme: ThemeData(extensions: [ContentTheme()]),
7172
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
7273
supportedLocales: ZulipLocalizations.supportedLocales,
7374
home: GlobalStoreWidget(

test/widgets/profile_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Future<void> setupPage(WidgetTester tester, {
4343
await tester.pumpWidget(
4444
GlobalStoreWidget(
4545
child: MaterialApp(
46+
theme: ThemeData(extensions: [ContentTheme()]),
4647
navigatorObservers: navigatorObserver != null ? [navigatorObserver] : [],
4748
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
4849
supportedLocales: ZulipLocalizations.supportedLocales,

0 commit comments

Comments
 (0)