From 87affcd455f81aa208c30c1feb9f5d0971ecfd35 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:05:20 +0100 Subject: [PATCH 01/21] feat(l10n): add community config localization keys Adds all necessary English and Arabic localization keys for the new "Community & Engagement" section in the App Configuration page. This includes titles, descriptions, and labels for user engagement, content reporting, and the app feedback funnel, ensuring the UI is fully localized and admin-centric. --- lib/l10n/arb/app_ar.arb | 116 ++++++++++++++++++++++++++++++++++++++++ lib/l10n/arb/app_en.arb | 116 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) diff --git a/lib/l10n/arb/app_ar.arb b/lib/l10n/arb/app_ar.arb index deb7c638..3436d64f 100644 --- a/lib/l10n/arb/app_ar.arb +++ b/lib/l10n/arb/app_ar.arb @@ -2117,5 +2117,121 @@ "appUrlsDescription": "إدارة الروابط الخارجية والداخلية المستخدمة داخل التطبيق.", "@appUrlsDescription": { "description": "وصف قسم روابط التطبيق القابل للتوسيع." + }, + "communityAndEngagementTitle": "المجتمع والمشاركة", + "@communityAndEngagementTitle": { + "description": "عنوان قسم المجتمع والمشاركة القابل للتوسيع." + }, + "communityAndEngagementDescription": "إدارة تفاعلات المستخدمين، والإبلاغ عن المحتوى، ونظام ملاحظات التطبيق الداخلي.", + "@communityAndEngagementDescription": { + "description": "وصف قسم المجتمع والمشاركة القابل للتوسيع." + }, + "userEngagementTitle": "مشاركة المستخدم", + "@userEngagementTitle": { + "description": "عنوان قسم مشاركة المستخدم القابل للتوسيع." + }, + "userEngagementDescription": "تكوين التفاعلات والتعليقات.", + "@userEngagementDescription": { + "description": "وصف قسم مشاركة المستخدم القابل للتوسيع." + }, + "contentReportingTitle": "الإبلاغ عن المحتوى", + "@contentReportingTitle": { + "description": "عنوان قسم الإبلاغ عن المحتوى القابل للتوسيع." + }, + "contentReportingDescription": "ضع قواعد لما يمكن للمستخدمين الإبلاغ عنه.", + "@contentReportingDescription": { + "description": "وصف قسم الإبلاغ عن المحتوى القابل للتوسيع." + }, + "appFeedbackFunnelTitle": "قمع ملاحظات التطبيق", + "@appFeedbackFunnelTitle": { + "description": "عنوان قسم قمع ملاحظات التطبيق القابل للتوسيع." + }, + "appFeedbackFunnelDescription": "إدارة عملية جمع رضا المستخدم وطلب المراجعات اختياريًا.", + "@appFeedbackFunnelDescription": { + "description": "وصف قسم قمع ملاحظات التطبيق القابل للتوسيع." + }, + "enableEngagementFeaturesLabel": "تفعيل ميزات المشاركة", + "@enableEngagementFeaturesLabel": { + "description": "تسمية المفتاح الرئيسي لتفعيل جميع ميزات المشاركة." + }, + "enableEngagementFeaturesDescription": "ينشط أو يعطل عالميًا جميع وظائف التفاعل والتعليق.", + "@enableEngagementFeaturesDescription": { + "description": "وصف المفتاح الرئيسي لتفعيل جميع ميزات المشاركة." + }, + "engagementModeLabel": "وضع المشاركة", + "@engagementModeLabel": { + "description": "تسمية زر وضع المشاركة المقسم." + }, + "engagementModeDescription": "يحدد ما إذا كان يمكن للمستخدمين التفاعل فقط أو إضافة تعليقات أيضًا على المحتوى.", + "@engagementModeDescription": { + "description": "وصف زر وضع المشاركة المقسم." + }, + "engagementModeReactionsOnly": "التفاعلات فقط", + "@engagementModeReactionsOnly": { + "description": "تسمية وضع المشاركة 'التفاعلات فقط'." + }, + "engagementModeReactionsAndComments": "التفاعلات والتعليقات", + "@engagementModeReactionsAndComments": { + "description": "تسمية وضع المشاركة 'التفاعلات والتعليقات'." + }, + "enableReportingSystemLabel": "تفعيل نظام الإبلاغ", + "@enableReportingSystemLabel": { + "description": "تسمية المفتاح الرئيسي لتفعيل نظام الإبلاغ." + }, + "enableReportingSystemDescription": "ينشط أو يعطل عالميًا جميع خيارات الإبلاغ الموجهة للمستخدم.", + "@enableReportingSystemDescription": { + "description": "وصف المفتاح الرئيسي لتفعيل نظام الإبلاغ." + }, + "enableHeadlineReportingLabel": "تفعيل الإبلاغ عن العناوين", + "@enableHeadlineReportingLabel": { + "description": "تسمية مفتاح تفعيل الإبلاغ عن العناوين." + }, + "enableSourceReportingLabel": "تفعيل الإبلاغ عن المصادر", + "@enableSourceReportingLabel": { + "description": "تسمية مفتاح تفعيل الإبلاغ عن المصادر." + }, + "enableCommentReportingLabel": "تفعيل الإبلاغ عن التعليقات", + "@enableCommentReportingLabel": { + "description": "تسمية مفتاح تفعيل الإبلاغ عن التعليقات." + }, + "enableAppFeedbackSystemLabel": "تفعيل نظام ملاحظات التطبيق", + "@enableAppFeedbackSystemLabel": { + "description": "تسمية المفتاح الرئيسي لتفعيل نظام ملاحظات التطبيق." + }, + "enableAppFeedbackSystemDescription": "ينشط النظام الداخلي الذي يسأل المستخدمين بشكل دوري عما إذا كانوا يستمتعون بالتطبيق.", + "@enableAppFeedbackSystemDescription": { + "description": "وصف المفتاح الرئيسي لتفعيل نظام ملاحظات التطبيق." + }, + "positiveInteractionThresholdLabel": "عتبة التفاعل الإيجابي", + "@positiveInteractionThresholdLabel": { + "description": "تسمية حقل إدخال عتبة التفاعل الإيجابي." + }, + "positiveInteractionThresholdDescription": "يحدد عدد الإجراءات الإيجابية (مثل الحفظ، الإعجاب) المطلوبة لتشغيل موجه الاستمتاع. يظهر الموجه في كل مرة يكون فيها إجمالي الإجراءات الإيجابية للمستخدم من مضاعفات هذا الرقم.", + "@positiveInteractionThresholdDescription": { + "description": "وصف حقل إدخال عتبة التفاعل الإيجابي." + }, + "initialPromptCooldownLabel": "فترة تهدئة الموجه الأولي (أيام)", + "@initialPromptCooldownLabel": { + "description": "تسمية حقل إدخال فترة تهدئة الموجه الأولي." + }, + "initialPromptCooldownDescription": "إذا رفض المستخدم الموجه، انتظر هذا العدد من الأيام قبل أن يكون مؤهلاً لرؤيته مرة أخرى. ملاحظة: تتحكم زينة 'تقييم التطبيق' في قسم الموجز في تردد عرضها المنفصل.", + "@initialPromptCooldownDescription": { + "description": "وصف حقل إدخال فترة تهدئة الموجه الأولي." + }, + "requestStoreReviewLabel": "طلب مراجعة المتجر بعد 'نعم'", + "@requestStoreReviewLabel": { + "description": "تسمية مفتاح طلب مراجعة المتجر بعد رد إيجابي." + }, + "requestStoreReviewDescription": "إذا تم التمكين، سيُعرض للمستخدمين الذين يجيبون بـ 'نعم' على موجه الاستمتاع مربع حوار مراجعة متجر نظام التشغيل الرسمي.", + "@requestStoreReviewDescription": { + "description": "وصف مفتاح طلب مراجعة المتجر بعد رد إيجابي." + }, + "requestWrittenFeedbackLabel": "طلب ملاحظات مكتوبة بعد 'لا'", + "@requestWrittenFeedbackLabel": { + "description": "تسمية مفتاح طلب ملاحظات مكتوبة بعد رد سلبي." + }, + "requestWrittenFeedbackDescription": "إذا تم التمكين، سيُطلب من المستخدمين الذين يجيبون بـ 'لا' تقديم ملاحظات مكتوبة مباشرة إلى فريق التطوير.", + "@requestWrittenFeedbackDescription": { + "description": "وصف مفتاح طلب ملاحظات مكتوبة بعد رد سلبي." } } \ No newline at end of file diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 10e5a602..dc7f876a 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -2113,5 +2113,121 @@ "appUrlsDescription": "Manage external and internal URLs used within the application.", "@appUrlsDescription": { "description": "Description for the Application URLs expansion tile." + }, + "communityAndEngagementTitle": "Community & Engagement", + "@communityAndEngagementTitle": { + "description": "Title for the Community & Engagement expansion tile." + }, + "communityAndEngagementDescription": "Manage user interactions, content reporting, and the internal app feedback system.", + "@communityAndEngagementDescription": { + "description": "Description for the Community & Engagement expansion tile." + }, + "userEngagementTitle": "User Engagement", + "@userEngagementTitle": { + "description": "Title for the User Engagement expansion tile." + }, + "userEngagementDescription": "Configure reactions and comments.", + "@userEngagementDescription": { + "description": "Description for the User Engagement expansion tile." + }, + "contentReportingTitle": "Content Reporting", + "@contentReportingTitle": { + "description": "Title for the Content Reporting expansion tile." + }, + "contentReportingDescription": "Set rules for what users can report.", + "@contentReportingDescription": { + "description": "Description for the Content Reporting expansion tile." + }, + "appFeedbackFunnelTitle": "App Feedback Funnel", + "@appFeedbackFunnelTitle": { + "description": "Title for the App Feedback Funnel expansion tile." + }, + "appFeedbackFunnelDescription": "Manage the process for capturing user satisfaction and optionally requesting reviews.", + "@appFeedbackFunnelDescription": { + "description": "Description for the App Feedback Funnel expansion tile." + }, + "enableEngagementFeaturesLabel": "Enable Engagement Features", + "@enableEngagementFeaturesLabel": { + "description": "Label for the master switch to enable all engagement features." + }, + "enableEngagementFeaturesDescription": "Globally activates or deactivates all reaction and comment functionality.", + "@enableEngagementFeaturesDescription": { + "description": "Description for the master switch to enable all engagement features." + }, + "engagementModeLabel": "Engagement Mode", + "@engagementModeLabel": { + "description": "Label for the engagement mode segmented button." + }, + "engagementModeDescription": "Determines if users can only react or also add comments to content.", + "@engagementModeDescription": { + "description": "Description for the engagement mode segmented button." + }, + "engagementModeReactionsOnly": "Reactions Only", + "@engagementModeReactionsOnly": { + "description": "Label for the 'Reactions Only' engagement mode." + }, + "engagementModeReactionsAndComments": "Reactions & Comments", + "@engagementModeReactionsAndComments": { + "description": "Label for the 'Reactions & Comments' engagement mode." + }, + "enableReportingSystemLabel": "Enable Reporting System", + "@enableReportingSystemLabel": { + "description": "Label for the master switch to enable the reporting system." + }, + "enableReportingSystemDescription": "Globally activates or deactivates all user-facing reporting options.", + "@enableReportingSystemDescription": { + "description": "Description for the master switch to enable the reporting system." + }, + "enableHeadlineReportingLabel": "Enable Headline Reporting", + "@enableHeadlineReportingLabel": { + "description": "Label for the switch to enable headline reporting." + }, + "enableSourceReportingLabel": "Enable Source Reporting", + "@enableSourceReportingLabel": { + "description": "Label for the switch to enable source reporting." + }, + "enableCommentReportingLabel": "Enable Comment Reporting", + "@enableCommentReportingLabel": { + "description": "Label for the switch to enable comment reporting." + }, + "enableAppFeedbackSystemLabel": "Enable App Feedback System", + "@enableAppFeedbackSystemLabel": { + "description": "Label for the master switch to enable the app feedback system." + }, + "enableAppFeedbackSystemDescription": "Activates the internal system that periodically asks users if they are enjoying the app.", + "@enableAppFeedbackSystemDescription": { + "description": "Description for the master switch to enable the app feedback system." + }, + "positiveInteractionThresholdLabel": "Positive Interaction Threshold", + "@positiveInteractionThresholdLabel": { + "description": "Label for the positive interaction threshold input field." + }, + "positiveInteractionThresholdDescription": "Defines the number of positive actions (e.g., save, like) required to trigger the enjoyment prompt. The prompt is shown each time the user's total positive actions is a multiple of this number.", + "@positiveInteractionThresholdDescription": { + "description": "Description for the positive interaction threshold input field." + }, + "initialPromptCooldownLabel": "Initial Prompt Cooldown (Days)", + "@initialPromptCooldownLabel": { + "description": "Label for the initial prompt cooldown input field." + }, + "initialPromptCooldownDescription": "If a user dismisses the prompt, wait this many days before they are eligible to see it again. Note: The 'Rate App' decorator in the Feed section controls its own separate display frequency.", + "@initialPromptCooldownDescription": { + "description": "Description for the initial prompt cooldown input field." + }, + "requestStoreReviewLabel": "Request Store Review After 'Yes'", + "@requestStoreReviewLabel": { + "description": "Label for the switch to request a store review after positive feedback." + }, + "requestStoreReviewDescription": "If enabled, users who respond 'Yes' to the enjoyment prompt will be shown the official OS store review dialog.", + "@requestStoreReviewDescription": { + "description": "Description for the switch to request a store review after positive feedback." + }, + "requestWrittenFeedbackLabel": "Request Written Feedback After 'No'", + "@requestWrittenFeedbackLabel": { + "description": "Label for the switch to request written feedback after a negative response." + }, + "requestWrittenFeedbackDescription": "If enabled, users who respond 'No' will be prompted to provide written feedback directly to the team.", + "@requestWrittenFeedbackDescription": { + "description": "Description for the switch to request written feedback after a negative response." } } \ No newline at end of file From 2ada8d882856ebc28cc362363da8a3af9dcc989b Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:05:41 +0100 Subject: [PATCH 02/21] build(l10n): sync --- lib/l10n/app_localizations.dart | 174 +++++++++++++++++++++++++++++ lib/l10n/app_localizations_ar.dart | 98 ++++++++++++++++ lib/l10n/app_localizations_en.dart | 100 +++++++++++++++++ 3 files changed, 372 insertions(+) diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 2d935214..7e81c4ca 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -3145,6 +3145,180 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Manage external and internal URLs used within the application.'** String get appUrlsDescription; + + /// Title for the Community & Engagement expansion tile. + /// + /// In en, this message translates to: + /// **'Community & Engagement'** + String get communityAndEngagementTitle; + + /// Description for the Community & Engagement expansion tile. + /// + /// In en, this message translates to: + /// **'Manage user interactions, content reporting, and the internal app feedback system.'** + String get communityAndEngagementDescription; + + /// Title for the User Engagement expansion tile. + /// + /// In en, this message translates to: + /// **'User Engagement'** + String get userEngagementTitle; + + /// Description for the User Engagement expansion tile. + /// + /// In en, this message translates to: + /// **'Configure reactions and comments.'** + String get userEngagementDescription; + + /// Title for the Content Reporting expansion tile. + /// + /// In en, this message translates to: + /// **'Content Reporting'** + String get contentReportingTitle; + + /// Description for the Content Reporting expansion tile. + /// + /// In en, this message translates to: + /// **'Set rules for what users can report.'** + String get contentReportingDescription; + + /// Title for the App Feedback Funnel expansion tile. + /// + /// In en, this message translates to: + /// **'App Feedback Funnel'** + String get appFeedbackFunnelTitle; + + /// Description for the App Feedback Funnel expansion tile. + /// + /// In en, this message translates to: + /// **'Manage the process for capturing user satisfaction and optionally requesting reviews.'** + String get appFeedbackFunnelDescription; + + /// Label for the master switch to enable all engagement features. + /// + /// In en, this message translates to: + /// **'Enable Engagement Features'** + String get enableEngagementFeaturesLabel; + + /// Description for the master switch to enable all engagement features. + /// + /// In en, this message translates to: + /// **'Globally activates or deactivates all reaction and comment functionality.'** + String get enableEngagementFeaturesDescription; + + /// Label for the engagement mode segmented button. + /// + /// In en, this message translates to: + /// **'Engagement Mode'** + String get engagementModeLabel; + + /// Description for the engagement mode segmented button. + /// + /// In en, this message translates to: + /// **'Determines if users can only react or also add comments to content.'** + String get engagementModeDescription; + + /// Label for the 'Reactions Only' engagement mode. + /// + /// In en, this message translates to: + /// **'Reactions Only'** + String get engagementModeReactionsOnly; + + /// Label for the 'Reactions & Comments' engagement mode. + /// + /// In en, this message translates to: + /// **'Reactions & Comments'** + String get engagementModeReactionsAndComments; + + /// Label for the master switch to enable the reporting system. + /// + /// In en, this message translates to: + /// **'Enable Reporting System'** + String get enableReportingSystemLabel; + + /// Description for the master switch to enable the reporting system. + /// + /// In en, this message translates to: + /// **'Globally activates or deactivates all user-facing reporting options.'** + String get enableReportingSystemDescription; + + /// Label for the switch to enable headline reporting. + /// + /// In en, this message translates to: + /// **'Enable Headline Reporting'** + String get enableHeadlineReportingLabel; + + /// Label for the switch to enable source reporting. + /// + /// In en, this message translates to: + /// **'Enable Source Reporting'** + String get enableSourceReportingLabel; + + /// Label for the switch to enable comment reporting. + /// + /// In en, this message translates to: + /// **'Enable Comment Reporting'** + String get enableCommentReportingLabel; + + /// Label for the master switch to enable the app feedback system. + /// + /// In en, this message translates to: + /// **'Enable App Feedback System'** + String get enableAppFeedbackSystemLabel; + + /// Description for the master switch to enable the app feedback system. + /// + /// In en, this message translates to: + /// **'Activates the internal system that periodically asks users if they are enjoying the app.'** + String get enableAppFeedbackSystemDescription; + + /// Label for the positive interaction threshold input field. + /// + /// In en, this message translates to: + /// **'Positive Interaction Threshold'** + String get positiveInteractionThresholdLabel; + + /// Description for the positive interaction threshold input field. + /// + /// In en, this message translates to: + /// **'Defines the number of positive actions (e.g., save, like) required to trigger the enjoyment prompt. The prompt is shown each time the user\'s total positive actions is a multiple of this number.'** + String get positiveInteractionThresholdDescription; + + /// Label for the initial prompt cooldown input field. + /// + /// In en, this message translates to: + /// **'Initial Prompt Cooldown (Days)'** + String get initialPromptCooldownLabel; + + /// Description for the initial prompt cooldown input field. + /// + /// In en, this message translates to: + /// **'If a user dismisses the prompt, wait this many days before they are eligible to see it again. Note: The \'Rate App\' decorator in the Feed section controls its own separate display frequency.'** + String get initialPromptCooldownDescription; + + /// Label for the switch to request a store review after positive feedback. + /// + /// In en, this message translates to: + /// **'Request Store Review After \'Yes\''** + String get requestStoreReviewLabel; + + /// Description for the switch to request a store review after positive feedback. + /// + /// In en, this message translates to: + /// **'If enabled, users who respond \'Yes\' to the enjoyment prompt will be shown the official OS store review dialog.'** + String get requestStoreReviewDescription; + + /// Label for the switch to request written feedback after a negative response. + /// + /// In en, this message translates to: + /// **'Request Written Feedback After \'No\''** + String get requestWrittenFeedbackLabel; + + /// Description for the switch to request written feedback after a negative response. + /// + /// In en, this message translates to: + /// **'If enabled, users who respond \'No\' will be prompted to provide written feedback directly to the team.'** + String get requestWrittenFeedbackDescription; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart index ef4c2407..f4f8a8ab 100644 --- a/lib/l10n/app_localizations_ar.dart +++ b/lib/l10n/app_localizations_ar.dart @@ -1691,4 +1691,102 @@ class AppLocalizationsAr extends AppLocalizations { @override String get appUrlsDescription => 'إدارة الروابط الخارجية والداخلية المستخدمة داخل التطبيق.'; + + @override + String get communityAndEngagementTitle => 'المجتمع والمشاركة'; + + @override + String get communityAndEngagementDescription => + 'إدارة تفاعلات المستخدمين، والإبلاغ عن المحتوى، ونظام ملاحظات التطبيق الداخلي.'; + + @override + String get userEngagementTitle => 'مشاركة المستخدم'; + + @override + String get userEngagementDescription => 'تكوين التفاعلات والتعليقات.'; + + @override + String get contentReportingTitle => 'الإبلاغ عن المحتوى'; + + @override + String get contentReportingDescription => + 'ضع قواعد لما يمكن للمستخدمين الإبلاغ عنه.'; + + @override + String get appFeedbackFunnelTitle => 'قمع ملاحظات التطبيق'; + + @override + String get appFeedbackFunnelDescription => + 'إدارة عملية جمع رضا المستخدم وطلب المراجعات اختياريًا.'; + + @override + String get enableEngagementFeaturesLabel => 'تفعيل ميزات المشاركة'; + + @override + String get enableEngagementFeaturesDescription => + 'ينشط أو يعطل عالميًا جميع وظائف التفاعل والتعليق.'; + + @override + String get engagementModeLabel => 'وضع المشاركة'; + + @override + String get engagementModeDescription => + 'يحدد ما إذا كان يمكن للمستخدمين التفاعل فقط أو إضافة تعليقات أيضًا على المحتوى.'; + + @override + String get engagementModeReactionsOnly => 'التفاعلات فقط'; + + @override + String get engagementModeReactionsAndComments => 'التفاعلات والتعليقات'; + + @override + String get enableReportingSystemLabel => 'تفعيل نظام الإبلاغ'; + + @override + String get enableReportingSystemDescription => + 'ينشط أو يعطل عالميًا جميع خيارات الإبلاغ الموجهة للمستخدم.'; + + @override + String get enableHeadlineReportingLabel => 'تفعيل الإبلاغ عن العناوين'; + + @override + String get enableSourceReportingLabel => 'تفعيل الإبلاغ عن المصادر'; + + @override + String get enableCommentReportingLabel => 'تفعيل الإبلاغ عن التعليقات'; + + @override + String get enableAppFeedbackSystemLabel => 'تفعيل نظام ملاحظات التطبيق'; + + @override + String get enableAppFeedbackSystemDescription => + 'ينشط النظام الداخلي الذي يسأل المستخدمين بشكل دوري عما إذا كانوا يستمتعون بالتطبيق.'; + + @override + String get positiveInteractionThresholdLabel => 'عتبة التفاعل الإيجابي'; + + @override + String get positiveInteractionThresholdDescription => + 'يحدد عدد الإجراءات الإيجابية (مثل الحفظ، الإعجاب) المطلوبة لتشغيل موجه الاستمتاع. يظهر الموجه في كل مرة يكون فيها إجمالي الإجراءات الإيجابية للمستخدم من مضاعفات هذا الرقم.'; + + @override + String get initialPromptCooldownLabel => 'فترة تهدئة الموجه الأولي (أيام)'; + + @override + String get initialPromptCooldownDescription => + 'إذا رفض المستخدم الموجه، انتظر هذا العدد من الأيام قبل أن يكون مؤهلاً لرؤيته مرة أخرى. ملاحظة: تتحكم زينة \'تقييم التطبيق\' في قسم الموجز في تردد عرضها المنفصل.'; + + @override + String get requestStoreReviewLabel => 'طلب مراجعة المتجر بعد \'نعم\''; + + @override + String get requestStoreReviewDescription => + 'إذا تم التمكين، سيُعرض للمستخدمين الذين يجيبون بـ \'نعم\' على موجه الاستمتاع مربع حوار مراجعة متجر نظام التشغيل الرسمي.'; + + @override + String get requestWrittenFeedbackLabel => 'طلب ملاحظات مكتوبة بعد \'لا\''; + + @override + String get requestWrittenFeedbackDescription => + 'إذا تم التمكين، سيُطلب من المستخدمين الذين يجيبون بـ \'لا\' تقديم ملاحظات مكتوبة مباشرة إلى فريق التطوير.'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 279785d4..3dca17b2 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1694,4 +1694,104 @@ class AppLocalizationsEn extends AppLocalizations { @override String get appUrlsDescription => 'Manage external and internal URLs used within the application.'; + + @override + String get communityAndEngagementTitle => 'Community & Engagement'; + + @override + String get communityAndEngagementDescription => + 'Manage user interactions, content reporting, and the internal app feedback system.'; + + @override + String get userEngagementTitle => 'User Engagement'; + + @override + String get userEngagementDescription => 'Configure reactions and comments.'; + + @override + String get contentReportingTitle => 'Content Reporting'; + + @override + String get contentReportingDescription => + 'Set rules for what users can report.'; + + @override + String get appFeedbackFunnelTitle => 'App Feedback Funnel'; + + @override + String get appFeedbackFunnelDescription => + 'Manage the process for capturing user satisfaction and optionally requesting reviews.'; + + @override + String get enableEngagementFeaturesLabel => 'Enable Engagement Features'; + + @override + String get enableEngagementFeaturesDescription => + 'Globally activates or deactivates all reaction and comment functionality.'; + + @override + String get engagementModeLabel => 'Engagement Mode'; + + @override + String get engagementModeDescription => + 'Determines if users can only react or also add comments to content.'; + + @override + String get engagementModeReactionsOnly => 'Reactions Only'; + + @override + String get engagementModeReactionsAndComments => 'Reactions & Comments'; + + @override + String get enableReportingSystemLabel => 'Enable Reporting System'; + + @override + String get enableReportingSystemDescription => + 'Globally activates or deactivates all user-facing reporting options.'; + + @override + String get enableHeadlineReportingLabel => 'Enable Headline Reporting'; + + @override + String get enableSourceReportingLabel => 'Enable Source Reporting'; + + @override + String get enableCommentReportingLabel => 'Enable Comment Reporting'; + + @override + String get enableAppFeedbackSystemLabel => 'Enable App Feedback System'; + + @override + String get enableAppFeedbackSystemDescription => + 'Activates the internal system that periodically asks users if they are enjoying the app.'; + + @override + String get positiveInteractionThresholdLabel => + 'Positive Interaction Threshold'; + + @override + String get positiveInteractionThresholdDescription => + 'Defines the number of positive actions (e.g., save, like) required to trigger the enjoyment prompt. The prompt is shown each time the user\'s total positive actions is a multiple of this number.'; + + @override + String get initialPromptCooldownLabel => 'Initial Prompt Cooldown (Days)'; + + @override + String get initialPromptCooldownDescription => + 'If a user dismisses the prompt, wait this many days before they are eligible to see it again. Note: The \'Rate App\' decorator in the Feed section controls its own separate display frequency.'; + + @override + String get requestStoreReviewLabel => 'Request Store Review After \'Yes\''; + + @override + String get requestStoreReviewDescription => + 'If enabled, users who respond \'Yes\' to the enjoyment prompt will be shown the official OS store review dialog.'; + + @override + String get requestWrittenFeedbackLabel => + 'Request Written Feedback After \'No\''; + + @override + String get requestWrittenFeedbackDescription => + 'If enabled, users who respond \'No\' will be prompted to provide written feedback directly to the team.'; } From 3ce025dddf14c7dcd07b2a20031ed7d65cbba5fc Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:05:59 +0100 Subject: [PATCH 03/21] feat(l10n): create EngagementMode localization extension Introduces a new extension `EngagementModeL10n` to provide localized string representations for the `EngagementMode` enum values. This centralizes localization logic for the enum, making it reusable and consistent across the UI. --- lib/shared/extensions/engagement_mode_l10n.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 lib/shared/extensions/engagement_mode_l10n.dart diff --git a/lib/shared/extensions/engagement_mode_l10n.dart b/lib/shared/extensions/engagement_mode_l10n.dart new file mode 100644 index 00000000..6aa54cff --- /dev/null +++ b/lib/shared/extensions/engagement_mode_l10n.dart @@ -0,0 +1,17 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart'; + +/// Extension to localize the [EngagementMode] enum. +extension EngagementModeL10n on EngagementMode { + /// Returns the localized string representation of the [EngagementMode]. + String l10n(BuildContext context) { + final l10n = AppLocalizationsX(context).l10n; + switch (this) { + case EngagementMode.reactionsOnly: + return l10n.engagementModeReactionsOnly; + case EngagementMode.reactionsAndComments: + return l10n.engagementModeReactionsAndComments; + } + } +} From 7ffc3ba69af657783b5ebb1726765966444d93cd Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:06:32 +0100 Subject: [PATCH 04/21] feat(config): create app review settings form widget Introduces the `AppReviewSettingsForm`, a self-contained widget for managing the `AppReviewConfig`. It provides UI controls for enabling the feedback system, setting the positive interaction threshold, and configuring follow-up actions, guided by descriptive text that clarifies the two-layer feedback funnel logic. --- .../widgets/app_review_settings_form.dart | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 lib/app_configuration/widgets/app_review_settings_form.dart diff --git a/lib/app_configuration/widgets/app_review_settings_form.dart b/lib/app_configuration/widgets/app_review_settings_form.dart new file mode 100644 index 00000000..df6ccdde --- /dev/null +++ b/lib/app_configuration/widgets/app_review_settings_form.dart @@ -0,0 +1,144 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/app_config_form_fields.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart'; +import 'package:ui_kit/ui_kit.dart'; + +/// {@template app_review_settings_form} +/// A form widget for configuring app review funnel settings. +/// {@endtemplate} +class AppReviewSettingsForm extends StatefulWidget { + /// {@macro app_review_settings_form} + const AppReviewSettingsForm({ + required this.remoteConfig, + required this.onConfigChanged, + super.key, + }); + + /// The current [RemoteConfig] object. + final RemoteConfig remoteConfig; + + /// Callback to notify parent of changes to the [RemoteConfig]. + final ValueChanged onConfigChanged; + + @override + State createState() => _AppReviewSettingsFormState(); +} + +class _AppReviewSettingsFormState extends State { + late final TextEditingController _positiveInteractionThresholdController; + late final TextEditingController _initialPromptCooldownController; + + @override + void initState() { + super.initState(); + _initializeControllers(); + } + + @override + void didUpdateWidget(covariant AppReviewSettingsForm oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.remoteConfig.features.community.appReview != + oldWidget.remoteConfig.features.community.appReview) { + _updateControllers(); + } + } + + void _initializeControllers() { + final appReviewConfig = widget.remoteConfig.features.community.appReview; + _positiveInteractionThresholdController = TextEditingController( + text: appReviewConfig.positiveInteractionThreshold.toString(), + ); + _initialPromptCooldownController = TextEditingController( + text: appReviewConfig.initialPromptCooldownDays.toString(), + ); + } + + void _updateControllers() { + final appReviewConfig = widget.remoteConfig.features.community.appReview; + _positiveInteractionThresholdController.text = appReviewConfig + .positiveInteractionThreshold + .toString(); + _initialPromptCooldownController.text = appReviewConfig + .initialPromptCooldownDays + .toString(); + } + + @override + void dispose() { + _positiveInteractionThresholdController.dispose(); + _initialPromptCooldownController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizationsX(context).l10n; + final communityConfig = widget.remoteConfig.features.community; + final appReviewConfig = communityConfig.appReview; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SwitchListTile( + title: Text(l10n.enableAppFeedbackSystemLabel), + subtitle: Text(l10n.enableAppFeedbackSystemDescription), + value: appReviewConfig.enabled, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith(enabled: value), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, + ), + const SizedBox(height: AppSpacing.lg), + AppConfigIntField( + label: l10n.positiveInteractionThresholdLabel, + description: l10n.positiveInteractionThresholdDescription, + value: appReviewConfig.positiveInteractionThreshold, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith( + positiveInteractionThreshold: value, + ), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, + controller: _positiveInteractionThresholdController, + ), + AppConfigIntField( + label: l10n.initialPromptCooldownLabel, + description: l10n.initialPromptCooldownDescription, + value: appReviewConfig.initialPromptCooldownDays, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith( + initialPromptCooldownDays: value, + ), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, + controller: _initialPromptCooldownController, + ), + ], + ); + } +} From 2bc554e1be7b0ce370cd1b0077383d28b1163494 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:06:54 +0100 Subject: [PATCH 05/21] feat(config): create reporting settings form widget Introduces the `ReportingSettingsForm`, a widget for managing the `ReportingConfig`. It includes a master toggle for the reporting system and individual switches for enabling/disabling reporting on headlines, sources, and comments, providing granular control. --- .../widgets/reporting_settings_form.dart | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 lib/app_configuration/widgets/reporting_settings_form.dart diff --git a/lib/app_configuration/widgets/reporting_settings_form.dart b/lib/app_configuration/widgets/reporting_settings_form.dart new file mode 100644 index 00000000..d715900a --- /dev/null +++ b/lib/app_configuration/widgets/reporting_settings_form.dart @@ -0,0 +1,94 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart'; +import 'package:ui_kit/ui_kit.dart'; + +/// {@template reporting_settings_form} +/// A form widget for configuring content reporting settings. +/// {@endtemplate} +class ReportingSettingsForm extends StatelessWidget { + /// {@macro reporting_settings_form} + const ReportingSettingsForm({ + required this.remoteConfig, + required this.onConfigChanged, + super.key, + }); + + /// The current [RemoteConfig] object. + final RemoteConfig remoteConfig; + + /// Callback to notify parent of changes to the [RemoteConfig]. + final ValueChanged onConfigChanged; + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizationsX(context).l10n; + final communityConfig = remoteConfig.features.community; + final reportingConfig = communityConfig.reporting; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SwitchListTile( + title: Text(l10n.enableReportingSystemLabel), + subtitle: Text(l10n.enableReportingSystemDescription), + value: reportingConfig.enabled, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + reporting: reportingConfig.copyWith(enabled: value), + ); + onConfigChanged( + remoteConfig.copyWith( + features: remoteConfig.features.copyWith(community: newConfig), + ), + ); + }, + ), + const SizedBox(height: AppSpacing.lg), + Padding( + padding: const EdgeInsetsDirectional.only(start: AppSpacing.lg), + child: Column( + children: [ + SwitchListTile( + title: Text(l10n.enableHeadlineReportingLabel), + value: reportingConfig.headlineReportingEnabled, + onChanged: (value) { + final newConfig = reportingConfig.copyWith( + headlineReportingEnabled: value, + ); + onConfigChanged( + remoteConfig.copyWith( + features: remoteConfig.features.copyWith( + community: communityConfig.copyWith( + reporting: newConfig, + ), + ), + ), + ); + }, + ), + SwitchListTile( + title: Text(l10n.enableCommentReportingLabel), + value: reportingConfig.commentReportingEnabled, + onChanged: (value) { + final newConfig = reportingConfig.copyWith( + commentReportingEnabled: value, + ); + onConfigChanged( + remoteConfig.copyWith( + features: remoteConfig.features.copyWith( + community: communityConfig.copyWith( + reporting: newConfig, + ), + ), + ), + ); + }, + ), + ], + ), + ), + ], + ); + } +} From 16efe2dbf9f7500efc1c42b9592f54fbb22c026f Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:07:57 +0100 Subject: [PATCH 06/21] feat(config): create main community config form widget Introduces `CommunityConfigForm`, a container widget that orchestrates the community settings UI. It composes the `EngagementSettingsForm`, `ReportingSettingsForm`, and `AppReviewSettingsForm` into a series of nested, descriptive `ExpansionTile`s, creating a clear and hierarchical user interface for administrators. --- .../widgets/community_config_form.dart | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 lib/app_configuration/widgets/community_config_form.dart diff --git a/lib/app_configuration/widgets/community_config_form.dart b/lib/app_configuration/widgets/community_config_form.dart new file mode 100644 index 00000000..b931dae2 --- /dev/null +++ b/lib/app_configuration/widgets/community_config_form.dart @@ -0,0 +1,84 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/app_review_settings_form.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/engagement_settings_form.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/reporting_settings_form.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart'; +import 'package:ui_kit/ui_kit.dart'; + +/// {@template community_config_form} +/// A form widget for configuring all community-related settings. +/// +/// This widget acts as a container for more specific forms like +/// [EngagementSettingsForm], [ReportingSettingsForm], and +/// [AppReviewSettingsForm], organizing them into nested [ExpansionTile]s. +/// {@endtemplate} +class CommunityConfigForm extends StatelessWidget { + /// {@macro community_config_form} + const CommunityConfigForm({ + required this.remoteConfig, + required this.onConfigChanged, + super.key, + }); + + /// The current [RemoteConfig] object. + final RemoteConfig remoteConfig; + + /// Callback to notify parent of changes to the [RemoteConfig]. + final ValueChanged onConfigChanged; + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizationsX(context).l10n; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ExpansionTile( + title: Text(l10n.userEngagementTitle), + subtitle: Text(l10n.userEngagementDescription), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + EngagementSettingsForm( + remoteConfig: remoteConfig, + onConfigChanged: onConfigChanged, + ), + ], + ), + const SizedBox(height: AppSpacing.lg), + ExpansionTile( + title: Text(l10n.contentReportingTitle), + subtitle: Text(l10n.contentReportingDescription), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + ReportingSettingsForm( + remoteConfig: remoteConfig, + onConfigChanged: onConfigChanged, + ), + ], + ), + const SizedBox(height: AppSpacing.lg), + ExpansionTile( + title: Text(l10n.appFeedbackFunnelTitle), + subtitle: Text(l10n.appFeedbackFunnelDescription), + children: [ + AppReviewSettingsForm( + remoteConfig: remoteConfig, + onConfigChanged: onConfigChanged, + ), + ], + ), + ], + ); + } +} From 3adde5e874863316e9e6310e2d92f9f19dbcb74e Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:08:23 +0100 Subject: [PATCH 07/21] feat(config): integrate community config form into features tab Integrates the newly created `CommunityConfigForm` into the `FeaturesConfigurationTab`. A new top-level `ExpansionTile` labeled "Community & Engagement" is added to the main list, which houses the form. This change maintains the existing single-expansion UX pattern by leveraging the shared `_expandedTileIndex` ValueNotifier. --- .../view/tabs/features_configuration_tab.dart | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/app_configuration/view/tabs/features_configuration_tab.dart b/lib/app_configuration/view/tabs/features_configuration_tab.dart index 18a17739..ac173ec2 100644 --- a/lib/app_configuration/view/tabs/features_configuration_tab.dart +++ b/lib/app_configuration/view/tabs/features_configuration_tab.dart @@ -2,6 +2,7 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/ad_config_form.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/ad_platform_config_form.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/community_config_form.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/feed_ad_settings_form.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/feed_decorator_form.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/navigation_ad_settings_form.dart'; @@ -244,6 +245,36 @@ class _FeaturesConfigurationTabState extends State { ); }, ), + const SizedBox(height: AppSpacing.lg), + + // Community & Engagement + ValueListenableBuilder( + valueListenable: _expandedTileIndex, + builder: (context, expandedIndex, child) { + const tileIndex = 3; + return ExpansionTile( + key: ValueKey('communityTile_$expandedIndex'), + title: Text(l10n.communityAndEngagementTitle), + subtitle: Text(l10n.communityAndEngagementDescription), + onExpansionChanged: (isExpanded) { + _expandedTileIndex.value = isExpanded ? tileIndex : null; + }, + initiallyExpanded: expandedIndex == tileIndex, + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + CommunityConfigForm( + remoteConfig: widget.remoteConfig, + onConfigChanged: widget.onConfigChanged, + ), + ], + ); + }, + ), ], ); } From 895796c04dd4a52bd27bde2d2f71124874c3ce28 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:08:53 +0100 Subject: [PATCH 08/21] feat(config): create engagement settings form widget Introduces the `EngagementSettingsForm` for managing the `EngagementConfig`. This widget provides a master toggle for the engagement system and a `SegmentedButton` to switch between 'Reactions Only' and 'Reactions & Comments' modes, abstracting the engagement logic into a dedicated UI component. --- .../widgets/engagement_settings_form.dart | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 lib/app_configuration/widgets/engagement_settings_form.dart diff --git a/lib/app_configuration/widgets/engagement_settings_form.dart b/lib/app_configuration/widgets/engagement_settings_form.dart new file mode 100644 index 00000000..4a370020 --- /dev/null +++ b/lib/app_configuration/widgets/engagement_settings_form.dart @@ -0,0 +1,88 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/shared/extensions/engagement_mode_l10n.dart'; +import 'package:ui_kit/ui_kit.dart'; + +/// {@template engagement_settings_form} +/// A form widget for configuring user engagement settings. +/// {@endtemplate} +class EngagementSettingsForm extends StatelessWidget { + /// {@macro engagement_settings_form} + const EngagementSettingsForm({ + required this.remoteConfig, + required this.onConfigChanged, + super.key, + }); + + /// The current [RemoteConfig] object. + final RemoteConfig remoteConfig; + + /// Callback to notify parent of changes to the [RemoteConfig]. + final ValueChanged onConfigChanged; + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizationsX(context).l10n; + final communityConfig = remoteConfig.features.community; + final engagementConfig = communityConfig.engagement; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SwitchListTile( + title: Text(l10n.enableEngagementFeaturesLabel), + subtitle: Text(l10n.enableEngagementFeaturesDescription), + value: engagementConfig.enabled, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + engagement: engagementConfig.copyWith(enabled: value), + ); + onConfigChanged( + remoteConfig.copyWith( + features: remoteConfig.features.copyWith(community: newConfig), + ), + ); + }, + ), + const SizedBox(height: AppSpacing.lg), + Padding( + padding: const EdgeInsets.symmetric(horizontal: AppSpacing.lg), + child: Text( + l10n.engagementModeDescription, + style: Theme.of(context).textTheme.bodySmall, + ), + ), + const SizedBox(height: AppSpacing.md), + Padding( + padding: const EdgeInsets.symmetric(horizontal: AppSpacing.lg), + child: SegmentedButton( + segments: EngagementMode.values + .map( + (mode) => ButtonSegment( + value: mode, + label: Text(mode.l10n(context)), + ), + ) + .toList(), + selected: {engagementConfig.engagementMode}, + onSelectionChanged: (newSelection) { + final newConfig = communityConfig.copyWith( + engagement: engagementConfig.copyWith( + engagementMode: newSelection.first, + ), + ); + onConfigChanged( + remoteConfig.copyWith( + features: remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, + ), + ), + ], + ); + } +} From ccb76fd6050eece9cb1ab27532a93c919559f151 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:28:17 +0100 Subject: [PATCH 09/21] chore(deps): update core package reference - Updated core package reference from 3779a8b to a960fe8 in pubspec.yaml - Updated corresponding reference in pubspec.lock --- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 489f590e..16c1b196 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -89,8 +89,8 @@ packages: dependency: "direct main" description: path: "." - ref: "3779a8b1dbd8450d524574cf5376b7cc2ed514e7" - resolved-ref: "3779a8b1dbd8450d524574cf5376b7cc2ed514e7" + ref: a960fe8f340fc8b74b651997de45aee10d8435aa + resolved-ref: a960fe8f340fc8b74b651997de45aee10d8435aa url: "https://github.com/flutter-news-app-full-source-code/core.git" source: git version: "1.3.1" diff --git a/pubspec.yaml b/pubspec.yaml index 10824d60..c86f6508 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -94,7 +94,7 @@ dependency_overrides: core: git: url: https://github.com/flutter-news-app-full-source-code/core.git - ref: 3779a8b1dbd8450d524574cf5376b7cc2ed514e7 + ref: a960fe8f340fc8b74b651997de45aee10d8435aa http_client: git: url: https://github.com/flutter-news-app-full-source-code/http-client.git From ea6bef405eb65676f89e45719db237cc65e74bde Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:28:30 +0100 Subject: [PATCH 10/21] fix(data): update fixture data initialization with language code - Replace static fixture data with language-specific data for headlines, topics, and sources - Modify DataInMemory initialization to use getHeadlinesFixturesData, getTopicsFixturesData, and getSourcesFixturesData with 'en' language code --- lib/bootstrap.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/bootstrap.dart b/lib/bootstrap.dart index 713b945e..962ca7d4 100644 --- a/lib/bootstrap.dart +++ b/lib/bootstrap.dart @@ -70,19 +70,19 @@ Future bootstrap( headlinesClient = DataInMemory( toJson: (i) => i.toJson(), getId: (i) => i.id, - initialData: headlinesFixturesData, + initialData: getHeadlinesFixturesData(languageCode: 'en'), logger: Logger('DataInMemory'), ); topicsClient = DataInMemory( toJson: (i) => i.toJson(), getId: (i) => i.id, - initialData: topicsFixturesData, + initialData: getTopicsFixturesData(languageCode: 'en'), logger: Logger('DataInMemory'), ); sourcesClient = DataInMemory( toJson: (i) => i.toJson(), getId: (i) => i.id, - initialData: sourcesFixturesData, + initialData: getSourcesFixturesData(languageCode: 'en'), logger: Logger('DataInMemory'), ); userContentPreferencesClient = DataInMemory( From 2e8c039b82409bbb837994691ae9da1b6d32d406 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:49:09 +0100 Subject: [PATCH 11/21] feat(app_configuration): add expansion tiles for app review settings - Add ExpansionTile for internal prompt logic settings - Add ExpansionTile for follow-up actions settings - Move positive interaction threshold and initial prompt cooldown fields inside the new tiles - Add switches for requesting store review and written feedback in the follow-up actions tile --- .../widgets/app_review_settings_form.dart | 137 +++++++++++++----- 1 file changed, 99 insertions(+), 38 deletions(-) diff --git a/lib/app_configuration/widgets/app_review_settings_form.dart b/lib/app_configuration/widgets/app_review_settings_form.dart index df6ccdde..14703149 100644 --- a/lib/app_configuration/widgets/app_review_settings_form.dart +++ b/lib/app_configuration/widgets/app_review_settings_form.dart @@ -98,45 +98,106 @@ class _AppReviewSettingsFormState extends State { }, ), const SizedBox(height: AppSpacing.lg), - AppConfigIntField( - label: l10n.positiveInteractionThresholdLabel, - description: l10n.positiveInteractionThresholdDescription, - value: appReviewConfig.positiveInteractionThreshold, - onChanged: (value) { - final newConfig = communityConfig.copyWith( - appReview: appReviewConfig.copyWith( - positiveInteractionThreshold: value, - ), - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: newConfig, - ), - ), - ); - }, - controller: _positiveInteractionThresholdController, + ExpansionTile( + title: Text(l10n.internalPromptLogicTitle), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppConfigIntField( + label: l10n.positiveInteractionThresholdLabel, + description: l10n.positiveInteractionThresholdDescription, + value: appReviewConfig.positiveInteractionThreshold, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith( + positiveInteractionThreshold: value, + ), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, + controller: _positiveInteractionThresholdController, + ), + AppConfigIntField( + label: l10n.initialPromptCooldownLabel, + description: l10n.initialPromptCooldownDescription, + value: appReviewConfig.initialPromptCooldownDays, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith( + initialPromptCooldownDays: value, + ), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, + controller: _initialPromptCooldownController, + ), + ], ), - AppConfigIntField( - label: l10n.initialPromptCooldownLabel, - description: l10n.initialPromptCooldownDescription, - value: appReviewConfig.initialPromptCooldownDays, - onChanged: (value) { - final newConfig = communityConfig.copyWith( - appReview: appReviewConfig.copyWith( - initialPromptCooldownDays: value, - ), - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: newConfig, - ), - ), - ); - }, - controller: _initialPromptCooldownController, + const SizedBox(height: AppSpacing.lg), + ExpansionTile( + title: Text(l10n.followUpActionsTitle), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + SwitchListTile( + title: Text(l10n.requestStoreReviewLabel), + subtitle: Text(l10n.requestStoreReviewDescription), + value: appReviewConfig.isPositiveFeedbackFollowUpEnabled, + onChanged: (value) { + final newAppReviewConfig = appReviewConfig.copyWith( + isPositiveFeedbackFollowUpEnabled: value, + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: communityConfig.copyWith( + appReview: newAppReviewConfig, + ), + ), + ), + ); + }, + ), + SwitchListTile( + title: Text(l10n.requestWrittenFeedbackLabel), + subtitle: Text(l10n.requestWrittenFeedbackDescription), + value: appReviewConfig.isNegativeFeedbackFollowUpEnabled, + onChanged: (value) { + final newAppReviewConfig = appReviewConfig.copyWith( + isNegativeFeedbackFollowUpEnabled: value, + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: communityConfig.copyWith( + appReview: newAppReviewConfig, + ), + ), + ), + ); + }, + ), + ], ), ], ); From f4da20f3ff77de6d22ee18449f97ccd232b4aede Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:49:45 +0100 Subject: [PATCH 12/21] feat(l10n): add arb entries for internal prompt logic and follow-up actions - Add Arabic and English entries for "internalPromptLogicTitle" and "followUpActionsTitle" - Include descriptions for new entries to facilitate translation and understanding of context --- lib/l10n/arb/app_ar.arb | 8 ++++++++ lib/l10n/arb/app_en.arb | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/l10n/arb/app_ar.arb b/lib/l10n/arb/app_ar.arb index 3436d64f..0381466a 100644 --- a/lib/l10n/arb/app_ar.arb +++ b/lib/l10n/arb/app_ar.arb @@ -2233,5 +2233,13 @@ "requestWrittenFeedbackDescription": "إذا تم التمكين، سيُطلب من المستخدمين الذين يجيبون بـ 'لا' تقديم ملاحظات مكتوبة مباشرة إلى فريق التطوير.", "@requestWrittenFeedbackDescription": { "description": "وصف مفتاح طلب ملاحظات مكتوبة بعد رد سلبي." + }, + "internalPromptLogicTitle": "منطق الموجه الداخلي", + "@internalPromptLogicTitle": { + "description": "عنوان قسم منطق الموجه الداخلي لمراجعة التطبيق." + }, + "followUpActionsTitle": "إجراءات المتابعة", + "@followUpActionsTitle": { + "description": "عنوان قسم إجراءات المتابعة لمراجعة التطبيق." } } \ No newline at end of file diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index dc7f876a..564adba4 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -2229,5 +2229,13 @@ "requestWrittenFeedbackDescription": "If enabled, users who respond 'No' will be prompted to provide written feedback directly to the team.", "@requestWrittenFeedbackDescription": { "description": "Description for the switch to request written feedback after a negative response." + }, + "internalPromptLogicTitle": "Internal Prompt Logic", + "@internalPromptLogicTitle": { + "description": "Title for the nested expansion tile for internal app review prompt settings." + }, + "followUpActionsTitle": "Follow-up Actions", + "@followUpActionsTitle": { + "description": "Title for the nested expansion tile for app review follow-up actions." } } \ No newline at end of file From 2cd4585d99e6ac7946bb3edf5c80e56e8ee7ac7f Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:49:59 +0100 Subject: [PATCH 13/21] build(l10n): sync --- lib/l10n/app_localizations.dart | 12 ++++++++++++ lib/l10n/app_localizations_ar.dart | 6 ++++++ lib/l10n/app_localizations_en.dart | 6 ++++++ 3 files changed, 24 insertions(+) diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 7e81c4ca..b57c1ffd 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -3319,6 +3319,18 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'If enabled, users who respond \'No\' will be prompted to provide written feedback directly to the team.'** String get requestWrittenFeedbackDescription; + + /// Title for the nested expansion tile for internal app review prompt settings. + /// + /// In en, this message translates to: + /// **'Internal Prompt Logic'** + String get internalPromptLogicTitle; + + /// Title for the nested expansion tile for app review follow-up actions. + /// + /// In en, this message translates to: + /// **'Follow-up Actions'** + String get followUpActionsTitle; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart index f4f8a8ab..3693b001 100644 --- a/lib/l10n/app_localizations_ar.dart +++ b/lib/l10n/app_localizations_ar.dart @@ -1789,4 +1789,10 @@ class AppLocalizationsAr extends AppLocalizations { @override String get requestWrittenFeedbackDescription => 'إذا تم التمكين، سيُطلب من المستخدمين الذين يجيبون بـ \'لا\' تقديم ملاحظات مكتوبة مباشرة إلى فريق التطوير.'; + + @override + String get internalPromptLogicTitle => 'منطق الموجه الداخلي'; + + @override + String get followUpActionsTitle => 'إجراءات المتابعة'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 3dca17b2..25068186 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1794,4 +1794,10 @@ class AppLocalizationsEn extends AppLocalizations { @override String get requestWrittenFeedbackDescription => 'If enabled, users who respond \'No\' will be prompted to provide written feedback directly to the team.'; + + @override + String get internalPromptLogicTitle => 'Internal Prompt Logic'; + + @override + String get followUpActionsTitle => 'Follow-up Actions'; } From 9311cf93e133d7cd378661d3c70ca86bf287c04e Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:52:00 +0100 Subject: [PATCH 14/21] style(app_configuration): adjust subtitle text style for better visibility - Update subtitle text style in FeaturesConfigurationTab and CommunityConfigForm - Apply onSurface color with 0.7 opacity for better contrast and readability - Extract subtitle style to a variable for reuse and consistency --- .../view/tabs/features_configuration_tab.dart | 9 ++++++++- .../widgets/community_config_form.dart | 18 +++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/app_configuration/view/tabs/features_configuration_tab.dart b/lib/app_configuration/view/tabs/features_configuration_tab.dart index ac173ec2..96fbf462 100644 --- a/lib/app_configuration/view/tabs/features_configuration_tab.dart +++ b/lib/app_configuration/view/tabs/features_configuration_tab.dart @@ -255,7 +255,14 @@ class _FeaturesConfigurationTabState extends State { return ExpansionTile( key: ValueKey('communityTile_$expandedIndex'), title: Text(l10n.communityAndEngagementTitle), - subtitle: Text(l10n.communityAndEngagementDescription), + subtitle: Text( + l10n.communityAndEngagementDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), onExpansionChanged: (isExpanded) { _expandedTileIndex.value = isExpanded ? tileIndex : null; }, diff --git a/lib/app_configuration/widgets/community_config_form.dart b/lib/app_configuration/widgets/community_config_form.dart index b931dae2..b79078b4 100644 --- a/lib/app_configuration/widgets/community_config_form.dart +++ b/lib/app_configuration/widgets/community_config_form.dart @@ -30,13 +30,19 @@ class CommunityConfigForm extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = AppLocalizationsX(context).l10n; + final subtitleStyle = Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ExpansionTile( title: Text(l10n.userEngagementTitle), - subtitle: Text(l10n.userEngagementDescription), + subtitle: Text( + l10n.userEngagementDescription, + style: subtitleStyle, + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -53,7 +59,10 @@ class CommunityConfigForm extends StatelessWidget { const SizedBox(height: AppSpacing.lg), ExpansionTile( title: Text(l10n.contentReportingTitle), - subtitle: Text(l10n.contentReportingDescription), + subtitle: Text( + l10n.contentReportingDescription, + style: subtitleStyle, + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -70,7 +79,10 @@ class CommunityConfigForm extends StatelessWidget { const SizedBox(height: AppSpacing.lg), ExpansionTile( title: Text(l10n.appFeedbackFunnelTitle), - subtitle: Text(l10n.appFeedbackFunnelDescription), + subtitle: Text( + l10n.appFeedbackFunnelDescription, + style: subtitleStyle, + ), children: [ AppReviewSettingsForm( remoteConfig: remoteConfig, From 9fc036154bf3389fc67cf8663997d6b1542f7ef8 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 04:55:47 +0100 Subject: [PATCH 15/21] refactor(app_configuration): conditionally show app review settings - Wrap app review settings in a Padding widget - Display app review settings only if appReviewConfig.enabled is true - Adjust layout structure to improve readability and maintainability --- .../widgets/app_review_settings_form.dart | 196 +++++++++--------- 1 file changed, 102 insertions(+), 94 deletions(-) diff --git a/lib/app_configuration/widgets/app_review_settings_form.dart b/lib/app_configuration/widgets/app_review_settings_form.dart index 14703149..ad303e8f 100644 --- a/lib/app_configuration/widgets/app_review_settings_form.dart +++ b/lib/app_configuration/widgets/app_review_settings_form.dart @@ -98,107 +98,115 @@ class _AppReviewSettingsFormState extends State { }, ), const SizedBox(height: AppSpacing.lg), - ExpansionTile( - title: Text(l10n.internalPromptLogicTitle), - childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, - top: AppSpacing.md, - bottom: AppSpacing.md, - ), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - children: [ - AppConfigIntField( - label: l10n.positiveInteractionThresholdLabel, - description: l10n.positiveInteractionThresholdDescription, - value: appReviewConfig.positiveInteractionThreshold, - onChanged: (value) { - final newConfig = communityConfig.copyWith( - appReview: appReviewConfig.copyWith( - positiveInteractionThreshold: value, + if (appReviewConfig.enabled) + Padding( + padding: const EdgeInsetsDirectional.only(start: AppSpacing.lg), + child: Column( + children: [ + ExpansionTile( + title: Text(l10n.internalPromptLogicTitle), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, ), - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: newConfig, + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppConfigIntField( + label: l10n.positiveInteractionThresholdLabel, + description: l10n.positiveInteractionThresholdDescription, + value: appReviewConfig.positiveInteractionThreshold, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith( + positiveInteractionThreshold: value, + ), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, + controller: _positiveInteractionThresholdController, ), - ), - ); - }, - controller: _positiveInteractionThresholdController, - ), - AppConfigIntField( - label: l10n.initialPromptCooldownLabel, - description: l10n.initialPromptCooldownDescription, - value: appReviewConfig.initialPromptCooldownDays, - onChanged: (value) { - final newConfig = communityConfig.copyWith( - appReview: appReviewConfig.copyWith( - initialPromptCooldownDays: value, - ), - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: newConfig, + AppConfigIntField( + label: l10n.initialPromptCooldownLabel, + description: l10n.initialPromptCooldownDescription, + value: appReviewConfig.initialPromptCooldownDays, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith( + initialPromptCooldownDays: value, + ), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, + controller: _initialPromptCooldownController, ), + ], + ), + const SizedBox(height: AppSpacing.lg), + ExpansionTile( + title: Text(l10n.followUpActionsTitle), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, ), - ); - }, - controller: _initialPromptCooldownController, - ), - ], - ), - const SizedBox(height: AppSpacing.lg), - ExpansionTile( - title: Text(l10n.followUpActionsTitle), - childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, - top: AppSpacing.md, - bottom: AppSpacing.md, - ), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - children: [ - SwitchListTile( - title: Text(l10n.requestStoreReviewLabel), - subtitle: Text(l10n.requestStoreReviewDescription), - value: appReviewConfig.isPositiveFeedbackFollowUpEnabled, - onChanged: (value) { - final newAppReviewConfig = appReviewConfig.copyWith( - isPositiveFeedbackFollowUpEnabled: value, - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: communityConfig.copyWith( - appReview: newAppReviewConfig, - ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + SwitchListTile( + title: Text(l10n.requestStoreReviewLabel), + subtitle: Text(l10n.requestStoreReviewDescription), + value: appReviewConfig.isPositiveFeedbackFollowUpEnabled, + onChanged: (value) { + final newAppReviewConfig = appReviewConfig.copyWith( + isPositiveFeedbackFollowUpEnabled: value, + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: communityConfig.copyWith( + appReview: newAppReviewConfig, + ), + ), + ), + ); + }, ), - ), - ); - }, - ), - SwitchListTile( - title: Text(l10n.requestWrittenFeedbackLabel), - subtitle: Text(l10n.requestWrittenFeedbackDescription), - value: appReviewConfig.isNegativeFeedbackFollowUpEnabled, - onChanged: (value) { - final newAppReviewConfig = appReviewConfig.copyWith( - isNegativeFeedbackFollowUpEnabled: value, - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: communityConfig.copyWith( - appReview: newAppReviewConfig, - ), + SwitchListTile( + title: Text(l10n.requestWrittenFeedbackLabel), + subtitle: Text(l10n.requestWrittenFeedbackDescription), + value: appReviewConfig.isNegativeFeedbackFollowUpEnabled, + onChanged: (value) { + final newAppReviewConfig = appReviewConfig.copyWith( + isNegativeFeedbackFollowUpEnabled: value, + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: communityConfig.copyWith( + appReview: newAppReviewConfig, + ), + ), + ), + ); + }, ), - ), - ); - }, + ], + ), + ], ), - ], - ), + ), ], ); } From df9b90acf737c26e0cd61883c15d196873a8c582 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 05:03:12 +0100 Subject: [PATCH 16/21] refactor(app_configuration): improve app review settings form layout - Add padding around form elements - Improve spacing between sections - Update ExpansionTile layout for better readability - Adjust switch alignment for consistency - Update related localization strings to reflect new terminology --- .../widgets/app_review_settings_form.dart | 253 ++++++++++-------- .../widgets/community_config_form.dart | 4 +- lib/l10n/app_localizations.dart | 10 +- lib/l10n/app_localizations_ar.dart | 6 +- lib/l10n/app_localizations_en.dart | 6 +- lib/l10n/arb/app_ar.arb | 14 +- lib/l10n/arb/app_en.arb | 12 +- 7 files changed, 163 insertions(+), 142 deletions(-) diff --git a/lib/app_configuration/widgets/app_review_settings_form.dart b/lib/app_configuration/widgets/app_review_settings_form.dart index ad303e8f..2b058366 100644 --- a/lib/app_configuration/widgets/app_review_settings_form.dart +++ b/lib/app_configuration/widgets/app_review_settings_form.dart @@ -78,135 +78,156 @@ class _AppReviewSettingsFormState extends State { final appReviewConfig = communityConfig.appReview; return Column( - crossAxisAlignment: CrossAxisAlignment.start, children: [ - SwitchListTile( - title: Text(l10n.enableAppFeedbackSystemLabel), - subtitle: Text(l10n.enableAppFeedbackSystemDescription), - value: appReviewConfig.enabled, - onChanged: (value) { - final newConfig = communityConfig.copyWith( - appReview: appReviewConfig.copyWith(enabled: value), - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: newConfig, - ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: AppSpacing.lg), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SwitchListTile( + title: Text(l10n.enableAppFeedbackSystemLabel), + subtitle: Text(l10n.enableAppFeedbackSystemDescription), + value: appReviewConfig.enabled, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith(enabled: value), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + community: newConfig, + ), + ), + ); + }, ), - ); - }, - ), - const SizedBox(height: AppSpacing.lg), - if (appReviewConfig.enabled) - Padding( - padding: const EdgeInsetsDirectional.only(start: AppSpacing.lg), - child: Column( - children: [ - ExpansionTile( - title: Text(l10n.internalPromptLogicTitle), - childrenPadding: const EdgeInsetsDirectional.only( + if (appReviewConfig.enabled) ...[ + const SizedBox(height: AppSpacing.lg), + Padding( + padding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, - top: AppSpacing.md, - bottom: AppSpacing.md, ), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - children: [ - AppConfigIntField( - label: l10n.positiveInteractionThresholdLabel, - description: l10n.positiveInteractionThresholdDescription, - value: appReviewConfig.positiveInteractionThreshold, - onChanged: (value) { - final newConfig = communityConfig.copyWith( - appReview: appReviewConfig.copyWith( - positiveInteractionThreshold: value, + child: Column( + children: [ + ExpansionTile( + title: Text(l10n.internalPromptLogicTitle), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppConfigIntField( + label: l10n.positiveInteractionThresholdLabel, + description: + l10n.positiveInteractionThresholdDescription, + value: appReviewConfig.positiveInteractionThreshold, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith( + positiveInteractionThreshold: value, + ), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features + .copyWith( + community: newConfig, + ), + ), + ); + }, + controller: _positiveInteractionThresholdController, ), - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: newConfig, - ), + AppConfigIntField( + label: l10n.initialPromptCooldownLabel, + description: l10n.initialPromptCooldownDescription, + value: appReviewConfig.initialPromptCooldownDays, + onChanged: (value) { + final newConfig = communityConfig.copyWith( + appReview: appReviewConfig.copyWith( + initialPromptCooldownDays: value, + ), + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features + .copyWith( + community: newConfig, + ), + ), + ); + }, + controller: _initialPromptCooldownController, ), - ); - }, - controller: _positiveInteractionThresholdController, - ), - AppConfigIntField( - label: l10n.initialPromptCooldownLabel, - description: l10n.initialPromptCooldownDescription, - value: appReviewConfig.initialPromptCooldownDays, - onChanged: (value) { - final newConfig = communityConfig.copyWith( - appReview: appReviewConfig.copyWith( - initialPromptCooldownDays: value, + ], + ), + const SizedBox(height: AppSpacing.lg), + ExpansionTile( + title: Text(l10n.followUpActionsTitle), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + SwitchListTile( + title: Text(l10n.requestStoreReviewLabel), + subtitle: Text(l10n.requestStoreReviewDescription), + value: appReviewConfig + .isPositiveFeedbackFollowUpEnabled, + onChanged: (value) { + final newAppReviewConfig = appReviewConfig + .copyWith( + isPositiveFeedbackFollowUpEnabled: value, + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features + .copyWith( + community: communityConfig.copyWith( + appReview: newAppReviewConfig, + ), + ), + ), + ); + }, ), - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: newConfig, + SwitchListTile( + title: Text(l10n.requestWrittenFeedbackLabel), + subtitle: Text( + l10n.requestWrittenFeedbackDescription, ), + value: appReviewConfig + .isNegativeFeedbackFollowUpEnabled, + onChanged: (value) { + final newAppReviewConfig = appReviewConfig + .copyWith( + isNegativeFeedbackFollowUpEnabled: value, + ); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features + .copyWith( + community: communityConfig.copyWith( + appReview: newAppReviewConfig, + ), + ), + ), + ); + }, ), - ); - }, - controller: _initialPromptCooldownController, - ), - ], - ), - const SizedBox(height: AppSpacing.lg), - ExpansionTile( - title: Text(l10n.followUpActionsTitle), - childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, - top: AppSpacing.md, - bottom: AppSpacing.md, + ], + ), + ], ), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - children: [ - SwitchListTile( - title: Text(l10n.requestStoreReviewLabel), - subtitle: Text(l10n.requestStoreReviewDescription), - value: appReviewConfig.isPositiveFeedbackFollowUpEnabled, - onChanged: (value) { - final newAppReviewConfig = appReviewConfig.copyWith( - isPositiveFeedbackFollowUpEnabled: value, - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: communityConfig.copyWith( - appReview: newAppReviewConfig, - ), - ), - ), - ); - }, - ), - SwitchListTile( - title: Text(l10n.requestWrittenFeedbackLabel), - subtitle: Text(l10n.requestWrittenFeedbackDescription), - value: appReviewConfig.isNegativeFeedbackFollowUpEnabled, - onChanged: (value) { - final newAppReviewConfig = appReviewConfig.copyWith( - isNegativeFeedbackFollowUpEnabled: value, - ); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - community: communityConfig.copyWith( - appReview: newAppReviewConfig, - ), - ), - ), - ); - }, - ), - ], ), ], - ), + ], ), + ), ], ); } diff --git a/lib/app_configuration/widgets/community_config_form.dart b/lib/app_configuration/widgets/community_config_form.dart index b79078b4..40945c2f 100644 --- a/lib/app_configuration/widgets/community_config_form.dart +++ b/lib/app_configuration/widgets/community_config_form.dart @@ -78,9 +78,9 @@ class CommunityConfigForm extends StatelessWidget { ), const SizedBox(height: AppSpacing.lg), ExpansionTile( - title: Text(l10n.appFeedbackFunnelTitle), + title: Text(l10n.appReviewFunnelTitle), subtitle: Text( - l10n.appFeedbackFunnelDescription, + l10n.appReviewFunnelDescription, style: subtitleStyle, ), children: [ diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index b57c1ffd..de50be7d 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -3155,7 +3155,7 @@ abstract class AppLocalizations { /// Description for the Community & Engagement expansion tile. /// /// In en, this message translates to: - /// **'Manage user interactions, content reporting, and the internal app feedback system.'** + /// **'Manage user interactions, content reporting, and the internal app reporting system.'** String get communityAndEngagementDescription; /// Title for the User Engagement expansion tile. @@ -3182,17 +3182,17 @@ abstract class AppLocalizations { /// **'Set rules for what users can report.'** String get contentReportingDescription; - /// Title for the App Feedback Funnel expansion tile. + /// Title for the App Review Funnel expansion tile. /// /// In en, this message translates to: - /// **'App Feedback Funnel'** - String get appFeedbackFunnelTitle; + /// **'App Reviews'** + String get appReviewFunnelTitle; /// Description for the App Feedback Funnel expansion tile. /// /// In en, this message translates to: /// **'Manage the process for capturing user satisfaction and optionally requesting reviews.'** - String get appFeedbackFunnelDescription; + String get appReviewFunnelDescription; /// Label for the master switch to enable all engagement features. /// diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart index 3693b001..1e0d295a 100644 --- a/lib/l10n/app_localizations_ar.dart +++ b/lib/l10n/app_localizations_ar.dart @@ -1697,7 +1697,7 @@ class AppLocalizationsAr extends AppLocalizations { @override String get communityAndEngagementDescription => - 'إدارة تفاعلات المستخدمين، والإبلاغ عن المحتوى، ونظام ملاحظات التطبيق الداخلي.'; + 'إدارة تفاعلات المستخدمين، والإبلاغ عن المحتوى، ونظام مراجعات التطبيق الداخلي.'; @override String get userEngagementTitle => 'مشاركة المستخدم'; @@ -1713,10 +1713,10 @@ class AppLocalizationsAr extends AppLocalizations { 'ضع قواعد لما يمكن للمستخدمين الإبلاغ عنه.'; @override - String get appFeedbackFunnelTitle => 'قمع ملاحظات التطبيق'; + String get appReviewFunnelTitle => 'مراجعات التطبيق'; @override - String get appFeedbackFunnelDescription => + String get appReviewFunnelDescription => 'إدارة عملية جمع رضا المستخدم وطلب المراجعات اختياريًا.'; @override diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 25068186..5070b4f8 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1700,7 +1700,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get communityAndEngagementDescription => - 'Manage user interactions, content reporting, and the internal app feedback system.'; + 'Manage user interactions, content reporting, and the internal app reporting system.'; @override String get userEngagementTitle => 'User Engagement'; @@ -1716,10 +1716,10 @@ class AppLocalizationsEn extends AppLocalizations { 'Set rules for what users can report.'; @override - String get appFeedbackFunnelTitle => 'App Feedback Funnel'; + String get appReviewFunnelTitle => 'App Reviews'; @override - String get appFeedbackFunnelDescription => + String get appReviewFunnelDescription => 'Manage the process for capturing user satisfaction and optionally requesting reviews.'; @override diff --git a/lib/l10n/arb/app_ar.arb b/lib/l10n/arb/app_ar.arb index 0381466a..07c87656 100644 --- a/lib/l10n/arb/app_ar.arb +++ b/lib/l10n/arb/app_ar.arb @@ -2122,7 +2122,7 @@ "@communityAndEngagementTitle": { "description": "عنوان قسم المجتمع والمشاركة القابل للتوسيع." }, - "communityAndEngagementDescription": "إدارة تفاعلات المستخدمين، والإبلاغ عن المحتوى، ونظام ملاحظات التطبيق الداخلي.", + "communityAndEngagementDescription": "إدارة تفاعلات المستخدمين، والإبلاغ عن المحتوى، ونظام مراجعات التطبيق الداخلي.", "@communityAndEngagementDescription": { "description": "وصف قسم المجتمع والمشاركة القابل للتوسيع." }, @@ -2142,13 +2142,13 @@ "@contentReportingDescription": { "description": "وصف قسم الإبلاغ عن المحتوى القابل للتوسيع." }, - "appFeedbackFunnelTitle": "قمع ملاحظات التطبيق", - "@appFeedbackFunnelTitle": { - "description": "عنوان قسم قمع ملاحظات التطبيق القابل للتوسيع." + "appReviewFunnelTitle": "مراجعات التطبيق", + "@appReviewFunnelTitle": { + "description": "عنوان قسم مراجعات التطبيق القابل للتوسيع." }, - "appFeedbackFunnelDescription": "إدارة عملية جمع رضا المستخدم وطلب المراجعات اختياريًا.", - "@appFeedbackFunnelDescription": { - "description": "وصف قسم قمع ملاحظات التطبيق القابل للتوسيع." + "appReviewFunnelDescription": "إدارة عملية جمع رضا المستخدم وطلب المراجعات اختياريًا.", + "@appReviewFunnelDescription": { + "description": "وصف قسممراجعات التطبيق القابل للتوسيع." }, "enableEngagementFeaturesLabel": "تفعيل ميزات المشاركة", "@enableEngagementFeaturesLabel": { diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 564adba4..9ee89cbc 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -2118,7 +2118,7 @@ "@communityAndEngagementTitle": { "description": "Title for the Community & Engagement expansion tile." }, - "communityAndEngagementDescription": "Manage user interactions, content reporting, and the internal app feedback system.", + "communityAndEngagementDescription": "Manage user interactions, content reporting, and the internal app reporting system.", "@communityAndEngagementDescription": { "description": "Description for the Community & Engagement expansion tile." }, @@ -2138,12 +2138,12 @@ "@contentReportingDescription": { "description": "Description for the Content Reporting expansion tile." }, - "appFeedbackFunnelTitle": "App Feedback Funnel", - "@appFeedbackFunnelTitle": { - "description": "Title for the App Feedback Funnel expansion tile." + "appReviewFunnelTitle": "App Reviews", + "@appReviewFunnelTitle": { + "description": "Title for the App Review Funnel expansion tile." }, - "appFeedbackFunnelDescription": "Manage the process for capturing user satisfaction and optionally requesting reviews.", - "@appFeedbackFunnelDescription": { + "appReviewFunnelDescription": "Manage the process for capturing user satisfaction and optionally requesting reviews.", + "@appReviewFunnelDescription": { "description": "Description for the App Feedback Funnel expansion tile." }, "enableEngagementFeaturesLabel": "Enable Engagement Features", From 154ea0542952d7310cf28ac50b334037fd0e008e Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 05:12:16 +0100 Subject: [PATCH 17/21] fix(layout): align app review settings to the left Added `expandedCrossAxisAlignment: CrossAxisAlignment.start` to the `CommunityConfigForm` widget to align the app review settings to the left side. This improves the layout and readability of the settings form. --- lib/app_configuration/widgets/community_config_form.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/app_configuration/widgets/community_config_form.dart b/lib/app_configuration/widgets/community_config_form.dart index 40945c2f..2fb2c61d 100644 --- a/lib/app_configuration/widgets/community_config_form.dart +++ b/lib/app_configuration/widgets/community_config_form.dart @@ -83,6 +83,7 @@ class CommunityConfigForm extends StatelessWidget { l10n.appReviewFunnelDescription, style: subtitleStyle, ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, children: [ AppReviewSettingsForm( remoteConfig: remoteConfig, From 75882906ee3acf6dd0af17a1bebbc62623fa083c Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 05:21:05 +0100 Subject: [PATCH 18/21] feat(community): add global community features toggle - Add a SwitchListTile to enable/disable community features - Wrap existing settings forms in a conditional rendering block - Improve user flow by allowing access to settings only when community features are enabled --- .../widgets/community_config_form.dart | 116 ++++++++++-------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/lib/app_configuration/widgets/community_config_form.dart b/lib/app_configuration/widgets/community_config_form.dart index 2fb2c61d..d6f587a5 100644 --- a/lib/app_configuration/widgets/community_config_form.dart +++ b/lib/app_configuration/widgets/community_config_form.dart @@ -33,64 +33,82 @@ class CommunityConfigForm extends StatelessWidget { final subtitleStyle = Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), ); + final communityConfig = remoteConfig.features.community; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ExpansionTile( - title: Text(l10n.userEngagementTitle), - subtitle: Text( - l10n.userEngagementDescription, - style: subtitleStyle, - ), - childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, - top: AppSpacing.md, - bottom: AppSpacing.md, - ), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - children: [ - EngagementSettingsForm( - remoteConfig: remoteConfig, - onConfigChanged: onConfigChanged, - ), - ], + SwitchListTile( + title: Text(l10n.enableCommunityFeaturesLabel), + subtitle: Text(l10n.enableCommunityFeaturesDescription), + value: communityConfig.enabled, + onChanged: (value) { + onConfigChanged( + remoteConfig.copyWith( + features: remoteConfig.features.copyWith( + community: communityConfig.copyWith(enabled: value), + ), + ), + ); + }, ), - const SizedBox(height: AppSpacing.lg), - ExpansionTile( - title: Text(l10n.contentReportingTitle), - subtitle: Text( - l10n.contentReportingDescription, - style: subtitleStyle, - ), - childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, - top: AppSpacing.md, - bottom: AppSpacing.md, + if (communityConfig.enabled) ...[ + const SizedBox(height: AppSpacing.lg), + ExpansionTile( + title: Text(l10n.userEngagementTitle), + subtitle: Text( + l10n.userEngagementDescription, + style: subtitleStyle, + ), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + EngagementSettingsForm( + remoteConfig: remoteConfig, + onConfigChanged: onConfigChanged, + ), + ], ), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - children: [ - ReportingSettingsForm( - remoteConfig: remoteConfig, - onConfigChanged: onConfigChanged, + const SizedBox(height: AppSpacing.lg), + ExpansionTile( + title: Text(l10n.contentReportingTitle), + subtitle: Text( + l10n.contentReportingDescription, + style: subtitleStyle, ), - ], - ), - const SizedBox(height: AppSpacing.lg), - ExpansionTile( - title: Text(l10n.appReviewFunnelTitle), - subtitle: Text( - l10n.appReviewFunnelDescription, - style: subtitleStyle, + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + ReportingSettingsForm( + remoteConfig: remoteConfig, + onConfigChanged: onConfigChanged, + ), + ], ), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - children: [ - AppReviewSettingsForm( - remoteConfig: remoteConfig, - onConfigChanged: onConfigChanged, + const SizedBox(height: AppSpacing.lg), + ExpansionTile( + title: Text(l10n.appReviewFunnelTitle), + subtitle: Text( + l10n.appReviewFunnelDescription, + style: subtitleStyle, ), - ], - ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppReviewSettingsForm( + remoteConfig: remoteConfig, + onConfigChanged: onConfigChanged, + ), + ], + ), + ], ], ); } From f88926160bb4a436812a4d6c11efffb7e2b4fd9a Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 05:21:33 +0100 Subject: [PATCH 19/21] feat(app_configuration): add switch for source reporting - Add SwitchListTile to enable/disable source reporting - Update reporting configuration when switch state changes - Implement source reporting --- .../widgets/reporting_settings_form.dart | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/app_configuration/widgets/reporting_settings_form.dart b/lib/app_configuration/widgets/reporting_settings_form.dart index d715900a..0add4b1b 100644 --- a/lib/app_configuration/widgets/reporting_settings_form.dart +++ b/lib/app_configuration/widgets/reporting_settings_form.dart @@ -67,6 +67,24 @@ class ReportingSettingsForm extends StatelessWidget { ); }, ), + SwitchListTile( + title: Text(l10n.enableSourceReportingLabel), + value: reportingConfig.sourceReportingEnabled, + onChanged: (value) { + final newConfig = reportingConfig.copyWith( + sourceReportingEnabled: value, + ); + onConfigChanged( + remoteConfig.copyWith( + features: remoteConfig.features.copyWith( + community: communityConfig.copyWith( + reporting: newConfig, + ), + ), + ), + ); + }, + ), SwitchListTile( title: Text(l10n.enableCommentReportingLabel), value: reportingConfig.commentReportingEnabled, From 813c7e49452db966d4d92e7621c0c27b6b40db97 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 05:22:01 +0100 Subject: [PATCH 20/21] feat(l10n): add translations for community --- lib/l10n/arb/app_ar.arb | 8 ++++++++ lib/l10n/arb/app_en.arb | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/l10n/arb/app_ar.arb b/lib/l10n/arb/app_ar.arb index 07c87656..c9059458 100644 --- a/lib/l10n/arb/app_ar.arb +++ b/lib/l10n/arb/app_ar.arb @@ -2241,5 +2241,13 @@ "followUpActionsTitle": "إجراءات المتابعة", "@followUpActionsTitle": { "description": "عنوان قسم إجراءات المتابعة لمراجعة التطبيق." + }, + "enableCommunityFeaturesLabel": "تفعيل ميزات المجتمع", + "@enableCommunityFeaturesLabel": { + "description": "تسمية المفتاح الرئيسي لتفعيل جميع ميزات المجتمع." + }, + "enableCommunityFeaturesDescription": "ينشط أو يعطل عالميًا جميع الوظائف المتعلقة بالمجتمع، بما في ذلك المشاركة والإبلاغ.", + "@enableCommunityFeaturesDescription": { + "description": "وصف المفتاح الرئيسي لتفعيل جميع ميزات المجتمع." } } \ No newline at end of file diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 9ee89cbc..006df5d9 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -2237,5 +2237,13 @@ "followUpActionsTitle": "Follow-up Actions", "@followUpActionsTitle": { "description": "Title for the nested expansion tile for app review follow-up actions." + }, + "enableCommunityFeaturesLabel": "Enable Community Features", + "@enableCommunityFeaturesLabel": { + "description": "Label for the master switch to enable all community features." + }, + "enableCommunityFeaturesDescription": "Globally activates or deactivates all community-related functionality, including engagement and reporting.", + "@enableCommunityFeaturesDescription": { + "description": "Description for the master switch to enable all community features." } } \ No newline at end of file From f891710cb58f242a7a2e62d3b3d599a40939dea3 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Dec 2025 05:22:23 +0100 Subject: [PATCH 21/21] build(l10n): sync --- lib/l10n/app_localizations.dart | 12 ++++++++++++ lib/l10n/app_localizations_ar.dart | 7 +++++++ lib/l10n/app_localizations_en.dart | 7 +++++++ 3 files changed, 26 insertions(+) diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index de50be7d..4f9e618e 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -3331,6 +3331,18 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Follow-up Actions'** String get followUpActionsTitle; + + /// Label for the master switch to enable all community features. + /// + /// In en, this message translates to: + /// **'Enable Community Features'** + String get enableCommunityFeaturesLabel; + + /// Description for the master switch to enable all community features. + /// + /// In en, this message translates to: + /// **'Globally activates or deactivates all community-related functionality, including engagement and reporting.'** + String get enableCommunityFeaturesDescription; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart index 1e0d295a..345786b8 100644 --- a/lib/l10n/app_localizations_ar.dart +++ b/lib/l10n/app_localizations_ar.dart @@ -1795,4 +1795,11 @@ class AppLocalizationsAr extends AppLocalizations { @override String get followUpActionsTitle => 'إجراءات المتابعة'; + + @override + String get enableCommunityFeaturesLabel => 'تفعيل ميزات المجتمع'; + + @override + String get enableCommunityFeaturesDescription => + 'ينشط أو يعطل عالميًا جميع الوظائف المتعلقة بالمجتمع، بما في ذلك المشاركة والإبلاغ.'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 5070b4f8..caf6510a 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1800,4 +1800,11 @@ class AppLocalizationsEn extends AppLocalizations { @override String get followUpActionsTitle => 'Follow-up Actions'; + + @override + String get enableCommunityFeaturesLabel => 'Enable Community Features'; + + @override + String get enableCommunityFeaturesDescription => + 'Globally activates or deactivates all community-related functionality, including engagement and reporting.'; }