Skip to content

Commit 6593a7e

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 88960f2 commit 6593a7e

File tree

4 files changed

+38
-19
lines changed

4 files changed

+38
-19
lines changed

lib/widgets/compose_box.dart

Lines changed: 28 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

@@ -235,7 +235,11 @@ enum ContentValidationError {
235235
}
236236

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

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

15771581
sealed class ComposeBoxController {
1578-
final content = ComposeContentController();
1582+
ComposeBoxController({required this.store})
1583+
: content = ComposeContentController(store: store);
1584+
1585+
final PerAccountStore store;
1586+
final ComposeContentController content;
15791587
final contentFocusNode = FocusNode();
15801588

15811589
/// If no input is focused, requests focus on the appropriate input.
@@ -1668,7 +1676,7 @@ enum ComposeTopicInteractionStatus {
16681676
}
16691677

16701678
class StreamComposeBoxController extends ComposeBoxController {
1671-
StreamComposeBoxController({required PerAccountStore store})
1679+
StreamComposeBoxController({required super.store})
16721680
: topic = ComposeTopicController(store: store);
16731681

16741682
final ComposeTopicController topic;
@@ -1698,21 +1706,25 @@ class StreamComposeBoxController extends ComposeBoxController {
16981706
}
16991707
}
17001708

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

17031713
class EditMessageComposeBoxController extends ComposeBoxController {
17041714
EditMessageComposeBoxController({
1715+
required super.store,
17051716
required this.messageId,
17061717
required this.originalRawContent,
17071718
required String? initialText,
17081719
}) : _content = ComposeContentController(
17091720
text: initialText,
1721+
store: store,
17101722
// Editing to delete the content is a supported form of
17111723
// deletion: https://zulip.com/help/delete-a-message#delete-message-content
17121724
requireNotEmpty: false);
17131725

1714-
factory EditMessageComposeBoxController.empty(int messageId) =>
1715-
EditMessageComposeBoxController(messageId: messageId,
1726+
factory EditMessageComposeBoxController.empty(PerAccountStore store, int messageId) =>
1727+
EditMessageComposeBoxController(store: store, messageId: messageId,
17161728
originalRawContent: null, initialText: null);
17171729

17181730
@override ComposeContentController get content => _content;
@@ -2058,6 +2070,7 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
20582070
setState(() {
20592071
controller.dispose();
20602072
_controller = EditMessageComposeBoxController(
2073+
store: store,
20612074
messageId: messageId,
20622075
originalRawContent: failedEdit.originalRawContent,
20632076
initialText: failedEdit.newContent,
@@ -2067,8 +2080,9 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
20672080
}
20682081

20692082
void _editFromRawContentFetch(int messageId) async {
2083+
final store = PerAccountStoreWidget.of(context);
20702084
final zulipLocalizations = ZulipLocalizations.of(context);
2071-
final emptyEditController = EditMessageComposeBoxController.empty(messageId);
2085+
final emptyEditController = EditMessageComposeBoxController.empty(store, messageId);
20722086
setState(() {
20732087
controller.dispose();
20742088
_controller = emptyEditController;
@@ -2136,10 +2150,11 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
21362150

21372151
switch (controller) {
21382152
case StreamComposeBoxController():
2153+
controller.content.store = newStore;
21392154
controller.topic.store = newStore;
21402155
case FixedDestinationComposeBoxController():
21412156
case EditMessageComposeBoxController():
2142-
// no reference to the store that needs updating
2157+
controller.content.store = newStore;
21432158
}
21442159
}
21452160

@@ -2149,7 +2164,7 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
21492164
_controller = StreamComposeBoxController(store: store);
21502165
case TopicNarrow():
21512166
case DmNarrow():
2152-
_controller = FixedDestinationComposeBoxController();
2167+
_controller = FixedDestinationComposeBoxController(store: store);
21532168
case CombinedFeedNarrow():
21542169
case MentionsNarrow():
21552170
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+
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
@@ -1650,7 +1650,7 @@ void main() {
16501650
required TextEditingValue valueBefore,
16511651
required Message message,
16521652
}) {
1653-
check(contentController).value.equals((ComposeContentController()
1653+
check(contentController).value.equals((ComposeContentController(store: store)
16541654
..value = valueBefore
16551655
..insertPadded(quoteAndReplyPlaceholder(
16561656
GlobalLocalizations.zulipLocalizations, store, message: message))
@@ -1663,7 +1663,7 @@ void main() {
16631663
required Message message,
16641664
required String rawContent,
16651665
}) {
1666-
final builder = ComposeContentController()
1666+
final builder = ComposeContentController(store: store)
16671667
..value = valueBefore
16681668
..insertPadded(quoteAndReply(store, message: message, rawContent: rawContent));
16691669
if (!valueBefore.selection.isValid) {

test/widgets/compose_box_test.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ void main() {
253253
/// In expectedValue, represent the collapsed selection as "^".
254254
void testInsertPadded(String description, String valueBefore, String textToInsert, String expectedValue) {
255255
test(description, () {
256-
final controller = ComposeContentController();
256+
store = eg.store();
257+
final controller = ComposeContentController(store: store);
257258
controller.value = parseMarkedText(valueBefore);
258259
controller.insertPadded(textToInsert);
259260
check(controller.value).equals(parseMarkedText(expectedValue));
@@ -334,15 +335,17 @@ void main() {
334335
}
335336

336337
testWidgets('requireNotEmpty: true (default)', (tester) async {
337-
controller = ComposeContentController();
338+
store = eg.store();
339+
controller = ComposeContentController(store: store);
338340
addTearDown(controller.dispose);
339341
checkCountsAsEmpty('', true);
340342
checkCountsAsEmpty(' ', true);
341343
checkCountsAsEmpty('a', false);
342344
});
343345

344346
testWidgets('requireNotEmpty: false', (tester) async {
345-
controller = ComposeContentController(requireNotEmpty: false);
347+
store = eg.store();
348+
controller = ComposeContentController(store: store, requireNotEmpty: false);
346349
addTearDown(controller.dispose);
347350
checkCountsAsEmpty('', false);
348351
checkCountsAsEmpty(' ', false);

0 commit comments

Comments
 (0)