@@ -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,92 @@ class _InboxPageState extends State<InboxPageBody> with PerAccountStoreAwareStat
182187 }
183188}
184189
190+ class InboxEmptyWidget extends StatelessWidget {
191+ const InboxEmptyWidget ({super .key});
192+
193+ // Splits a message containing text in square brackets into three parts.
194+ List <String > _splitMessage (String message) {
195+ final pattern = RegExp (r'(.*?)\[(.*?)\](.*)' , dotAll: true );
196+ final match = pattern.firstMatch (message);
197+
198+ return match == null
199+ ? [message, '' , '' ]
200+ : [
201+ match.group (1 ) ?? '' ,
202+ match.group (2 ) ?? '' ,
203+ match.group (3 ) ?? '' ,
204+ ];
205+ }
206+
207+ @override
208+ Widget build (BuildContext context) {
209+ final zulipLocalizations = ZulipLocalizations .of (context);
210+ final designVariables = DesignVariables .of (context);
211+
212+ final messageParts = _splitMessage (zulipLocalizations.emptyInboxMessage);
213+
214+ return Center (
215+ child: Padding (
216+ padding: const EdgeInsets .all (16 ),
217+ child: Column (
218+ mainAxisAlignment: MainAxisAlignment .start,
219+ children: [
220+ const SizedBox (height: 48 ),
221+ Icon (
222+ ZulipIcons .inbox_done,
223+ size: 80 ,
224+ color: designVariables.foreground.withFadedAlpha (0.3 ),
225+ ),
226+ const SizedBox (height: 16 ),
227+ Text .rich (
228+ TextSpan (
229+ style: TextStyle (
230+ color: designVariables.labelSearchPrompt,
231+ fontSize: 17 ,
232+ fontWeight: FontWeight .w500,
233+ ),
234+ children: [
235+ TextSpan (text: messageParts[0 ]),
236+ WidgetSpan (
237+ alignment: PlaceholderAlignment .baseline,
238+ baseline: TextBaseline .alphabetic,
239+ child: TextButton (
240+ style: TextButton .styleFrom (
241+ padding: EdgeInsets .zero,
242+ minimumSize: Size .zero,
243+ tapTargetSize: MaterialTapTargetSize .shrinkWrap,
244+ splashFactory: NoSplash .splashFactory
245+ ),
246+ onPressed: () => Navigator .push (context,
247+ MessageListPage .buildRoute (context: context,
248+ narrow: const CombinedFeedNarrow ())),
249+ child: Text (
250+ messageParts[1 ],
251+ style: TextStyle (
252+ fontSize: 17 ,
253+ fontWeight: FontWeight .w500,
254+ color: designVariables.link,
255+ decoration: TextDecoration .underline,
256+ decorationStyle: TextDecorationStyle .solid,
257+ decorationThickness: 2.5 ,
258+ decorationColor: designVariables.link,
259+ height: 1.5 ,
260+ )
261+ ),
262+ ),
263+ ),
264+ TextSpan (text: messageParts[2 ]),
265+ ],
266+ ),
267+ textAlign: TextAlign .center,
268+ ),
269+ ],
270+ ),
271+ ),
272+ );
273+ }
274+ }
275+
185276sealed class _InboxSectionData {
186277 const _InboxSectionData ();
187278}
0 commit comments