Skip to content

Commit cdf7dce

Browse files
authored
fix: count title towards word count(#7042) (#7127)
1 parent 552c592 commit cdf7dce

File tree

7 files changed

+155
-5
lines changed

7 files changed

+155
-5
lines changed

frontend/appflowy_flutter/integration_test/desktop/document/document_more_actions_test.dart

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1+
import 'package:appflowy/generated/locale_keys.g.dart';
12
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
3+
import 'package:appflowy/workspace/presentation/widgets/more_view_actions/widgets/view_meta_info.dart';
4+
import 'package:appflowy_editor/appflowy_editor.dart';
5+
import 'package:easy_localization/easy_localization.dart';
6+
import 'package:flowy_infra_ui/style_widget/text.dart';
7+
import 'package:flutter/services.dart';
28
import 'package:flutter_test/flutter_test.dart';
39
import 'package:integration_test/integration_test.dart';
410

@@ -31,4 +37,104 @@ void main() {
3137
expect(pageFinder, findsNWidgets(1));
3238
});
3339
});
40+
41+
testWidgets('count title towards word count', (tester) async {
42+
await tester.initializeAppFlowy();
43+
await tester.tapAnonymousSignInButton();
44+
await tester.createNewPageWithNameUnderParent();
45+
46+
Finder title = tester.editor.findDocumentTitle('');
47+
48+
await tester.openMoreViewActions();
49+
final viewMetaInfo = find.byType(ViewMetaInfo);
50+
expect(viewMetaInfo, findsOneWidget);
51+
52+
ViewMetaInfo viewMetaInfoWidget =
53+
viewMetaInfo.evaluate().first.widget as ViewMetaInfo;
54+
Counters titleCounter = viewMetaInfoWidget.titleCounters!;
55+
56+
expect(titleCounter.charCount, 0);
57+
expect(titleCounter.wordCount, 0);
58+
59+
/// input [str1] within title
60+
const str1 = 'Hello',
61+
str2 = '$str1 AppFlowy',
62+
str3 = '$str2!',
63+
str4 = 'Hello world';
64+
await tester.simulateKeyEvent(LogicalKeyboardKey.escape);
65+
await tester.tapButton(title);
66+
await tester.enterText(title, str1);
67+
await tester.pumpAndSettle(const Duration(seconds: 1));
68+
await tester.openMoreViewActions();
69+
viewMetaInfoWidget = viewMetaInfo.evaluate().first.widget as ViewMetaInfo;
70+
titleCounter = viewMetaInfoWidget.titleCounters!;
71+
expect(titleCounter.charCount, str1.length);
72+
expect(titleCounter.wordCount, 1);
73+
74+
/// input [str2] within title
75+
title = tester.editor.findDocumentTitle(str1);
76+
await tester.simulateKeyEvent(LogicalKeyboardKey.escape);
77+
await tester.tapButton(title);
78+
await tester.enterText(title, str2);
79+
await tester.pumpAndSettle(const Duration(seconds: 1));
80+
await tester.openMoreViewActions();
81+
viewMetaInfoWidget = viewMetaInfo.evaluate().first.widget as ViewMetaInfo;
82+
titleCounter = viewMetaInfoWidget.titleCounters!;
83+
expect(titleCounter.charCount, str2.length);
84+
expect(titleCounter.wordCount, 2);
85+
86+
/// input [str3] within title
87+
title = tester.editor.findDocumentTitle(str2);
88+
await tester.simulateKeyEvent(LogicalKeyboardKey.escape);
89+
await tester.tapButton(title);
90+
await tester.enterText(title, str3);
91+
await tester.pumpAndSettle(const Duration(seconds: 1));
92+
await tester.openMoreViewActions();
93+
viewMetaInfoWidget = viewMetaInfo.evaluate().first.widget as ViewMetaInfo;
94+
titleCounter = viewMetaInfoWidget.titleCounters!;
95+
expect(titleCounter.charCount, str3.length);
96+
expect(titleCounter.wordCount, 2);
97+
98+
/// input [str4] within document
99+
await tester.simulateKeyEvent(LogicalKeyboardKey.escape);
100+
await tester.editor
101+
.updateSelection(Selection.collapsed(Position(path: [0])));
102+
await tester.pumpAndSettle();
103+
await tester.editor
104+
.getCurrentEditorState()
105+
.insertTextAtCurrentSelection(str4);
106+
await tester.pumpAndSettle(const Duration(seconds: 1));
107+
await tester.openMoreViewActions();
108+
final texts =
109+
find.descendant(of: viewMetaInfo, matching: find.byType(FlowyText));
110+
expect(texts, findsNWidgets(3));
111+
viewMetaInfoWidget = viewMetaInfo.evaluate().first.widget as ViewMetaInfo;
112+
titleCounter = viewMetaInfoWidget.titleCounters!;
113+
final Counters documentCounters = viewMetaInfoWidget.documentCounters!;
114+
final wordCounter = texts.evaluate().elementAt(0).widget as FlowyText,
115+
charCounter = texts.evaluate().elementAt(1).widget as FlowyText;
116+
final numberFormat = NumberFormat();
117+
expect(
118+
wordCounter.text,
119+
LocaleKeys.moreAction_wordCount.tr(
120+
args: [
121+
numberFormat
122+
.format(titleCounter.wordCount + documentCounters.wordCount)
123+
.toString(),
124+
],
125+
),
126+
);
127+
expect(
128+
charCounter.text,
129+
LocaleKeys.moreAction_charCount.tr(
130+
args: [
131+
numberFormat
132+
.format(
133+
titleCounter.charCount + documentCounters.charCount,
134+
)
135+
.toString(),
136+
],
137+
),
138+
);
139+
});
34140
}

frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/cover_title.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:appflowy/plugins/document/presentation/editor_style.dart';
55
import 'package:appflowy/shared/text_field/text_filed_with_metric_lines.dart';
66
import 'package:appflowy/workspace/application/appearance_defaults.dart';
77
import 'package:appflowy/workspace/application/view/view_bloc.dart';
8+
import 'package:appflowy/workspace/application/view_info/view_info_bloc.dart';
89
import 'package:appflowy_backend/log.dart';
910
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
1011
import 'package:appflowy_editor/appflowy_editor.dart';
@@ -220,6 +221,9 @@ class _InnerCoverTitleState extends State<_InnerCoverTitle> {
220221
.read<ViewBloc>()
221222
.add(ViewEvent.rename(titleTextController.text));
222223
}
224+
context
225+
.read<ViewInfoBloc?>()
226+
?.add(ViewInfoEvent.titleChanged(titleTextController.text));
223227
},
224228
);
225229
}

frontend/appflowy_flutter/lib/shared/patterns/common_patterns.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,6 @@ final numberedListRegex = RegExp(_numberedListPattern);
4545

4646
const _localPathPattern = r'^(file:\/\/|\/|\\|[a-zA-Z]:[/\\]|\.{1,2}[/\\])';
4747
final localPathRegex = RegExp(_localPathPattern, caseSensitive: false);
48+
49+
const _wordPattern = r"\S+";
50+
final wordRegex = RegExp(_wordPattern);

frontend/appflowy_flutter/lib/util/string_extension.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,11 @@ extension IconExtension on String {
8484
)..iconGroup = iconGroup;
8585
}
8686
}
87+
88+
extension CounterExtension on String {
89+
Counters getCounter() {
90+
final wordCount = wordRegex.allMatches(this).length;
91+
final charCount = runes.length;
92+
return Counters(wordCount: wordCount, charCount: charCount);
93+
}
94+
}

