Skip to content

Commit 6b2ef9c

Browse files
committed
compose: Introduce PerAccountStore in ComposeController
This way, subclasses can use the reference to the store for different purposes, such as using `max_topic_length` for the topic length instead of the hard-coded limit of 60, or using `max_stream_name_length` for how far back from the cursor we look to find a channel-link autocomplete interaction in compose box.
1 parent 7f03226 commit 6b2ef9c

File tree

4 files changed

+37
-19
lines changed

4 files changed

+37
-19
lines changed

lib/widgets/compose_box.dart

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ const double _composeButtonSize = 44;
8989
///
9090
/// Subclasses must ensure that [_update] is called in all exposed constructors.
9191
abstract class ComposeController<ErrorT> extends TextEditingController {
92-
ComposeController({super.text});
92+
ComposeController({super.text, required this.store});
93+
94+
PerAccountStore store;
9395

9496
int get maxLengthUnicodeCodePoints;
9597

@@ -152,12 +154,10 @@ enum TopicValidationError {
152154
}
153155

154156
class ComposeTopicController extends ComposeController<TopicValidationError> {
155-
ComposeTopicController({super.text, required this.store}) {
157+
ComposeTopicController({super.text, required super.store}) {
156158
_update();
157159
}
158160

159-
PerAccountStore store;
160-
161161
// TODO(#668): listen to [PerAccountStore] once we subscribe to this value
162162
bool get mandatory => store.realmMandatoryTopics;
163163

@@ -234,7 +234,11 @@ enum ContentValidationError {
234234
}
235235

236236
class ComposeContentController extends ComposeController<ContentValidationError> {
237-
ComposeContentController({super.text, this.requireNotEmpty = true}) {
237+
ComposeContentController({
238+
super.text,
239+
required super.store,
240+
this.requireNotEmpty = true,
241+
}) {
238242
_update();
239243
}
240244

@@ -1575,7 +1579,10 @@ class _EditMessageComposeBoxBody extends _ComposeBoxBody {
15751579
}
15761580

15771581
sealed class ComposeBoxController {
1578-
final content = ComposeContentController();
1582+
ComposeBoxController({required PerAccountStore store})
1583+
: content = ComposeContentController(store: store);
1584+
1585+
final ComposeContentController content;
15791586
final contentFocusNode = FocusNode();
15801587

15811588
/// If no input is focused, requests focus on the appropriate input.
@@ -1668,7 +1675,7 @@ enum ComposeTopicInteractionStatus {
16681675
}
16691676

16701677
class StreamComposeBoxController extends ComposeBoxController {
1671-
StreamComposeBoxController({required PerAccountStore store})
1678+
StreamComposeBoxController({required super.store})
16721679
: topic = ComposeTopicController(store: store);
16731680

16741681
final ComposeTopicController topic;
@@ -1698,21 +1705,25 @@ class StreamComposeBoxController extends ComposeBoxController {
16981705
}
16991706
}
17001707

1701-
class FixedDestinationComposeBoxController extends ComposeBoxController {}
1708+
class FixedDestinationComposeBoxController extends ComposeBoxController {
1709+
FixedDestinationComposeBoxController({required super.store});
1710+
}
17021711

17031712
class EditMessageComposeBoxController extends ComposeBoxController {
17041713
EditMessageComposeBoxController({
1714+
required super.store,
17051715
required this.messageId,
17061716
required this.originalRawContent,
17071717
required String? initialText,
17081718
}) : _content = ComposeContentController(
17091719
text: initialText,
1720+
store: store,
17101721
// Editing to delete the content is a supported form of
17111722
// deletion: https://zulip.com/help/delete-a-message#delete-message-content
17121723
requireNotEmpty: false);
17131724

1714-
factory EditMessageComposeBoxController.empty(int messageId) =>
1715-
EditMessageComposeBoxController(messageId: messageId,
1725+
factory EditMessageComposeBoxController.empty(PerAccountStore store, int messageId) =>
1726+
EditMessageComposeBoxController(store: store, messageId: messageId,
17161727
originalRawContent: null, initialText: null);
17171728

17181729
@override ComposeContentController get content => _content;
@@ -2058,6 +2069,7 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
20582069
setState(() {
20592070
controller.dispose();
20602071
_controller = EditMessageComposeBoxController(
2072+
store: store,
20612073
messageId: messageId,
20622074
originalRawContent: failedEdit.originalRawContent,
20632075
initialText: failedEdit.newContent,
@@ -2067,8 +2079,9 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
20672079
}
20682080

20692081
void _editFromRawContentFetch(int messageId) async {
2082+
final store = PerAccountStoreWidget.of(context);
20702083
final zulipLocalizations = ZulipLocalizations.of(context);
2071-
final emptyEditController = EditMessageComposeBoxController.empty(messageId);
2084+
final emptyEditController = EditMessageComposeBoxController.empty(store, messageId);
20722085
setState(() {
20732086
controller.dispose();
20742087
_controller = emptyEditController;
@@ -2134,10 +2147,11 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
21342147

21352148
switch (controller) {
21362149
case StreamComposeBoxController():
2150+
controller.content.store = newStore;
21372151
controller.topic.store = newStore;
21382152
case FixedDestinationComposeBoxController():
21392153
case EditMessageComposeBoxController():
2140-
// no reference to the store that needs updating
2154+
controller.content.store = newStore;
21412155
}
21422156
}
21432157

@@ -2148,7 +2162,7 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
21482162
_controller = StreamComposeBoxController(store: store);
21492163
case TopicNarrow():
21502164
case DmNarrow():
2151-
_controller = FixedDestinationComposeBoxController();
2165+
_controller = FixedDestinationComposeBoxController(store: store);
21522166
case CombinedFeedNarrow():
21532167
case MentionsNarrow():
21542168
case StarredMessagesNarrow():

test/model/autocomplete_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ void main() {
8282
? 'in ${jsonEncode(markedText)}, query ${jsonEncode(expectedQuery.raw)}'
8383
: 'no query in ${jsonEncode(markedText)}';
8484
test(description, () {
85-
final controller = ComposeContentController();
85+
final store = eg.store();
86+
final controller = ComposeContentController(store: store);
8687
final parsed = parseMarkedText(markedText);
8788
assert((expectedQuery == null) == (parsed.expectedSyntaxStart == null));
8889
controller.value = parsed.value;

test/widgets/action_sheet_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,7 +1651,7 @@ void main() {
16511651
required TextEditingValue valueBefore,
16521652
required Message message,
16531653
}) {
1654-
check(contentController).value.equals((ComposeContentController()
1654+
check(contentController).value.equals((ComposeContentController(store: store)
16551655
..value = valueBefore
16561656
..insertPadded(quoteAndReplyPlaceholder(
16571657
GlobalLocalizations.zulipLocalizations, store, message: message))
@@ -1664,7 +1664,7 @@ void main() {
16641664
required Message message,
16651665
required String rawContent,
16661666
}) {
1667-
final builder = ComposeContentController()
1667+
final builder = ComposeContentController(store: store)
16681668
..value = valueBefore
16691669
..insertPadded(quoteAndReply(store, message: message, rawContent: rawContent));
16701670
if (!valueBefore.selection.isValid) {

test/widgets/compose_box_test.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ void main() {
255255
/// In expectedValue, represent the collapsed selection as "^".
256256
void testInsertPadded(String description, String valueBefore, String textToInsert, String expectedValue) {
257257
test(description, () {
258-
final controller = ComposeContentController();
258+
store = eg.store();
259+
final controller = ComposeContentController(store: store);
259260
controller.value = parseMarkedText(valueBefore);
260261
controller.insertPadded(textToInsert);
261262
check(controller.value).equals(parseMarkedText(expectedValue));
@@ -336,15 +337,17 @@ void main() {
336337
}
337338

338339
testWidgets('requireNotEmpty: true (default)', (tester) async {
339-
controller = ComposeContentController();
340+
store = eg.store();
341+
controller = ComposeContentController(store: store);
340342
addTearDown(controller.dispose);
341343
checkCountsAsEmpty('', true);
342344
checkCountsAsEmpty(' ', true);
343345
checkCountsAsEmpty('a', false);
344346
});
345347

346348
testWidgets('requireNotEmpty: false', (tester) async {
347-
controller = ComposeContentController(requireNotEmpty: false);
349+
store = eg.store();
350+
controller = ComposeContentController(store: store, requireNotEmpty: false);
348351
addTearDown(controller.dispose);
349352
checkCountsAsEmpty('', false);
350353
checkCountsAsEmpty(' ', false);

0 commit comments

Comments
 (0)