@@ -45,8 +45,7 @@ class _AutocompleteFieldState<QueryT extends AutocompleteQuery, ResultT extends
4545 }
4646
4747 void _handleControllerChange () {
48- var newQuery = widget.autocompleteIntent ()? .query;
49- if (newQuery is ChannelLinkAutocompleteQuery ) newQuery = null ; // TODO(#124)
48+ final newQuery = widget.autocompleteIntent ()? .query;
5049 // First, tear down the old view-model if necessary.
5150 if (_viewModel != null
5251 && (newQuery == null
@@ -227,8 +226,17 @@ class ComposeAutocomplete extends AutocompleteField<ComposeAutocompleteQuery, Co
227226 // TODO(#1805) language-appropriate space character; check active keyboard?
228227 // (maybe handle centrally in `controller`)
229228 replacementString = '${userGroupMention (userGroup .name , silent : query .silent )} ' ;
230- case ChannelLinkAutocompleteResult ():
231- throw UnimplementedError (); // TODO(#124)
229+ case ChannelLinkAutocompleteResult (: final channelId):
230+ if (query is ! ChannelLinkAutocompleteQuery ) {
231+ return ; // Shrug; similar to `intent == null` case above.
232+ }
233+ final channel = store.streams[channelId];
234+ if (channel == null ) {
235+ // Don't crash on theoretical race between async results-filtering
236+ // and losing data for the channel.
237+ return ;
238+ }
239+ replacementString = '${channelLink (channel , store : store )} ' ;
232240 }
233241
234242 controller.value = intent.textEditingValue.replaced (
@@ -246,7 +254,7 @@ class ComposeAutocomplete extends AutocompleteField<ComposeAutocompleteQuery, Co
246254 final child = switch (option) {
247255 MentionAutocompleteResult () => MentionAutocompleteItem (
248256 option: option, narrow: narrow),
249- ChannelLinkAutocompleteResult () => throw UnimplementedError (), // TODO(#124)
257+ ChannelLinkAutocompleteResult () => _ChannelLinkAutocompleteItem (option : option),
250258 EmojiAutocompleteResult () => _EmojiAutocompleteItem (option: option),
251259 };
252260 return InkWell (
@@ -361,6 +369,51 @@ class MentionAutocompleteItem extends StatelessWidget {
361369 }
362370}
363371
372+ class _ChannelLinkAutocompleteItem extends StatelessWidget {
373+ const _ChannelLinkAutocompleteItem ({required this .option});
374+
375+ final ChannelLinkAutocompleteResult option;
376+
377+ @override
378+ Widget build (BuildContext context) {
379+ final store = PerAccountStoreWidget .of (context);
380+ final zulipLocalizations = ZulipLocalizations .of (context);
381+ final designVariables = DesignVariables .of (context);
382+
383+ final channel = store.streams[option.channelId];
384+
385+ // A null [Icon.icon] makes a blank space.
386+ IconData ? icon;
387+ Color ? iconColor;
388+ String label;
389+ if (channel != null ) {
390+ icon = iconDataForStream (channel);
391+ iconColor = colorSwatchFor (context, store.subscriptions[channel.streamId])
392+ .iconOnPlainBackground;
393+ label = channel.name;
394+ } else {
395+ icon = null ;
396+ iconColor = null ;
397+ label = zulipLocalizations.unknownChannelName;
398+ }
399+
400+ final labelWidget = Text (label,
401+ overflow: TextOverflow .ellipsis,
402+ style: TextStyle (
403+ fontSize: 18 , height: 20 / 18 ,
404+ fontStyle: channel == null ? FontStyle .italic : FontStyle .normal,
405+ color: designVariables.contextMenuItemLabel,
406+ ).merge (weightVariableTextStyle (context, wght: 600 )));
407+
408+ return Padding (
409+ padding: EdgeInsetsDirectional .fromSTEB (4 , 4 , 8 , 4 ),
410+ child: Row (spacing: 6 , children: [
411+ SizedBox .square (dimension: 36 , child: Icon (size: 18 , color: iconColor, icon)),
412+ Expanded (child: labelWidget), // TODO(#1945): show channel description
413+ ]));
414+ }
415+ }
416+
364417class _EmojiAutocompleteItem extends StatelessWidget {
365418 const _EmojiAutocompleteItem ({required this .option});
366419
0 commit comments