@@ -6,6 +6,7 @@ import '../model/narrow.dart';
66import '../model/recent_dm_conversations.dart' ;
77import '../model/unreads.dart' ;
88import 'action_sheet.dart' ;
9+ import 'color.dart' ;
910import 'icons.dart' ;
1011import 'message_list.dart' ;
1112import 'sticky_header.dart' ;
@@ -160,6 +161,10 @@ class _InboxPageState extends State<InboxPageBody> with PerAccountStoreAwareStat
160161 sections.add (_StreamSectionData (streamId, countInStream, streamHasMention, topicItems));
161162 }
162163
164+ if (sections.isEmpty) {
165+ return const InboxEmptyWidget ();
166+ }
167+
163168 return SafeArea (
164169 // Don't pad the bottom here; we want the list content to do that.
165170 bottom: false ,
@@ -182,6 +187,93 @@ class _InboxPageState extends State<InboxPageBody> with PerAccountStoreAwareStat
182187 }
183188}
184189
190+ class InboxEmptyWidget extends StatelessWidget {
191+ const InboxEmptyWidget ({super .key});
192+
193+ List <String > _splitMessage (String message) {
194+ final pattern = RegExp (r'(.*?)\[(.*?)\](.*)' , dotAll: true );
195+ final match = pattern.firstMatch (message);
196+
197+ if (match == null ) {
198+ throw Exception ('Message must contain text in [brackets]' );
199+ }
200+
201+ return [
202+ match.group (1 ) ?? '' ,
203+ match.group (2 ) ?? '' ,
204+ match.group (3 ) ?? '' ,
205+ ];
206+ }
207+
208+ @override
209+ Widget build (BuildContext context) {
210+ final zulipLocalizations = ZulipLocalizations .of (context);
211+ final designVariables = DesignVariables .of (context);
212+
213+ final messageParts = _splitMessage (zulipLocalizations.emptyInboxMessage);
214+
215+ return Center (
216+ child: Padding (
217+ padding: const EdgeInsets .all (16 ),
218+ child: Column (
219+ mainAxisAlignment: MainAxisAlignment .start,
220+ children: [
221+ const SizedBox (height: 48 ),
222+ Icon (
223+ ZulipIcons .inbox_done,
224+ size: 80 ,
225+ color: designVariables.foreground.withFadedAlpha (0.3 ),
226+ ),
227+ const SizedBox (height: 16 ),
228+ Text .rich (
229+ TextSpan (
230+ style: TextStyle (
231+ color: designVariables.labelSearchPrompt,
232+ fontSize: 17 ,
233+ fontWeight: FontWeight .w500,
234+ ),
235+ children: [
236+ TextSpan (text: messageParts[0 ]),
237+ WidgetSpan (
238+ alignment: PlaceholderAlignment .baseline,
239+ baseline: TextBaseline .alphabetic,
240+ child: TextButton (
241+ style: TextButton .styleFrom (
242+ padding: EdgeInsets .zero,
243+ minimumSize: Size .zero,
244+ tapTargetSize: MaterialTapTargetSize .shrinkWrap,
245+ splashFactory: NoSplash .splashFactory
246+ ),
247+ onPressed: () => Navigator .push (context,
248+ MessageListPage .buildRoute (context: context,
249+ narrow: const CombinedFeedNarrow ())),
250+ child: Text (
251+ messageParts[1 ],
252+ style: TextStyle (
253+ fontSize: 17 ,
254+ fontWeight: FontWeight .w500,
255+ color: designVariables.link,
256+ decoration: TextDecoration .underline,
257+ decorationStyle: TextDecorationStyle .solid,
258+ decorationThickness: 2.5 ,
259+ decorationColor: designVariables.link,
260+ height: 1.5 ,
261+ )
262+ ),
263+ ),
264+ ),
265+ TextSpan (text: messageParts[2 ]),
266+ ],
267+ ),
268+ textAlign: TextAlign .center,
269+ ),
270+ ],
271+ ),
272+ ),
273+ );
274+ }
275+ }
276+
185277sealed class _InboxSectionData {
186278 const _InboxSectionData ();
187279}
0 commit comments