frontend/appflowy_flutter/lib/workspace/application/view_info/view_info_bloc.dart

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:appflowy/util/int64_extension.dart';
2+
import 'package:appflowy/util/string_extension.dart';
23
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
34
import 'package:appflowy_editor/appflowy_editor.dart';
45
import 'package:bloc/bloc.dart';
@@ -11,7 +12,12 @@ class ViewInfoBloc extends Bloc<ViewInfoEvent, ViewInfoState> {
1112
on<ViewInfoEvent>((event, emit) {
1213
event.when(
1314
started: () {
14-
emit(state.copyWith(createdAt: view.createTime.toDateTime()));
15+
emit(
16+
state.copyWith(
17+
createdAt: view.createTime.toDateTime(),
18+
titleCounters: view.name.getCounter(),
19+
),
20+
);
1521
},
1622
unregisterEditorState: () {
1723
_clearWordCountService();
@@ -36,6 +42,13 @@ class ViewInfoBloc extends Bloc<ViewInfoEvent, ViewInfoState> {
3642
),
3743
);
3844
},
45+
titleChanged: (s) {
46+
emit(
47+
state.copyWith(
48+
titleCounters: s.getCounter(),
49+
),
50+
);
51+
},
3952
);
4053
});
4154
}
@@ -71,17 +84,21 @@ class ViewInfoEvent with _$ViewInfoEvent {
7184
}) = _RegisterEditorState;
7285

7386
const factory ViewInfoEvent.wordCountChanged() = _WordCountChanged;
87+
88+
const factory ViewInfoEvent.titleChanged(String title) = _TitleChanged;
7489
}
7590

7691
@freezed
7792
class ViewInfoState with _$ViewInfoState {
7893
const factory ViewInfoState({
7994
required Counters? documentCounters,
95+
required Counters? titleCounters,
8096
required DateTime? createdAt,
8197
}) = _ViewInfoState;
8298

8399
factory ViewInfoState.initial() => const ViewInfoState(
84100
documentCounters: null,
101+
titleCounters: null,
85102
createdAt: null,
86103
);
87104
}

frontend/appflowy_flutter/lib/workspace/presentation/widgets/more_view_actions/more_view_actions.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class _MoreViewActionsState extends State<MoreViewActions> {
129129
dateFormat: dateFormat,
130130
timeFormat: timeFormat,
131131
documentCounters: state.documentCounters,
132+
titleCounters: state.titleCounters,
132133
createdAt: state.createdAt,
133134
),
134135
const VSpace(4.0),

frontend/appflowy_flutter/lib/workspace/presentation/widgets/more_view_actions/widgets/view_meta_info.dart

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ class ViewMetaInfo extends StatelessWidget {
1313
required this.dateFormat,
1414
required this.timeFormat,
1515
this.documentCounters,
16+
this.titleCounters,
1617
this.createdAt,
1718
});
1819

1920
final UserDateFormatPB dateFormat;
2021
final UserTimeFormatPB timeFormat;
2122
final Counters? documentCounters;
23+
final Counters? titleCounters;
2224
final DateTime? createdAt;
2325

2426
@override
@@ -31,11 +33,15 @@ class ViewMetaInfo extends StatelessWidget {
3133
child: Column(
3234
crossAxisAlignment: CrossAxisAlignment.start,
3335
children: [
34-
if (documentCounters != null) ...[
36+
if (documentCounters != null && titleCounters != null) ...[
3537
FlowyText.regular(
3638
LocaleKeys.moreAction_wordCount.tr(
3739
args: [
38-
numberFormat.format(documentCounters!.wordCount).toString(),
40+
numberFormat
41+
.format(
42+
documentCounters!.wordCount + titleCounters!.wordCount,
43+
)
44+
.toString(),
3945
],
4046
),
4147
fontSize: 12,
@@ -45,15 +51,20 @@ class ViewMetaInfo extends StatelessWidget {
4551
FlowyText.regular(
4652
LocaleKeys.moreAction_charCount.tr(
4753
args: [
48-
numberFormat.format(documentCounters!.charCount).toString(),
54+
numberFormat
55+
.format(
56+
documentCounters!.charCount + titleCounters!.charCount,
57+
)
58+
.toString(),
4959
],
5060
),
5161
fontSize: 12,
5262
color: Theme.of(context).hintColor,
5363
),
5464
],
5565
if (createdAt != null) ...[
56-
if (documentCounters != null) const VSpace(2),
66+
if (documentCounters != null && titleCounters != null)
67+
const VSpace(2),
5768
FlowyText.regular(
5869
LocaleKeys.moreAction_createdAt.tr(
5970
args: [dateFormat.formatDate(createdAt!, true, timeFormat)],

0 commit comments

Comments
 (0)