@@ -327,6 +327,48 @@ class _StreamContentInputState extends State<_StreamContentInput> {
327
327
}
328
328
}
329
329
330
+ class _FixedDestinationContentInput extends StatelessWidget {
331
+ const _FixedDestinationContentInput ({
332
+ required this .narrow,
333
+ required this .controller,
334
+ required this .focusNode,
335
+ });
336
+
337
+ final SendableNarrow narrow;
338
+ final ComposeContentController controller;
339
+ final FocusNode focusNode;
340
+
341
+ String _hintText (BuildContext context) {
342
+ switch (narrow) {
343
+ case TopicNarrow (: final streamId, : final topic):
344
+ final store = PerAccountStoreWidget .of (context);
345
+ final streamName = store.streams[streamId]? .name ?? '(unknown stream)' ;
346
+ return "Message #$streamName > $topic " ;
347
+
348
+ case DmNarrow (otherRecipientIds: []): // The self-1:1 thread.
349
+ return "Jot down something" ;
350
+
351
+ case DmNarrow (otherRecipientIds: [final otherUserId]):
352
+ final store = PerAccountStoreWidget .of (context);
353
+ final fullName = store.users[otherUserId]? .fullName;
354
+ if (fullName == null ) return 'Type a message' ;
355
+ return 'Message @$fullName ' ;
356
+
357
+ case DmNarrow (): // A group DM thread.
358
+ return 'Message group' ;
359
+ }
360
+ }
361
+
362
+ @override
363
+ Widget build (BuildContext context) {
364
+ return _ContentInput (
365
+ narrow: narrow,
366
+ controller: controller,
367
+ focusNode: focusNode,
368
+ hintText: _hintText (context));
369
+ }
370
+ }
371
+
330
372
/// Data on a file to be uploaded, from any source.
331
373
///
332
374
/// A convenience class to represent data from the generic file picker,
@@ -781,6 +823,45 @@ class _StreamComposeBoxState extends State<_StreamComposeBox> {
781
823
}
782
824
}
783
825
826
+ class _FixedDestinationComposeBox extends StatefulWidget {
827
+ const _FixedDestinationComposeBox ({required this .narrow});
828
+
829
+ final SendableNarrow narrow;
830
+
831
+ @override
832
+ State <_FixedDestinationComposeBox > createState () => _FixedDestinationComposeBoxState ();
833
+ }
834
+
835
+ class _FixedDestinationComposeBoxState extends State <_FixedDestinationComposeBox > {
836
+ final _contentController = ComposeContentController ();
837
+ final _contentFocusNode = FocusNode ();
838
+
839
+ @override
840
+ void dispose () {
841
+ _contentController.dispose ();
842
+ _contentFocusNode.dispose ();
843
+ super .dispose ();
844
+ }
845
+
846
+ @override
847
+ Widget build (BuildContext context) {
848
+ return _ComposeBoxLayout (
849
+ contentController: _contentController,
850
+ contentFocusNode: _contentFocusNode,
851
+ topicInput: null ,
852
+ contentInput: _FixedDestinationContentInput (
853
+ narrow: widget.narrow,
854
+ controller: _contentController,
855
+ focusNode: _contentFocusNode,
856
+ ),
857
+ sendButton: _SendButton (
858
+ topicController: null ,
859
+ contentController: _contentController,
860
+ getDestination: () => widget.narrow.destination,
861
+ ));
862
+ }
863
+ }
864
+
784
865
class ComposeBox extends StatelessWidget {
785
866
const ComposeBox ({super .key, required this .narrow});
786
867
@@ -792,9 +873,9 @@ class ComposeBox extends StatelessWidget {
792
873
if (narrow is StreamNarrow ) {
793
874
return _StreamComposeBox (narrow: narrow);
794
875
} else if (narrow is TopicNarrow ) {
795
- return const SizedBox . shrink (); // TODO(#144): add a single-topic compose box
876
+ return _FixedDestinationComposeBox (narrow : narrow);
796
877
} else if (narrow is DmNarrow ) {
797
- return const SizedBox . shrink (); // TODO(#144): add a DM compose box
878
+ return _FixedDestinationComposeBox (narrow : narrow);
798
879
} else if (narrow is AllMessagesNarrow ) {
799
880
return const SizedBox .shrink ();
800
881
} else {
0 commit comments