From 4b2a175facff8a5155198cfaf4d7213edc6cc9e9 Mon Sep 17 00:00:00 2001 From: khanak0509 Date: Sat, 20 Dec 2025 21:38:23 +0530 Subject: [PATCH 1/2] Add intro modals for Inbox and Combined Feed Fixes #1856 --- assets/l10n/app_en.arb | 20 ++++ lib/generated/l10n/zulip_localizations.dart | 30 ++++++ .../l10n/zulip_localizations_ar.dart | 17 ++++ .../l10n/zulip_localizations_de.dart | 17 ++++ .../l10n/zulip_localizations_el.dart | 17 ++++ .../l10n/zulip_localizations_en.dart | 17 ++++ .../l10n/zulip_localizations_es.dart | 17 ++++ .../l10n/zulip_localizations_fr.dart | 17 ++++ .../l10n/zulip_localizations_he.dart | 17 ++++ .../l10n/zulip_localizations_hu.dart | 17 ++++ .../l10n/zulip_localizations_it.dart | 17 ++++ .../l10n/zulip_localizations_ja.dart | 17 ++++ .../l10n/zulip_localizations_nb.dart | 17 ++++ .../l10n/zulip_localizations_pl.dart | 17 ++++ .../l10n/zulip_localizations_ru.dart | 17 ++++ .../l10n/zulip_localizations_sk.dart | 17 ++++ .../l10n/zulip_localizations_sl.dart | 17 ++++ .../l10n/zulip_localizations_uk.dart | 17 ++++ .../l10n/zulip_localizations_vi.dart | 17 ++++ .../l10n/zulip_localizations_zh.dart | 17 ++++ lib/model/settings.dart | 4 + lib/widgets/dialog.dart | 95 +++++++++++++++++-- lib/widgets/inbox.dart | 2 + lib/widgets/message_list.dart | 4 + 24 files changed, 454 insertions(+), 7 deletions(-) diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 5afc9544d2..8e2a332ddc 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -31,6 +31,26 @@ "@upgradeWelcomeDialogDismiss": { "description": "Label for button dismissing dialog shown on first upgrade from the legacy Zulip app." }, + "introModalDismissButton": "Got it", + "@introModalDismissButton": { + "description": "Label for button dismissing intro modals." + }, + "inboxIntroModalTitle": "Welcome to your inbox!", + "@inboxIntroModalTitle": { + "description": "Title for the inbox intro modal." + }, + "inboxIntroModalMessage": "You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.", + "@inboxIntroModalMessage": { + "description": "Message content for the inbox intro modal." + }, + "combinedFeedIntroModalTitle": "Welcome to your combined feed!", + "@combinedFeedIntroModalTitle": { + "description": "Title for the combined feed intro modal." + }, + "combinedFeedIntroModalMessage": "You'll see a feed of all the unmuted messages you've received. You can click on a colored header bar to view a conversation.", + "@combinedFeedIntroModalMessage": { + "description": "Message content for the combined feed intro modal." + }, "chooseAccountPageTitle": "Choose account", "@chooseAccountPageTitle": { "description": "Title for the page to choose between Zulip accounts." diff --git a/lib/generated/l10n/zulip_localizations.dart b/lib/generated/l10n/zulip_localizations.dart index 36a83ac3bb..69df65821f 100644 --- a/lib/generated/l10n/zulip_localizations.dart +++ b/lib/generated/l10n/zulip_localizations.dart @@ -189,6 +189,36 @@ abstract class ZulipLocalizations { /// **'Let\'s go'** String get upgradeWelcomeDialogDismiss; + /// Label for button dismissing intro modals. + /// + /// In en, this message translates to: + /// **'Got it'** + String get introModalDismissButton; + + /// Title for the inbox intro modal. + /// + /// In en, this message translates to: + /// **'Welcome to your inbox!'** + String get inboxIntroModalTitle; + + /// Message content for the inbox intro modal. + /// + /// In en, this message translates to: + /// **'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'** + String get inboxIntroModalMessage; + + /// Title for the combined feed intro modal. + /// + /// In en, this message translates to: + /// **'Welcome to your combined feed!'** + String get combinedFeedIntroModalTitle; + + /// Message content for the combined feed intro modal. + /// + /// In en, this message translates to: + /// **'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'** + String get combinedFeedIntroModalMessage; + /// Title for the page to choose between Zulip accounts. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/zulip_localizations_ar.dart b/lib/generated/l10n/zulip_localizations_ar.dart index 0de3988707..b0976b88f0 100644 --- a/lib/generated/l10n/zulip_localizations_ar.dart +++ b/lib/generated/l10n/zulip_localizations_ar.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsAr extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'هيا بنا'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'اختر حساب'; diff --git a/lib/generated/l10n/zulip_localizations_de.dart b/lib/generated/l10n/zulip_localizations_de.dart index cb5793ef39..e23fc4f412 100644 --- a/lib/generated/l10n/zulip_localizations_de.dart +++ b/lib/generated/l10n/zulip_localizations_de.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsDe extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Los gehts'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Konto auswählen'; diff --git a/lib/generated/l10n/zulip_localizations_el.dart b/lib/generated/l10n/zulip_localizations_el.dart index 37510410f9..984a012859 100644 --- a/lib/generated/l10n/zulip_localizations_el.dart +++ b/lib/generated/l10n/zulip_localizations_el.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsEl extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choose account'; diff --git a/lib/generated/l10n/zulip_localizations_en.dart b/lib/generated/l10n/zulip_localizations_en.dart index 57a6a13d75..6ba37edfab 100644 --- a/lib/generated/l10n/zulip_localizations_en.dart +++ b/lib/generated/l10n/zulip_localizations_en.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsEn extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choose account'; diff --git a/lib/generated/l10n/zulip_localizations_es.dart b/lib/generated/l10n/zulip_localizations_es.dart index 163fb4e6a4..faba01f4a4 100644 --- a/lib/generated/l10n/zulip_localizations_es.dart +++ b/lib/generated/l10n/zulip_localizations_es.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsEs extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choose account'; diff --git a/lib/generated/l10n/zulip_localizations_fr.dart b/lib/generated/l10n/zulip_localizations_fr.dart index 43ed1eb3ad..eff8ba8886 100644 --- a/lib/generated/l10n/zulip_localizations_fr.dart +++ b/lib/generated/l10n/zulip_localizations_fr.dart @@ -35,6 +35,23 @@ class ZulipLocalizationsFr extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Allons-y'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choisir un compte'; diff --git a/lib/generated/l10n/zulip_localizations_he.dart b/lib/generated/l10n/zulip_localizations_he.dart index 4a813be1b0..3a30455fab 100644 --- a/lib/generated/l10n/zulip_localizations_he.dart +++ b/lib/generated/l10n/zulip_localizations_he.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsHe extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choose account'; diff --git a/lib/generated/l10n/zulip_localizations_hu.dart b/lib/generated/l10n/zulip_localizations_hu.dart index 6b3805bf99..a7c195236e 100644 --- a/lib/generated/l10n/zulip_localizations_hu.dart +++ b/lib/generated/l10n/zulip_localizations_hu.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsHu extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choose account'; diff --git a/lib/generated/l10n/zulip_localizations_it.dart b/lib/generated/l10n/zulip_localizations_it.dart index 0c06cd4b38..6cc4039898 100644 --- a/lib/generated/l10n/zulip_localizations_it.dart +++ b/lib/generated/l10n/zulip_localizations_it.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsIt extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Andiamo'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Scegli account'; diff --git a/lib/generated/l10n/zulip_localizations_ja.dart b/lib/generated/l10n/zulip_localizations_ja.dart index 5ae5bbc394..341204e3f9 100644 --- a/lib/generated/l10n/zulip_localizations_ja.dart +++ b/lib/generated/l10n/zulip_localizations_ja.dart @@ -33,6 +33,23 @@ class ZulipLocalizationsJa extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'はじめよう'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'アカウントを選択'; diff --git a/lib/generated/l10n/zulip_localizations_nb.dart b/lib/generated/l10n/zulip_localizations_nb.dart index d828f44d95..a9cdd8dde6 100644 --- a/lib/generated/l10n/zulip_localizations_nb.dart +++ b/lib/generated/l10n/zulip_localizations_nb.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsNb extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choose account'; diff --git a/lib/generated/l10n/zulip_localizations_pl.dart b/lib/generated/l10n/zulip_localizations_pl.dart index 5eb1ffd41f..be51b23274 100644 --- a/lib/generated/l10n/zulip_localizations_pl.dart +++ b/lib/generated/l10n/zulip_localizations_pl.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsPl extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Zaczynajmy'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Wybierz konto'; diff --git a/lib/generated/l10n/zulip_localizations_ru.dart b/lib/generated/l10n/zulip_localizations_ru.dart index 3fc9bd6832..614a84fc92 100644 --- a/lib/generated/l10n/zulip_localizations_ru.dart +++ b/lib/generated/l10n/zulip_localizations_ru.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsRu extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Приступим'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Выберите учетную запись'; diff --git a/lib/generated/l10n/zulip_localizations_sk.dart b/lib/generated/l10n/zulip_localizations_sk.dart index 4841efd265..fcd0cac52f 100644 --- a/lib/generated/l10n/zulip_localizations_sk.dart +++ b/lib/generated/l10n/zulip_localizations_sk.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsSk extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Zvoliť účet'; diff --git a/lib/generated/l10n/zulip_localizations_sl.dart b/lib/generated/l10n/zulip_localizations_sl.dart index c4c6d91ed1..e698aed2b3 100644 --- a/lib/generated/l10n/zulip_localizations_sl.dart +++ b/lib/generated/l10n/zulip_localizations_sl.dart @@ -33,6 +33,23 @@ class ZulipLocalizationsSl extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Začnimo'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Izberite račun'; diff --git a/lib/generated/l10n/zulip_localizations_uk.dart b/lib/generated/l10n/zulip_localizations_uk.dart index d18fd0fd53..eb4061deec 100644 --- a/lib/generated/l10n/zulip_localizations_uk.dart +++ b/lib/generated/l10n/zulip_localizations_uk.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsUk extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Ходімо'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Обрати обліковий запис'; diff --git a/lib/generated/l10n/zulip_localizations_vi.dart b/lib/generated/l10n/zulip_localizations_vi.dart index 36f0f7ded5..2ab09530be 100644 --- a/lib/generated/l10n/zulip_localizations_vi.dart +++ b/lib/generated/l10n/zulip_localizations_vi.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsVi extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choose account'; diff --git a/lib/generated/l10n/zulip_localizations_zh.dart b/lib/generated/l10n/zulip_localizations_zh.dart index 085866b1d8..15f0f43f84 100644 --- a/lib/generated/l10n/zulip_localizations_zh.dart +++ b/lib/generated/l10n/zulip_localizations_zh.dart @@ -34,6 +34,23 @@ class ZulipLocalizationsZh extends ZulipLocalizations { @override String get upgradeWelcomeDialogDismiss => 'Let\'s go'; + @override + String get introModalDismissButton => 'Got it'; + + @override + String get inboxIntroModalTitle => 'Welcome to your inbox!'; + + @override + String get inboxIntroModalMessage => + 'You’ll see a list of conversations where you have unread messages, organized by channel. Each conversation is labeled with a topic by the person who started it.'; + + @override + String get combinedFeedIntroModalTitle => 'Welcome to your combined feed!'; + + @override + String get combinedFeedIntroModalMessage => + 'You\'ll see a feed of all the unmuted messages you\'ve received. You can click on a colored header bar to view a conversation.'; + @override String get chooseAccountPageTitle => 'Choose account'; diff --git a/lib/model/settings.dart b/lib/model/settings.dart index a85a1f6f74..f48c0e837d 100644 --- a/lib/model/settings.dart +++ b/lib/model/settings.dart @@ -176,6 +176,10 @@ enum BoolGlobalSetting { /// A pseudo-setting recording whether the user has been shown the /// welcome dialog for upgrading from the legacy app. upgradeWelcomeDialogShown(GlobalSettingType.internal, false), + inboxIntroModalShown(GlobalSettingType.internal, false), + combinedFeedIntroModalShown(GlobalSettingType.internal, false), + + /// An experimental flag to enable rendering KaTeX even when some /// errors are encountered. diff --git a/lib/widgets/dialog.dart b/lib/widgets/dialog.dart index 4dacf8c0be..e73cc7ae08 100644 --- a/lib/widgets/dialog.dart +++ b/lib/widgets/dialog.dart @@ -71,6 +71,7 @@ Widget? _adaptiveContent(Widget? content) { // *top* of that page; shrug.) textAlign: TextAlign.start, child: content); + } } @@ -185,7 +186,9 @@ class UpgradeWelcomeDialog extends StatelessWidget { final navigator = await ZulipApp.navigator; final context = navigator.context; assert(context.mounted); - if (!context.mounted) return; // TODO(linter): this is impossible as there's no actual async gap, but the use_build_context_synchronously lint doesn't see that + if (!context.mounted) { + return; // TODO(linter): this is impossible as there's no actual async gap, but the use_build_context_synchronously lint doesn't see that + } final globalSettings = GlobalStoreWidget.settingsOf(context); switch (globalSettings.legacyUpgradeState) { @@ -214,11 +217,14 @@ class UpgradeWelcomeDialog extends StatelessWidget { await future; // Wait for the dialog to be dismissed. - await globalSettings.setBool(BoolGlobalSetting.upgradeWelcomeDialogShown, true); + await globalSettings.setBool( + BoolGlobalSetting.upgradeWelcomeDialogShown, + true, + ); } static const String _announcementUrl = - 'https://blog.zulip.com/flutter-mobile-app-launch'; + 'https://blog.zulip.com/flutter-mobile-app-launch'; @override Widget build(BuildContext context) { @@ -227,12 +233,12 @@ class UpgradeWelcomeDialog extends StatelessWidget { title: Text(zulipLocalizations.upgradeWelcomeDialogTitle), content: _adaptiveContent( Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(zulipLocalizations.upgradeWelcomeDialogMessage), - GestureDetector( + Text(zulipLocalizations.upgradeWelcomeDialogMessage), + GestureDetector( onTap: () => PlatformActions.launchUrl(context, Uri.parse(_announcementUrl)), - child: Text( - style: TextStyle(color: ContentTheme.of(context).colorLink), + child: Text( + style: TextStyle(color: ContentTheme.of(context).colorLink), zulipLocalizations.upgradeWelcomeDialogLinkText)), ])), actions: [ @@ -243,3 +249,78 @@ class UpgradeWelcomeDialog extends StatelessWidget { ]); } } + +class IntroModal extends StatelessWidget { + const IntroModal({ + super.key, + required this.title, + required this.message, + }); + + final String title; + final String message; + + @override + Widget build(BuildContext context) { + final zulipLocalizations = ZulipLocalizations.of(context); + return AlertDialog.adaptive( + title: Text(title), + content: _adaptiveContent(Text(message)), + actions: [ + _adaptiveAction( + onPressed: () => Navigator.pop(context), + isDefaultAction: true, + text: zulipLocalizations.introModalDismissButton) + ]); + } +} + +Future showInboxIntroModal(BuildContext context) async { + // Skip during tests by checking the binding type. + if (WidgetsBinding.instance.runtimeType.toString().contains('Test')) { + return; + } + + WidgetsBinding.instance.addPostFrameCallback((_) async { + final store = GlobalStoreWidget.settingsOf(context); + if (store.getBool(BoolGlobalSetting.inboxIntroModalShown)) { + return; + } + + final zulipLocalizations = ZulipLocalizations.of(context); + final future = showDialog( + context: context, + builder: (context) => IntroModal( + title: zulipLocalizations.inboxIntroModalTitle, + message: zulipLocalizations.inboxIntroModalMessage, + ), + ); + await future; + await store.setBool(BoolGlobalSetting.inboxIntroModalShown, true); + }); +} + +Future showCombinedFeedIntroModal(BuildContext context) async { + // Skip during tests by checking the binding type. + if (WidgetsBinding.instance.runtimeType.toString().contains('Test')) { + return; + } + + WidgetsBinding.instance.addPostFrameCallback((_) async { + final store = GlobalStoreWidget.settingsOf(context); + if (store.getBool(BoolGlobalSetting.combinedFeedIntroModalShown)) { + return; + } + + final zulipLocalizations = ZulipLocalizations.of(context); + final future = showDialog( + context: context, + builder: (context) => IntroModal( + title: zulipLocalizations.combinedFeedIntroModalTitle, + message: zulipLocalizations.combinedFeedIntroModalMessage, + ), + ); + await future; + await store.setBool(BoolGlobalSetting.combinedFeedIntroModalShown, true); + }); +} diff --git a/lib/widgets/inbox.dart b/lib/widgets/inbox.dart index ce7b200327..5f453a5809 100644 --- a/lib/widgets/inbox.dart +++ b/lib/widgets/inbox.dart @@ -6,6 +6,7 @@ import '../model/narrow.dart'; import '../model/recent_dm_conversations.dart'; import '../model/unreads.dart'; import 'action_sheet.dart'; +import 'dialog.dart'; import 'icons.dart'; import 'message_list.dart'; import 'page.dart'; @@ -55,6 +56,7 @@ class _InboxPageState extends State with PerAccountStoreAwareStat recentDmConversationsModel?.removeListener(_modelChanged); recentDmConversationsModel = newStore.recentDmConversationsView ..addListener(_modelChanged); + showInboxIntroModal(context); } @override diff --git a/lib/widgets/message_list.dart b/lib/widgets/message_list.dart index 24fa8c077b..80b4e955de 100644 --- a/lib/widgets/message_list.dart +++ b/lib/widgets/message_list.dart @@ -22,6 +22,7 @@ import 'button.dart'; import 'color.dart'; import 'compose_box.dart'; import 'content.dart'; +import 'dialog.dart'; import 'emoji_reaction.dart'; import 'icons.dart'; import 'page.dart'; @@ -320,6 +321,9 @@ class _MessageListPageState extends State implements MessageLis void initState() { super.initState(); narrow = widget.initNarrow; + if (narrow is CombinedFeedNarrow) { + showCombinedFeedIntroModal(context); + } } void _narrowChanged(Narrow newNarrow) { From 14cb4207e0017dd85fe447138dad59c3fe669a7d Mon Sep 17 00:00:00 2001 From: khanak0509 Date: Sun, 21 Dec 2025 14:47:34 +0530 Subject: [PATCH 2/2] add test --- lib/widgets/dialog.dart | 5 +- test/widgets/dialog_test.dart | 168 ++++++++++++++++++++++------------ 2 files changed, 112 insertions(+), 61 deletions(-) diff --git a/lib/widgets/dialog.dart b/lib/widgets/dialog.dart index e73cc7ae08..634595bde3 100644 --- a/lib/widgets/dialog.dart +++ b/lib/widgets/dialog.dart @@ -217,10 +217,7 @@ class UpgradeWelcomeDialog extends StatelessWidget { await future; // Wait for the dialog to be dismissed. - await globalSettings.setBool( - BoolGlobalSetting.upgradeWelcomeDialogShown, - true, - ); + await globalSettings.setBool(BoolGlobalSetting.upgradeWelcomeDialogShown, true); } static const String _announcementUrl = diff --git a/test/widgets/dialog_test.dart b/test/widgets/dialog_test.dart index 5e273a5dab..eb7ac57417 100644 --- a/test/widgets/dialog_test.dart +++ b/test/widgets/dialog_test.dart @@ -7,7 +7,7 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:zulip/model/settings.dart'; import 'package:zulip/widgets/app.dart'; import 'package:zulip/widgets/dialog.dart'; - +import '../example_data.dart' as eg; import '../model/binding.dart'; import 'dialog_checks.dart'; import 'test_app.dart'; @@ -31,48 +31,48 @@ void main() { group('showErrorDialog', () { testWidgets('show error dialog', (tester) async { - await prepare(tester); + await prepare(tester); - showErrorDialog(context: context, title: title, message: message); - await tester.pump(); + showErrorDialog(context: context, title: title, message: message); + await tester.pump(); checkErrorDialog(tester, expectedTitle: title, expectedMessage: message); }, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); testWidgets('user closes error dialog', (tester) async { - await prepare(tester); + await prepare(tester); - showErrorDialog(context: context, title: title, message: message); - await tester.pump(); + showErrorDialog(context: context, title: title, message: message); + await tester.pump(); - final button = checkErrorDialog(tester, expectedTitle: title); - await tester.tap(find.byWidget(button)); - await tester.pump(); - checkNoDialog(tester); + final button = checkErrorDialog(tester, expectedTitle: title); + await tester.tap(find.byWidget(button)); + await tester.pump(); + checkNoDialog(tester); }, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); testWidgets('tap "Learn more" button', (tester) async { - await prepare(tester); + await prepare(tester); - final learnMoreButtonUrl = Uri.parse('https://foo.example'); + final learnMoreButtonUrl = Uri.parse('https://foo.example'); showErrorDialog(context: context, title: title, learnMoreButtonUrl: learnMoreButtonUrl); - await tester.pump(); - checkErrorDialog(tester, expectedTitle: title); + await tester.pump(); + checkErrorDialog(tester, expectedTitle: title); - await tester.tap(find.text('Learn more')); - final expectedMode = switch (defaultTargetPlatform) { - TargetPlatform.android => LaunchMode.inAppBrowserView, + await tester.tap(find.text('Learn more')); + final expectedMode = switch (defaultTargetPlatform) { + TargetPlatform.android => LaunchMode.inAppBrowserView, TargetPlatform.iOS => LaunchMode.externalApplication, _ => throw StateError('attempted to test with $defaultTargetPlatform'), - }; + }; check(testBinding.takeLaunchUrlCalls()).single .equals((url: learnMoreButtonUrl, mode: expectedMode)); }, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); testWidgets('only one SingleChildScrollView created', (tester) async { - await prepare(tester); + await prepare(tester); - showErrorDialog(context: context, title: title, message: message); - await tester.pump(); + showErrorDialog(context: context, title: title, message: message); + await tester.pump(); checkErrorDialog(tester, expectedTitle: title, expectedMessage: message); check(find.ancestor(of: find.text(message), @@ -82,48 +82,48 @@ void main() { group('showSuggestedActionDialog', () { testWidgets('tap action button', (tester) async { - addTearDown(testBinding.reset); - await tester.pumpWidget(TestZulipApp()); - await tester.pump(); - final element = tester.element(find.byType(Placeholder)); + addTearDown(testBinding.reset); + await tester.pumpWidget(TestZulipApp()); + await tester.pump(); + final element = tester.element(find.byType(Placeholder)); final dialog = showSuggestedActionDialog(context: element, - title: 'Continue?', - message: 'Do the thing?', + title: 'Continue?', + message: 'Do the thing?', actionButtonText: 'Sure'); - await tester.pump(); - await tester.tap(find.text('Sure')); - await check(dialog.result).completes((it) => it.equals(true)); + await tester.pump(); + await tester.tap(find.text('Sure')); + await check(dialog.result).completes((it) => it.equals(true)); }, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); testWidgets('tap cancel', (tester) async { - addTearDown(testBinding.reset); - await tester.pumpWidget(TestZulipApp()); - await tester.pump(); - final element = tester.element(find.byType(Placeholder)); + addTearDown(testBinding.reset); + await tester.pumpWidget(TestZulipApp()); + await tester.pump(); + final element = tester.element(find.byType(Placeholder)); final dialog = showSuggestedActionDialog(context: element, - title: 'Continue?', - message: 'Do the thing?', + title: 'Continue?', + message: 'Do the thing?', actionButtonText: 'Sure'); - await tester.pump(); - await tester.tap(find.text('Cancel')); - await check(dialog.result).completes((it) => it.equals(null)); + await tester.pump(); + await tester.tap(find.text('Cancel')); + await check(dialog.result).completes((it) => it.equals(null)); }, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); testWidgets('tap outside dialog area', (tester) async { - addTearDown(testBinding.reset); - await tester.pumpWidget(TestZulipApp()); - await tester.pump(); - final element = tester.element(find.byType(Placeholder)); + addTearDown(testBinding.reset); + await tester.pumpWidget(TestZulipApp()); + await tester.pump(); + final element = tester.element(find.byType(Placeholder)); final dialog = showSuggestedActionDialog(context: element, - title: 'Continue?', - message: 'Do the thing?', + title: 'Continue?', + message: 'Do the thing?', actionButtonText: 'Sure'); - await tester.pump(); - await tester.tapAt(tester.getTopLeft(find.byType(TestZulipApp))); - await check(dialog.result).completes((it) => it.equals(null)); + await tester.pump(); + await tester.tapAt(tester.getTopLeft(find.byType(TestZulipApp))); + await check(dialog.result).completes((it) => it.equals(null)); }, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); }); @@ -147,23 +147,77 @@ void main() { // TODO(#1594): test LegacyUpgradeState and BoolGlobalSetting.upgradeWelcomeDialogShown testWidgets('only one SingleChildScrollView created', (tester) async { - final transitionDurationObserver = TransitionDurationObserver(); - addTearDown(testBinding.reset); + final transitionDurationObserver = TransitionDurationObserver(); + addTearDown(testBinding.reset); - // Real ZulipApp needed because the show-dialog function calls - // `await ZulipApp.navigator`. + // Real ZulipApp needed because the show-dialog function calls + // `await ZulipApp.navigator`. await tester.pumpWidget(ZulipApp(navigatorObservers: [transitionDurationObserver])); - await tester.pump(); + await tester.pump(); await testBinding.globalStore.settings .debugSetLegacyUpgradeState(LegacyUpgradeState.found); - UpgradeWelcomeDialog.maybeShow(); - await transitionDurationObserver.pumpPastTransition(tester); + UpgradeWelcomeDialog.maybeShow(); + await transitionDurationObserver.pumpPastTransition(tester); final expectedMessage = 'You’ll find a familiar experience in a faster, sleeker package.'; check(find.ancestor(of: find.text(expectedMessage), matching: find.byType(SingleChildScrollView))).findsOne(); }, variant: TargetPlatformVariant.all()); }); -} + + group('IntroModal', () { + testWidgets('IntroModal widget displays correctly', (tester) async { + addTearDown(testBinding.reset); + await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot()); + + const modal = IntroModal(title: 'Test Title', message: 'Test Message'); + + await tester.pumpWidget(TestZulipApp(child: modal)); + await tester.pumpAndSettle(); + + check(find.text('Test Title')).findsOne(); + check(find.text('Test Message')).findsOne(); + check(find.text('Got it')).findsOne(); + }); + + testWidgets('settings track inbox modal shown state', (tester) async { + addTearDown(testBinding.reset); + check( + testBinding.globalStore.settings.getBool( + BoolGlobalSetting.inboxIntroModalShown, + ), + ).isFalse(); + await testBinding.globalStore.settings.setBool( + BoolGlobalSetting.inboxIntroModalShown, + true, + ); + check( + testBinding.globalStore.settings.getBool( + BoolGlobalSetting.inboxIntroModalShown, + ), + ).isTrue(); + }); + + testWidgets('settings track combined feed modal shown state', ( + tester, + ) async { + addTearDown(testBinding.reset); + check( + testBinding.globalStore.settings.getBool( + BoolGlobalSetting.combinedFeedIntroModalShown, + ), + ).isFalse(); + await testBinding.globalStore.settings.setBool( + BoolGlobalSetting.combinedFeedIntroModalShown, + true, + ); + check( + testBinding.globalStore.settings.getBool( + BoolGlobalSetting.combinedFeedIntroModalShown, + ), + ).isTrue(); + }); + }); +} \ No newline at end of file