diff --git a/lib/app_configuration/view/tabs/features_configuration_tab.dart b/lib/app_configuration/view/tabs/features_configuration_tab.dart index 96fbf462..f6f68a6d 100644 --- a/lib/app_configuration/view/tabs/features_configuration_tab.dart +++ b/lib/app_configuration/view/tabs/features_configuration_tab.dart @@ -49,6 +49,27 @@ class _FeaturesConfigurationTabState extends State { super.dispose(); } + String _getDecoratorDescription( + BuildContext context, + FeedDecoratorType type, + ) { + final l10n = AppLocalizationsX(context).l10n; + switch (type) { + case FeedDecoratorType.linkAccount: + return l10n.feedDecoratorLinkAccountDescription; + case FeedDecoratorType.upgrade: + return l10n.feedDecoratorUpgradeDescription; + case FeedDecoratorType.rateApp: + return l10n.feedDecoratorRateAppDescription; + case FeedDecoratorType.enableNotifications: + return l10n.feedDecoratorEnableNotificationsDescription; + case FeedDecoratorType.suggestedTopics: + return l10n.feedDecoratorSuggestedTopicsDescription; + case FeedDecoratorType.suggestedSources: + return l10n.feedDecoratorSuggestedSourcesDescription; + } + } + @override Widget build(BuildContext context) { final l10n = AppLocalizationsX(context).l10n; @@ -62,14 +83,28 @@ class _FeaturesConfigurationTabState extends State { builder: (context, expandedIndex, child) { const tileIndex = 0; return ExpansionTile( + leading: Icon( + Icons.paid_outlined, + color: Theme.of(context).colorScheme.onSurface.withOpacity( + 0.7, + ), + ), key: ValueKey('advertisementsTile_$expandedIndex'), title: Text(l10n.advertisementsTab), - onExpansionChanged: (isExpanded) { + subtitle: Text( + l10n.advertisementsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), + onExpansionChanged: (bool isExpanded) { _expandedTileIndex.value = isExpanded ? tileIndex : null; }, initiallyExpanded: expandedIndex == tileIndex, childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, + start: AppSpacing.xxl, top: AppSpacing.md, bottom: AppSpacing.md, ), @@ -106,14 +141,28 @@ class _FeaturesConfigurationTabState extends State { builder: (context, expandedIndex, child) { const tileIndex = 1; return ExpansionTile( + leading: Icon( + Icons.notifications_active_outlined, + color: Theme.of(context).colorScheme.onSurface.withOpacity( + 0.7, + ), + ), key: ValueKey('pushNotificationsTile_$expandedIndex'), title: Text(l10n.notificationsTab), - onExpansionChanged: (isExpanded) { + subtitle: Text( + l10n.notificationsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), + onExpansionChanged: (bool isExpanded) { _expandedTileIndex.value = isExpanded ? tileIndex : null; }, initiallyExpanded: expandedIndex == tileIndex, childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, + start: AppSpacing.xxl, top: AppSpacing.md, bottom: AppSpacing.md, ), @@ -135,14 +184,28 @@ class _FeaturesConfigurationTabState extends State { builder: (context, expandedIndex, child) { const tileIndex = 2; return ExpansionTile( + leading: Icon( + Icons.dynamic_feed_outlined, + color: Theme.of(context).colorScheme.onSurface.withOpacity( + 0.7, + ), + ), key: ValueKey('feedTile_$expandedIndex'), title: Text(l10n.feedTab), - onExpansionChanged: (isExpanded) { + subtitle: Text( + l10n.feedDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), + onExpansionChanged: (bool isExpanded) { _expandedTileIndex.value = isExpanded ? tileIndex : null; }, initiallyExpanded: expandedIndex == tileIndex, childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, + start: AppSpacing.xxl, top: AppSpacing.md, bottom: AppSpacing.md, ), @@ -150,6 +213,14 @@ class _FeaturesConfigurationTabState extends State { children: [ ExpansionTile( title: Text(l10n.feedItemClickBehaviorTitle), + subtitle: Text( + l10n.feedItemClickBehaviorDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -157,15 +228,6 @@ class _FeaturesConfigurationTabState extends State { ), expandedCrossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - l10n.feedItemClickBehaviorDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of( - context, - ).colorScheme.onSurface.withOpacity(0.7), - ), - ), - const SizedBox(height: AppSpacing.lg), Align( alignment: AlignmentDirectional.centerStart, child: SegmentedButton( @@ -203,6 +265,14 @@ class _FeaturesConfigurationTabState extends State { const SizedBox(height: AppSpacing.lg), ExpansionTile( title: Text(l10n.feedDecoratorsTitle), + subtitle: Text( + l10n.feedDecoratorsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -210,20 +280,20 @@ class _FeaturesConfigurationTabState extends State { ), expandedCrossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - l10n.feedDecoratorsDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of( - context, - ).colorScheme.onSurface.withOpacity(0.7), - ), - ), - const SizedBox(height: AppSpacing.lg), for (final decoratorType in FeedDecoratorType.values) Padding( padding: const EdgeInsets.only(bottom: AppSpacing.md), child: ExpansionTile( title: Text(decoratorType.l10n(context)), + subtitle: Text( + _getDecoratorDescription(context, decoratorType), + style: Theme.of(context).textTheme.bodySmall + ?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.xl, top: AppSpacing.md, @@ -253,6 +323,12 @@ class _FeaturesConfigurationTabState extends State { builder: (context, expandedIndex, child) { const tileIndex = 3; return ExpansionTile( + leading: Icon( + Icons.groups_outlined, + color: Theme.of(context).colorScheme.onSurface.withOpacity( + 0.7, + ), + ), key: ValueKey('communityTile_$expandedIndex'), title: Text(l10n.communityAndEngagementTitle), subtitle: Text( @@ -263,12 +339,12 @@ class _FeaturesConfigurationTabState extends State { ).colorScheme.onSurface.withOpacity(0.7), ), ), - onExpansionChanged: (isExpanded) { + onExpansionChanged: (bool isExpanded) { _expandedTileIndex.value = isExpanded ? tileIndex : null; }, initiallyExpanded: expandedIndex == tileIndex, childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, + start: AppSpacing.xxl, top: AppSpacing.md, bottom: AppSpacing.md, ), diff --git a/lib/app_configuration/view/tabs/system_configuration_tab.dart b/lib/app_configuration/view/tabs/system_configuration_tab.dart index bb275f45..d78fc200 100644 --- a/lib/app_configuration/view/tabs/system_configuration_tab.dart +++ b/lib/app_configuration/view/tabs/system_configuration_tab.dart @@ -53,14 +53,28 @@ class _SystemConfigurationTabState extends State { builder: (context, expandedIndex, child) { const tileIndex = 0; return ExpansionTile( + leading: Icon( + Icons.system_update_alt_outlined, + color: Theme.of(context).colorScheme.onSurface.withOpacity( + 0.7, + ), + ), key: ValueKey('appStatusAndUpdatesTile_$expandedIndex'), title: Text(l10n.appStatusAndUpdatesTitle), + subtitle: Text( + l10n.appStatusAndUpdatesDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), onExpansionChanged: (isExpanded) { _expandedTileIndex.value = isExpanded ? tileIndex : null; }, initiallyExpanded: expandedIndex == tileIndex, childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, + start: AppSpacing.xxl, top: AppSpacing.md, bottom: AppSpacing.md, ), @@ -68,6 +82,14 @@ class _SystemConfigurationTabState extends State { children: [ ExpansionTile( title: Text(l10n.maintenanceModeTitle), + subtitle: Text( + l10n.maintenanceModeDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -99,6 +121,14 @@ class _SystemConfigurationTabState extends State { const SizedBox(height: AppSpacing.lg), ExpansionTile( title: Text(l10n.appUpdateManagementTitle), + subtitle: Text( + l10n.updateConfigDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -122,14 +152,28 @@ class _SystemConfigurationTabState extends State { builder: (context, expandedIndex, child) { const tileIndex = 1; return ExpansionTile( + leading: Icon( + Icons.link_outlined, + color: Theme.of(context).colorScheme.onSurface.withOpacity( + 0.7, + ), + ), key: ValueKey('appUrlsTile_$expandedIndex'), title: Text(l10n.appUrlsTitle), + subtitle: Text( + l10n.appUrlsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), onExpansionChanged: (isExpanded) { _expandedTileIndex.value = isExpanded ? tileIndex : null; }, initiallyExpanded: expandedIndex == tileIndex, childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, + start: AppSpacing.xxl, top: AppSpacing.md, bottom: AppSpacing.md, ), diff --git a/lib/app_configuration/view/tabs/user_configuration_tab.dart b/lib/app_configuration/view/tabs/user_configuration_tab.dart index 058d5ccb..6585163e 100644 --- a/lib/app_configuration/view/tabs/user_configuration_tab.dart +++ b/lib/app_configuration/view/tabs/user_configuration_tab.dart @@ -1,6 +1,6 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/saved_filter_limits_section.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/saved_filter_limits_form.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/user_limits_config_form.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart'; import 'package:ui_kit/ui_kit.dart'; @@ -52,14 +52,28 @@ class _UserConfigurationTabState extends State { builder: (context, expandedIndex, child) { const tileIndex = 0; return ExpansionTile( + leading: Icon( + Icons.manage_accounts_outlined, + color: Theme.of(context).colorScheme.onSurface.withOpacity( + 0.7, + ), + ), key: ValueKey('userLimitsTile_$expandedIndex'), title: Text(l10n.userLimitsTitle), + subtitle: Text( + l10n.userLimitsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), onExpansionChanged: (isExpanded) { _expandedTileIndex.value = isExpanded ? tileIndex : null; }, initiallyExpanded: expandedIndex == tileIndex, childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, + start: AppSpacing.xxl, top: AppSpacing.md, bottom: AppSpacing.md, ), @@ -67,6 +81,14 @@ class _UserConfigurationTabState extends State { children: [ ExpansionTile( title: Text(l10n.userContentLimitsTitle), + subtitle: Text( + l10n.userContentLimitsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -81,20 +103,16 @@ class _UserConfigurationTabState extends State { ], ), const SizedBox(height: AppSpacing.lg), - ExpansionTile( - title: Text(l10n.savedFeedFilterLimitsTitle), - childrenPadding: const EdgeInsetsDirectional.only( - start: AppSpacing.lg, - top: AppSpacing.md, - bottom: AppSpacing.md, - ), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - children: [ - SavedFilterLimitsSection( - remoteConfig: widget.remoteConfig, - onConfigChanged: widget.onConfigChanged, - ), - ], + SavedFilterLimitsForm( + remoteConfig: widget.remoteConfig, + onConfigChanged: widget.onConfigChanged, + filterType: SavedFilterType.headline, + ), + const SizedBox(height: AppSpacing.lg), + SavedFilterLimitsForm( + remoteConfig: widget.remoteConfig, + onConfigChanged: widget.onConfigChanged, + filterType: SavedFilterType.source, ), ], ); diff --git a/lib/app_configuration/widgets/ad_config_form.dart b/lib/app_configuration/widgets/ad_config_form.dart index a74323e8..2e180641 100644 --- a/lib/app_configuration/widgets/ad_config_form.dart +++ b/lib/app_configuration/widgets/ad_config_form.dart @@ -32,6 +32,7 @@ class AdConfigForm extends StatelessWidget { children: [ SwitchListTile( title: Text(l10n.enableGlobalAdsLabel), + subtitle: Text(l10n.enableGlobalAdsDescription), value: ads.enabled, onChanged: (value) { onConfigChanged( diff --git a/lib/app_configuration/widgets/ad_platform_config_form.dart b/lib/app_configuration/widgets/ad_platform_config_form.dart index ff776fd5..13713f0c 100644 --- a/lib/app_configuration/widgets/ad_platform_config_form.dart +++ b/lib/app_configuration/widgets/ad_platform_config_form.dart @@ -146,11 +146,23 @@ class _AdPlatformConfigFormState extends State final l10n = AppLocalizationsX(context).l10n; final adConfig = widget.remoteConfig.features.ads; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, + return ExpansionTile( + title: Text(l10n.adPlatformConfigurationTitle), + subtitle: Text( + l10n.adPlatformConfigurationDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ), + ), children: [ ExpansionTile( title: Text(l10n.primaryAdPlatformTitle), + subtitle: Text( + l10n.primaryAdPlatformDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -158,58 +170,61 @@ class _AdPlatformConfigFormState extends State ), expandedCrossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - l10n.primaryAdPlatformDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), - ), - textAlign: TextAlign.start, - ), - const SizedBox(height: AppSpacing.lg), - Align( - alignment: AlignmentDirectional.centerStart, - child: SegmentedButton( - style: SegmentedButton.styleFrom( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.zero, - ), - ), - segments: AdPlatformType.values - .where( - (type) => type != AdPlatformType.demo, - ) - .map( - (type) => ButtonSegment( - value: type, - label: Text(type.l10n(context)), - ), - ) - .toList(), - selected: {_selectedPlatform}, - onSelectionChanged: (newSelection) { - setState(() { - _selectedPlatform = newSelection.first; - _tabController.index = AdPlatformType.values.indexOf( - _selectedPlatform, - ); - }); - widget.onConfigChanged( - widget.remoteConfig.copyWith( - features: widget.remoteConfig.features.copyWith( - ads: adConfig.copyWith( - primaryAdPlatform: newSelection.first, - ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: AlignmentDirectional.centerStart, + child: SegmentedButton( + style: SegmentedButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.zero, ), ), - ); - }, - ), + segments: AdPlatformType.values + .where( + (type) => type != AdPlatformType.demo, + ) + .map( + (type) => ButtonSegment( + value: type, + label: Text(type.l10n(context)), + ), + ) + .toList(), + selected: {_selectedPlatform}, + onSelectionChanged: (newSelection) { + setState(() { + _selectedPlatform = newSelection.first; + _tabController.index = AdPlatformType.values.indexOf( + _selectedPlatform, + ); + }); + widget.onConfigChanged( + widget.remoteConfig.copyWith( + features: widget.remoteConfig.features.copyWith( + ads: adConfig.copyWith( + primaryAdPlatform: newSelection.first, + ), + ), + ), + ); + }, + ), + ), + ], ), ], ), const SizedBox(height: AppSpacing.lg), ExpansionTile( title: Text(l10n.adUnitIdentifiersTitle), + subtitle: Text( + l10n.adUnitIdentifiersDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -217,50 +232,47 @@ class _AdPlatformConfigFormState extends State ), expandedCrossAxisAlignment: CrossAxisAlignment.start, children: [ - Align( - alignment: AlignmentDirectional.centerStart, - child: SizedBox( - height: kTextTabBarHeight, - child: TabBar( - controller: _tabController, - tabAlignment: TabAlignment.start, - isScrollable: true, - tabs: AdPlatformType.values - .where( - (type) => type != AdPlatformType.demo, - ) - .map((platform) => Tab(text: platform.l10n(context))) - .toList(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: AlignmentDirectional.centerStart, + child: SizedBox( + height: kTextTabBarHeight, + child: TabBar( + controller: _tabController, + tabAlignment: TabAlignment.start, + isScrollable: true, + tabs: AdPlatformType.values + .where( + (type) => type != AdPlatformType.demo, + ) + .map((platform) => Tab(text: platform.l10n(context))) + .toList(), + ), + ), ), - ), - ), - const SizedBox(height: AppSpacing.lg), - Text( - l10n.adUnitIdentifiersDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), - ), - textAlign: TextAlign.start, - ), - const SizedBox(height: AppSpacing.lg), - SizedBox( - height: 300, // Adjust height as needed for the content - child: TabBarView( - controller: _tabController, - children: AdPlatformType.values - .where( - (type) => type != AdPlatformType.demo, - ) - .map( - (platform) => _buildAdUnitIdentifierFields( - context, - l10n, - platform, - adConfig, - ), - ) - .toList(), - ), + const SizedBox(height: AppSpacing.lg), + SizedBox( + height: 300, // Adjust height as needed for the content + child: TabBarView( + controller: _tabController, + children: AdPlatformType.values + .where( + (type) => type != AdPlatformType.demo, + ) + .map( + (platform) => _buildAdUnitIdentifierFields( + context, + l10n, + platform, + adConfig, + ), + ) + .toList(), + ), + ), + ], ), ], ), diff --git a/lib/app_configuration/widgets/app_review_settings_form.dart b/lib/app_configuration/widgets/app_review_settings_form.dart index 5e724210..c1d006a6 100644 --- a/lib/app_configuration/widgets/app_review_settings_form.dart +++ b/lib/app_configuration/widgets/app_review_settings_form.dart @@ -109,10 +109,18 @@ class _AppReviewSettingsFormState extends State { ), child: LayoutBuilder( builder: (context, constraints) { - final isMobile = constraints.maxWidth < 600; return ExpansionTile( title: Text(l10n.internalPromptLogicTitle), - initiallyExpanded: !isMobile, + subtitle: Text( + l10n.internalPromptLogicDescription, + style: Theme.of(context).textTheme.bodySmall + ?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), + initiallyExpanded: false, childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -174,10 +182,18 @@ class _AppReviewSettingsFormState extends State { ), child: LayoutBuilder( builder: (context, constraints) { - final isMobile = constraints.maxWidth < 600; return ExpansionTile( title: Text(l10n.eligiblePositiveInteractionsTitle), - initiallyExpanded: !isMobile, + subtitle: Text( + l10n.eligiblePositiveInteractionsDescription, + style: Theme.of(context).textTheme.bodySmall + ?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), + initiallyExpanded: false, childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -187,6 +203,9 @@ class _AppReviewSettingsFormState extends State { children: [ ...PositiveInteractionType.values.map( (interactionType) => SwitchListTile( + subtitle: Text( + interactionType.l10nDescription(context), + ), title: Text(interactionType.l10n(context)), value: appReviewConfig .eligiblePositiveInteractions @@ -231,10 +250,18 @@ class _AppReviewSettingsFormState extends State { ), child: LayoutBuilder( builder: (context, constraints) { - final isMobile = constraints.maxWidth < 600; return ExpansionTile( title: Text(l10n.followUpActionsTitle), - initiallyExpanded: !isMobile, + subtitle: Text( + l10n.followUpActionsDescription, + style: Theme.of(context).textTheme.bodySmall + ?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), + initiallyExpanded: false, childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -317,3 +344,19 @@ extension on PositiveInteractionType { } } } + +extension on PositiveInteractionType { + String l10nDescription(BuildContext context) { + final l10n = AppLocalizationsX(context).l10n; + switch (this) { + case PositiveInteractionType.saveItem: + return l10n.positiveInteractionTypeSaveItemDescription; + case PositiveInteractionType.followItem: + return l10n.positiveInteractionTypeFollowItemDescription; + case PositiveInteractionType.shareContent: + return l10n.positiveInteractionTypeShareContentDescription; + case PositiveInteractionType.saveFilter: + return l10n.positiveInteractionTypeSaveFilterDescription; + } + } +} diff --git a/lib/app_configuration/widgets/app_urls_form.dart b/lib/app_configuration/widgets/app_urls_form.dart index 14a77375..851c3a42 100644 --- a/lib/app_configuration/widgets/app_urls_form.dart +++ b/lib/app_configuration/widgets/app_urls_form.dart @@ -2,7 +2,6 @@ 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_urls_form} /// A form widget for configuring application URLs. @@ -84,13 +83,6 @@ class _AppUrlsFormState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - l10n.appUrlsDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), - ), - ), - const SizedBox(height: AppSpacing.lg), AppConfigTextField( label: l10n.termsOfServiceUrlLabel, description: l10n.termsOfServiceUrlDescription, diff --git a/lib/app_configuration/widgets/engagement_settings_form.dart b/lib/app_configuration/widgets/engagement_settings_form.dart index 4a370020..44553b4c 100644 --- a/lib/app_configuration/widgets/engagement_settings_form.dart +++ b/lib/app_configuration/widgets/engagement_settings_form.dart @@ -46,42 +46,45 @@ class EngagementSettingsForm extends StatelessWidget { }, ), 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, + if (engagementConfig.enabled) + Padding( + padding: const EdgeInsets.symmetric(horizontal: AppSpacing.lg), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + l10n.engagementModeDescription, + style: Theme.of(context).textTheme.bodySmall, ), - ); - onConfigChanged( - remoteConfig.copyWith( - features: remoteConfig.features.copyWith( - community: newConfig, - ), + const SizedBox(height: AppSpacing.md), + 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, + ), + ), + ); + }, ), - ); - }, + ], + ), ), - ), ], ); } diff --git a/lib/app_configuration/widgets/feed_ad_settings_form.dart b/lib/app_configuration/widgets/feed_ad_settings_form.dart index d0c53081..1e6cfa75 100644 --- a/lib/app_configuration/widgets/feed_ad_settings_form.dart +++ b/lib/app_configuration/widgets/feed_ad_settings_form.dart @@ -138,6 +138,12 @@ class _FeedAdSettingsFormState extends State return ExpansionTile( title: Text(l10n.feedAdSettingsTitle), + subtitle: Text( + l10n.feedAdSettingsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -147,6 +153,7 @@ class _FeedAdSettingsFormState extends State children: [ SwitchListTile( title: Text(l10n.enableFeedAdsLabel), + subtitle: Text(l10n.enableFeedAdsDescription), value: feedAdConfig.enabled, onChanged: (value) { widget.onConfigChanged( @@ -286,6 +293,7 @@ class _FeedAdSettingsFormState extends State children: [ SwitchListTile( title: Text(l10n.visibleToRoleLabel(role.l10n(context))), + subtitle: Text(l10n.visibleToRoleDescription(role.l10n(context))), value: roleConfig != null, onChanged: (value) { final newVisibleTo = Map.from( diff --git a/lib/app_configuration/widgets/feed_decorator_form.dart b/lib/app_configuration/widgets/feed_decorator_form.dart index 7d334fd7..ac9d24d2 100644 --- a/lib/app_configuration/widgets/feed_decorator_form.dart +++ b/lib/app_configuration/widgets/feed_decorator_form.dart @@ -156,6 +156,7 @@ class _FeedDecoratorFormState extends State children: [ SwitchListTile( title: Text(l10n.enabledLabel), + subtitle: Text(l10n.enableDecoratorDescription), value: decoratorConfig.enabled, onChanged: (value) { final newDecoratorConfig = decoratorConfig.copyWith(enabled: value); diff --git a/lib/app_configuration/widgets/navigation_ad_settings_form.dart b/lib/app_configuration/widgets/navigation_ad_settings_form.dart index 93c22258..05f54a24 100644 --- a/lib/app_configuration/widgets/navigation_ad_settings_form.dart +++ b/lib/app_configuration/widgets/navigation_ad_settings_form.dart @@ -115,6 +115,12 @@ class _NavigationAdSettingsFormState extends State return ExpansionTile( title: Text(l10n.navigationAdConfigTitle), + subtitle: Text( + l10n.navigationAdConfigDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -124,6 +130,7 @@ class _NavigationAdSettingsFormState extends State children: [ SwitchListTile( title: Text(l10n.enableNavigationAdsLabel), + subtitle: Text(l10n.enableNavigationAdsDescription), value: navAdConfig.enabled, onChanged: (value) { widget.onConfigChanged( @@ -206,6 +213,7 @@ class _NavigationAdSettingsFormState extends State children: [ SwitchListTile( title: Text(l10n.visibleToRoleLabel(role.l10n(context))), + subtitle: Text(l10n.visibleToRoleDescription(role.l10n(context))), value: roleConfig != null, onChanged: (value) { final newVisibleTo = diff --git a/lib/app_configuration/widgets/push_notification_settings_form.dart b/lib/app_configuration/widgets/push_notification_settings_form.dart index 38db1155..c35089ac 100644 --- a/lib/app_configuration/widgets/push_notification_settings_form.dart +++ b/lib/app_configuration/widgets/push_notification_settings_form.dart @@ -61,6 +61,12 @@ class PushNotificationSettingsForm extends StatelessWidget { ) { return ExpansionTile( title: Text(l10n.pushNotificationPrimaryProviderTitle), + subtitle: Text( + l10n.pushNotificationPrimaryProviderDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -68,13 +74,6 @@ class PushNotificationSettingsForm extends StatelessWidget { ), expandedCrossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - l10n.pushNotificationPrimaryProviderDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), - ), - ), - const SizedBox(height: AppSpacing.lg), Align( alignment: AlignmentDirectional.centerStart, child: SegmentedButton( @@ -104,6 +103,21 @@ class PushNotificationSettingsForm extends StatelessWidget { ); } + String _getDeliveryTypeDescription( + BuildContext context, + PushNotificationSubscriptionDeliveryType type, + ) { + final l10n = AppLocalizationsX(context).l10n; + switch (type) { + case PushNotificationSubscriptionDeliveryType.breakingOnly: + return l10n.pushNotificationDeliveryTypeBreakingOnlyDescription; + case PushNotificationSubscriptionDeliveryType.dailyDigest: + return l10n.pushNotificationDeliveryTypeDailyDigestDescription; + case PushNotificationSubscriptionDeliveryType.weeklyRoundup: + return l10n.pushNotificationDeliveryTypeWeeklyRoundupDescription; + } + } + Widget _buildDeliveryTypesSection( BuildContext context, AppLocalizations l10n, @@ -111,6 +125,12 @@ class PushNotificationSettingsForm extends StatelessWidget { ) { return ExpansionTile( title: Text(l10n.pushNotificationDeliveryTypesTitle), + subtitle: Text( + l10n.pushNotificationDeliveryTypesDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ), + ), childrenPadding: const EdgeInsetsDirectional.only( start: AppSpacing.lg, top: AppSpacing.md, @@ -118,18 +138,12 @@ class PushNotificationSettingsForm extends StatelessWidget { ), expandedCrossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - l10n.pushNotificationDeliveryTypesDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), - ), - ), - const SizedBox(height: AppSpacing.lg), Column( children: PushNotificationSubscriptionDeliveryType.values .map( (type) => SwitchListTile( title: Text(type.l10n(context)), + subtitle: Text(_getDeliveryTypeDescription(context, type)), value: pushConfig.deliveryConfigs[type] ?? false, onChanged: (value) { final newDeliveryConfigs = diff --git a/lib/app_configuration/widgets/reporting_settings_form.dart b/lib/app_configuration/widgets/reporting_settings_form.dart index 0add4b1b..bf5139dd 100644 --- a/lib/app_configuration/widgets/reporting_settings_form.dart +++ b/lib/app_configuration/widgets/reporting_settings_form.dart @@ -44,68 +44,66 @@ class ReportingSettingsForm extends StatelessWidget { ); }, ), - 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, - ), - ), + if (reportingConfig.enabled) ...[ + const SizedBox(height: AppSpacing.lg), + SwitchListTile( + title: Text(l10n.enableHeadlineReportingLabel), + subtitle: Text(l10n.enableHeadlineReportingDescription), + 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.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.enableSourceReportingLabel), + subtitle: Text(l10n.enableSourceReportingDescription), + 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, - onChanged: (value) { - final newConfig = reportingConfig.copyWith( - commentReportingEnabled: value, - ); - onConfigChanged( - remoteConfig.copyWith( - features: remoteConfig.features.copyWith( - community: communityConfig.copyWith( - reporting: newConfig, - ), - ), + ), + ), + ); + }, + ), + SwitchListTile( + title: Text(l10n.enableCommentReportingLabel), + subtitle: Text(l10n.enableCommentReportingDescription), + value: reportingConfig.commentReportingEnabled, + onChanged: (value) { + final newConfig = reportingConfig.copyWith( + commentReportingEnabled: value, + ); + onConfigChanged( + remoteConfig.copyWith( + features: remoteConfig.features.copyWith( + community: communityConfig.copyWith( + reporting: newConfig, ), - ); - }, - ), - ], + ), + ), + ); + }, ), - ), + ], ], ); } diff --git a/lib/app_configuration/widgets/saved_filter_limits_form.dart b/lib/app_configuration/widgets/saved_filter_limits_form.dart index 46c47429..7e062790 100644 --- a/lib/app_configuration/widgets/saved_filter_limits_form.dart +++ b/lib/app_configuration/widgets/saved_filter_limits_form.dart @@ -201,11 +201,23 @@ class _SavedFilterLimitsFormState extends State final l10n = AppLocalizationsX(context).l10n; final isHeadlineFilter = widget.filterType == SavedFilterType.headline; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, + return ExpansionTile( + title: Text( + isHeadlineFilter + ? l10n.savedHeadlineFilterLimitsTitle + : l10n.savedSourceFilterLimitsTitle, + ), + subtitle: Text( + isHeadlineFilter + ? l10n.savedHeadlineFilterLimitsDescription + : l10n.savedSourceFilterLimitsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), + ), + ), children: [ - Align( - alignment: AlignmentDirectional.centerStart, + Padding( + padding: const EdgeInsets.symmetric(horizontal: AppSpacing.lg), child: SizedBox( height: kTextTabBarHeight, child: TabBar( @@ -218,7 +230,7 @@ class _SavedFilterLimitsFormState extends State ), ), ), - const SizedBox(height: AppSpacing.lg), + const SizedBox(height: AppSpacing.md), SizedBox( height: isHeadlineFilter ? 500 : 250, child: TabBarView( diff --git a/lib/app_configuration/widgets/user_limits_config_form.dart b/lib/app_configuration/widgets/user_limits_config_form.dart index afb99d3d..44099685 100644 --- a/lib/app_configuration/widgets/user_limits_config_form.dart +++ b/lib/app_configuration/widgets/user_limits_config_form.dart @@ -109,13 +109,6 @@ class _UserLimitsConfigFormState extends State return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - l10n.userContentLimitsDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), - ), - ), - const SizedBox(height: AppSpacing.lg), Align( alignment: AlignmentDirectional.centerStart, child: SizedBox( @@ -158,6 +151,10 @@ class _UserLimitsConfigFormState extends State UserLimitsConfig limits, ) { return SingleChildScrollView( + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.lg, + vertical: AppSpacing.sm, + ), child: Column( children: [ AppConfigIntField( diff --git a/lib/community_management/widgets/community_filter_dialog/community_filter_dialog.dart b/lib/community_management/widgets/community_filter_dialog/community_filter_dialog.dart index cebf96fc..6b647d3e 100644 --- a/lib/community_management/widgets/community_filter_dialog/community_filter_dialog.dart +++ b/lib/community_management/widgets/community_filter_dialog/community_filter_dialog.dart @@ -254,13 +254,13 @@ class _CommunityFilterDialogState extends State { labelBuilder: (item) => item.l10n(context), onChanged: (item) { context.read().add( - EngagementsFilterChanged( - EngagementsFilter( - searchQuery: state.engagementsFilter.searchQuery, - selectedStatus: item, - ), - ), - ); + EngagementsFilterChanged( + EngagementsFilter( + searchQuery: state.engagementsFilter.searchQuery, + selectedStatus: item, + ), + ), + ); }, ), ]; diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index ccac0c16..dd4abc09 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -269,7 +269,7 @@ abstract class AppLocalizations { /// Label for the app configuration navigation item /// /// In en, this message translates to: - /// **'App Configuration'** + /// **'Remote Config'** String get appConfiguration; /// Description for the App Configuration page @@ -287,7 +287,7 @@ abstract class AppLocalizations { /// Title for the App Configuration page /// /// In en, this message translates to: - /// **'App Configuration'** + /// **'Remote Configuration'** String get appConfigurationPageTitle; /// Tab title for Feed settings @@ -389,7 +389,7 @@ abstract class AppLocalizations { /// Snackbar message for successful app configuration save /// /// In en, this message translates to: - /// **'App configuration saved successfully!'** + /// **'Remote configuration saved successfully. Mobile clients will update on their next launch.'** String get appConfigSaveSuccessMessage; /// Snackbar message for app configuration save error @@ -3095,7 +3095,7 @@ abstract class AppLocalizations { /// Description for the feed item click behavior setting. /// /// In en, this message translates to: - /// **'Select which browser opens when a user taps on a headline in the feed.'** + /// **'Set the default browser for opening headlines. This can be overridden by users in their app\'s feed settings.'** String get feedItemClickBehaviorDescription; /// Option for opening links in the app's internal browser. @@ -3116,6 +3116,36 @@ abstract class AppLocalizations { /// **'User Limits'** String get userLimitsTitle; + /// Description for the User Limits expansion tile. + /// + /// In en, this message translates to: + /// **'Define limits for user-specific features and content.'** + String get userLimitsDescription; + + /// Description for the App Status & Updates expansion tile. + /// + /// In en, this message translates to: + /// **'Control the application\'s operational status and manage update requirements.'** + String get appStatusAndUpdatesDescription; + + /// Description for the Advertisements expansion tile. + /// + /// In en, this message translates to: + /// **'Manage all advertisement settings, including global controls, platforms, and placements.'** + String get advertisementsDescription; + + /// Description for the Notifications expansion tile. + /// + /// In en, this message translates to: + /// **'Configure the push notification system, including providers and delivery types.'** + String get notificationsDescription; + + /// Description for the Feed expansion tile. + /// + /// In en, this message translates to: + /// **'Control the behavior and appearance of the user\'s content feed.'** + String get feedDescription; + /// Description for the breaking news notification subscription limit. /// /// In en, this message translates to: @@ -3173,7 +3203,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 reporting system.'** + /// **'Configure user engagement and reporting tools. To ensure accountability, these features are unavailable for guest users within the mobile app, irrespective of the settings configured here.'** String get communityAndEngagementDescription; /// Title for the User Engagement expansion tile. @@ -3353,19 +3383,19 @@ abstract class AppLocalizations { /// Label for the 'save item' positive interaction type. /// /// In en, this message translates to: - /// **'Save a content item (e.g., a headline)'** + /// **'Save a content item'** String get positiveInteractionTypeSaveItem; /// Label for the 'follow item' positive interaction type. /// /// In en, this message translates to: - /// **'Follow an entity (e.g., a topic, source, or country)'** + /// **'Follow an entity'** String get positiveInteractionTypeFollowItem; /// Label for the 'share content' positive interaction type. /// /// In en, this message translates to: - /// **'Share a content item (e.g., a headline)'** + /// **'Share a content item'** String get positiveInteractionTypeShareContent; /// Label for the 'save filter' positive interaction type. @@ -4135,6 +4165,168 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'{itemType} \"{itemName}\" deleted.'** String itemDeletedSnackbar(String itemType, String itemName); + + /// Description for the Ad Platform Configuration expansion tile. + /// + /// In en, this message translates to: + /// **'Select the primary ad provider and configure their respective ad unit IDs.'** + String get adPlatformConfigurationDescription; + + /// Description for the Feed Ad Settings expansion tile. + /// + /// In en, this message translates to: + /// **'Control ad visibility, type, and frequency within the user\'s content feed.'** + String get feedAdSettingsDescription; + + /// Description for the Navigation Ad Settings expansion tile. + /// + /// In en, this message translates to: + /// **'Configure interstitial ads that appear during user navigation.'** + String get navigationAdConfigDescription; + + /// Description for the 'Link Account' feed decorator. + /// + /// In en, this message translates to: + /// **'Prompts guest users to create a full account.'** + String get feedDecoratorLinkAccountDescription; + + /// Description for the 'Upgrade' feed decorator. + /// + /// In en, this message translates to: + /// **'Prompts standard users to upgrade to a premium subscription.'** + String get feedDecoratorUpgradeDescription; + + /// Description for the 'Rate App' feed decorator. + /// + /// In en, this message translates to: + /// **'Prompts users to rate the application in the app store.'** + String get feedDecoratorRateAppDescription; + + /// Description for the 'Enable Notifications' feed decorator. + /// + /// In en, this message translates to: + /// **'Prompts users to enable push notifications.'** + String get feedDecoratorEnableNotificationsDescription; + + /// Description for the 'Suggested Topics' feed decorator. + /// + /// In en, this message translates to: + /// **'Shows a collection of topics the user might be interested in following.'** + String get feedDecoratorSuggestedTopicsDescription; + + /// Description for the 'Suggested Sources' feed decorator. + /// + /// In en, this message translates to: + /// **'Shows a collection of sources the user might be interested in following.'** + String get feedDecoratorSuggestedSourcesDescription; + + /// Description for the global ad enablement switch. + /// + /// In en, this message translates to: + /// **'Globally activates or deactivates all advertisements within the application.'** + String get enableGlobalAdsDescription; + + /// Description for the feed ad enablement switch. + /// + /// In en, this message translates to: + /// **'Controls the visibility of all ads within content feeds.'** + String get enableFeedAdsDescription; + + /// Generic description for a role-specific visibility switch. + /// + /// In en, this message translates to: + /// **'When enabled, this feature will be active for users with the \'{roleName}\' role.'** + String visibleToRoleDescription(String roleName); + + /// Description for the decorator enablement switch. + /// + /// In en, this message translates to: + /// **'Globally activates or deactivates this decorator for all eligible users.'** + String get enableDecoratorDescription; + + /// Description for the navigation ad enablement switch. + /// + /// In en, this message translates to: + /// **'Controls the visibility of interstitial ads that appear during user navigation.'** + String get enableNavigationAdsDescription; + + /// Description for the headline reporting switch. + /// + /// In en, this message translates to: + /// **'Allows users to report individual headlines for issues like misinformation or clickbait.'** + String get enableHeadlineReportingDescription; + + /// Description for the source reporting switch. + /// + /// In en, this message translates to: + /// **'Allows users to report entire news sources for issues like low quality or bias.'** + String get enableSourceReportingDescription; + + /// Description for the comment reporting switch. + /// + /// In en, this message translates to: + /// **'Allows users to report individual comments for moderation.'** + String get enableCommentReportingDescription; + + /// Description for the 'Breaking News' delivery type switch. + /// + /// In en, this message translates to: + /// **'Enable to allow users to subscribe to immediate alerts for breaking news.'** + String get pushNotificationDeliveryTypeBreakingOnlyDescription; + + /// Description for the 'Daily Digest' delivery type switch. + /// + /// In en, this message translates to: + /// **'Enable to allow users to subscribe to a daily summary of relevant news.'** + String get pushNotificationDeliveryTypeDailyDigestDescription; + + /// Description for the 'Weekly Roundup' delivery type switch. + /// + /// In en, this message translates to: + /// **'Enable to allow users to subscribe to a weekly roundup of relevant news.'** + String get pushNotificationDeliveryTypeWeeklyRoundupDescription; + + /// Description for the 'save item' positive interaction type switch. + /// + /// In en, this message translates to: + /// **'Counts when a user bookmark a headline.'** + String get positiveInteractionTypeSaveItemDescription; + + /// Description for the 'follow item' positive interaction type switch. + /// + /// In en, this message translates to: + /// **'Counts when a user follows a headline topic, source, or country.'** + String get positiveInteractionTypeFollowItemDescription; + + /// Description for the 'share content' positive interaction type switch. + /// + /// In en, this message translates to: + /// **'Counts when a user shares a headline.'** + String get positiveInteractionTypeShareContentDescription; + + /// Description for the 'save filter' positive interaction type switch. + /// + /// In en, this message translates to: + /// **'Counts when a user creates a saved filter.'** + String get positiveInteractionTypeSaveFilterDescription; + + /// Description for the internal prompt logic settings. + /// + /// In en, this message translates to: + /// **'Define the conditions that trigger the enjoyment prompt, such as the number of user actions and cooldown periods.'** + String get internalPromptLogicDescription; + + /// Description for the eligible positive interactions settings. + /// + /// In en, this message translates to: + /// **'Select which user actions are counted as \'positive interactions\' to trigger the enjoyment prompt.'** + String get eligiblePositiveInteractionsDescription; + + /// Description for the follow-up actions settings. + /// + /// In en, this message translates to: + /// **'Configure what happens after a user responds to the enjoyment prompt, such as requesting a store review.'** + String get followUpActionsDescription; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart index 74295f99..cab4677f 100644 --- a/lib/l10n/app_localizations_ar.dart +++ b/lib/l10n/app_localizations_ar.dart @@ -105,7 +105,7 @@ class AppLocalizationsAr extends AppLocalizations { String get source => 'المصدر'; @override - String get appConfiguration => 'إعدادات التطبيق'; + String get appConfiguration => 'التحكم المركزي'; @override String get appConfigurationPageDescription => @@ -115,7 +115,7 @@ class AppLocalizationsAr extends AppLocalizations { String get settings => 'الإعدادات'; @override - String get appConfigurationPageTitle => 'إعدادات التطبيق'; + String get appConfigurationPageTitle => 'التحكم المركزي عن بعد'; @override String get feedTab => 'الموجز'; @@ -172,7 +172,8 @@ class AppLocalizationsAr extends AppLocalizations { String get forceUpdateTab => 'تحديث إجباري'; @override - String get appConfigSaveSuccessMessage => 'تم حفظ إعدادات التطبيق بنجاح!'; + String get appConfigSaveSuccessMessage => + 'تم حفظ الإعدادات عن بعد بنجاح. ستعكس تطبيقات الجوال هذه التغييرات عند تشغيلها التالي.'; @override String appConfigSaveErrorMessage(String errorMessage) { @@ -1661,7 +1662,7 @@ class AppLocalizationsAr extends AppLocalizations { @override String get feedItemClickBehaviorDescription => - 'اختر المتصفح الذي يفتح عند نقر المستخدم على عنوان في الموجز.'; + 'قم بتعيين المتصفح الافتراضي لفتح العناوين. يمكن للمستخدمين تجاوز هذا الإعداد في إعدادات الموجز الخاصة بهم في التطبيق.'; @override String get feedItemClickBehaviorInternalNavigation => 'متصفح داخل التطبيق'; @@ -1672,6 +1673,25 @@ class AppLocalizationsAr extends AppLocalizations { @override String get userLimitsTitle => 'حدود المستخدم'; + @override + String get userLimitsDescription => + 'تحديد حدود للميزات والمحتوى الخاص بالمستخدم.'; + + @override + String get appStatusAndUpdatesDescription => + 'التحكم في الحالة التشغيلية للتطبيق وإدارة متطلبات التحديث.'; + + @override + String get advertisementsDescription => + 'إدارة جميع إعدادات الإعلانات، بما في ذلك الضوابط العالمية والمنصات والمواضع.'; + + @override + String get notificationsDescription => + 'تكوين نظام الإشعارات الفورية، بما في ذلك المزودين وأنواع التسليم.'; + + @override + String get feedDescription => 'التحكم في سلوك ومظهر موجز محتوى المستخدم.'; + @override String get notificationSubscriptionBreakingOnlyDescription => 'حد الاشتراكات التي ترسل تنبيهات فورية للأخبار العاجلة للعناوين المطابقة.'; @@ -1706,7 +1726,7 @@ class AppLocalizationsAr extends AppLocalizations { @override String get communityAndEngagementDescription => - 'إدارة تفاعلات المستخدمين، والإبلاغ عن المحتوى، ونظام مراجعات التطبيق الداخلي.'; + 'تكوين أدوات تفاعل المستخدمين والإبلاغ. لضمان المساءلة، هذه الميزات غير متاحة للمستخدمين الضيوف داخل تطبيق الجوال، بغض النظر عن الإعدادات المكونة هنا.'; @override String get userEngagementTitle => 'مشاركة المستخدم'; @@ -1806,16 +1826,13 @@ class AppLocalizationsAr extends AppLocalizations { String get eligiblePositiveInteractionsTitle => 'التفاعلات الإيجابية المؤهلة'; @override - String get positiveInteractionTypeSaveItem => - 'حفظ عنصر محتوى (مثل عنوان رئيسي)'; + String get positiveInteractionTypeSaveItem => 'حفظ عنصر محتوى'; @override - String get positiveInteractionTypeFollowItem => - 'متابعة كيان (مثل موضوع أو مصدر أو بلد)'; + String get positiveInteractionTypeFollowItem => 'متابعة كيان '; @override - String get positiveInteractionTypeShareContent => - 'مشاركة عنصر محتوى (مثل عنوان رئيسي)'; + String get positiveInteractionTypeShareContent => 'مشاركة عنصر محتوى'; @override String get positiveInteractionTypeSaveFilter => 'إنشاء مرشح محفوظ'; @@ -2235,4 +2252,113 @@ class AppLocalizationsAr extends AppLocalizations { String itemDeletedSnackbar(String itemType, String itemName) { return 'تم حذف $itemType \"$itemName\".'; } + + @override + String get adPlatformConfigurationDescription => + 'اختر مزود الإعلانات الأساسي وقم بتكوين معرفات الوحدات الإعلانية الخاصة به.'; + + @override + String get feedAdSettingsDescription => + 'تحكم في رؤية الإعلانات ونوعها وتكرارها داخل موجز محتوى المستخدم.'; + + @override + String get navigationAdConfigDescription => + 'تكوين الإعلانات البينية التي تظهر أثناء تنقل المستخدم.'; + + @override + String get feedDecoratorLinkAccountDescription => + 'يطالب المستخدمين الضيوف بإنشاء حساب كامل.'; + + @override + String get feedDecoratorUpgradeDescription => + 'يطالب المستخدمين العاديين بالترقية إلى اشتراك مميز.'; + + @override + String get feedDecoratorRateAppDescription => + 'يطالب المستخدمين بتقييم التطبيق في متجر التطبيقات.'; + + @override + String get feedDecoratorEnableNotificationsDescription => + 'يطالب المستخدمين بتمكين الإشعارات الفورية.'; + + @override + String get feedDecoratorSuggestedTopicsDescription => + 'يعرض مجموعة من المواضيع التي قد يهتم المستخدم بمتابعتها.'; + + @override + String get feedDecoratorSuggestedSourcesDescription => + 'يعرض مجموعة من المصادر التي قد يهتم المستخدم بمتابعتها.'; + + @override + String get enableGlobalAdsDescription => + 'ينشط أو يعطل عالميًا جميع الإعلانات داخل التطبيق.'; + + @override + String get enableFeedAdsDescription => + 'يتحكم في رؤية جميع الإعلانات داخل موجزات المحتوى.'; + + @override + String visibleToRoleDescription(String roleName) { + return 'عند التمكين، ستكون هذه الميزة نشطة للمستخدمين الذين لديهم دور \'$roleName\'.'; + } + + @override + String get enableDecoratorDescription => + 'ينشط أو يعطل عالميًا هذه الزينة لجميع المستخدمين المؤهلين.'; + + @override + String get enableNavigationAdsDescription => + 'يتحكم في رؤية الإعلانات البينية التي تظهر أثناء تنقل المستخدم.'; + + @override + String get enableHeadlineReportingDescription => + 'يسمح للمستخدمين بالإبلاغ عن العناوين الفردية لمشاكل مثل المعلومات المضللة أو العناوين المضللة.'; + + @override + String get enableSourceReportingDescription => + 'يسمح للمستخدمين بالإبلاغ عن مصادر الأخبار بأكملها لمشاكل مثل الجودة المنخفضة أو التحيز.'; + + @override + String get enableCommentReportingDescription => + 'يسمح للمستخدمين بالإبلاغ عن التعليقات الفردية للإشراف عليها.'; + + @override + String get pushNotificationDeliveryTypeBreakingOnlyDescription => + 'تفعيل للسماح للمستخدمين بالاشتراك في التنبيهات الفورية للأخبار العاجلة.'; + + @override + String get pushNotificationDeliveryTypeDailyDigestDescription => + 'تفعيل للسماح للمستخدمين بالاشتراك في ملخص يومي للأخبار ذات الصلة.'; + + @override + String get pushNotificationDeliveryTypeWeeklyRoundupDescription => + 'تفعيل للسماح للمستخدمين بالاشتراك في ملخص أسبوعي للأخبار ذات الصلة.'; + + @override + String get positiveInteractionTypeSaveItemDescription => + 'يحتسب عندما يحفظ المستخدم عنوان رئيسي.'; + + @override + String get positiveInteractionTypeFollowItemDescription => + 'يحتسب عندما يتابع المستخدم موضوعًا أو مصدرًا أو بلدًا مثل لعنوان رئيسي.'; + + @override + String get positiveInteractionTypeShareContentDescription => + 'يحتسب عندما يشارك المستخدم عنوان رئيسي.'; + + @override + String get positiveInteractionTypeSaveFilterDescription => + 'يحتسب عندما ينشئ المستخدم مرشحًا محفوظًا.'; + + @override + String get internalPromptLogicDescription => + 'تحديد الشروط التي تؤدي إلى ظهور موجه الاستمتاع، مثل عدد إجراءات المستخدم وفترات التهدئة.'; + + @override + String get eligiblePositiveInteractionsDescription => + 'اختر إجراءات المستخدم التي تُحتسب \'كتفاعلات إيجابية\' لتشغيل موجه الاستمتاع.'; + + @override + String get followUpActionsDescription => + 'تكوين ما يحدث بعد استجابة المستخدم لموجه الاستمتاع، مثل طلب مراجعة المتجر.'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index a6cf159b..f7234eca 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -104,7 +104,7 @@ class AppLocalizationsEn extends AppLocalizations { String get source => 'Source'; @override - String get appConfiguration => 'App Configuration'; + String get appConfiguration => 'Remote Config'; @override String get appConfigurationPageDescription => @@ -114,7 +114,7 @@ class AppLocalizationsEn extends AppLocalizations { String get settings => 'Settings'; @override - String get appConfigurationPageTitle => 'App Configuration'; + String get appConfigurationPageTitle => 'Remote Configuration'; @override String get feedTab => 'Feed'; @@ -172,7 +172,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get appConfigSaveSuccessMessage => - 'App configuration saved successfully!'; + 'Remote configuration saved successfully. Mobile clients will update on their next launch.'; @override String appConfigSaveErrorMessage(String errorMessage) { @@ -1664,7 +1664,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get feedItemClickBehaviorDescription => - 'Select which browser opens when a user taps on a headline in the feed.'; + 'Set the default browser for opening headlines. This can be overridden by users in their app\'s feed settings.'; @override String get feedItemClickBehaviorInternalNavigation => 'In-App Browser'; @@ -1675,6 +1675,26 @@ class AppLocalizationsEn extends AppLocalizations { @override String get userLimitsTitle => 'User Limits'; + @override + String get userLimitsDescription => + 'Define limits for user-specific features and content.'; + + @override + String get appStatusAndUpdatesDescription => + 'Control the application\'s operational status and manage update requirements.'; + + @override + String get advertisementsDescription => + 'Manage all advertisement settings, including global controls, platforms, and placements.'; + + @override + String get notificationsDescription => + 'Configure the push notification system, including providers and delivery types.'; + + @override + String get feedDescription => + 'Control the behavior and appearance of the user\'s content feed.'; + @override String get notificationSubscriptionBreakingOnlyDescription => 'Limit for subscriptions that send immediate alerts for matching headlines.'; @@ -1709,7 +1729,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get communityAndEngagementDescription => - 'Manage user interactions, content reporting, and the internal app reporting system.'; + 'Configure user engagement and reporting tools. To ensure accountability, these features are unavailable for guest users within the mobile app, irrespective of the settings configured here.'; @override String get userEngagementTitle => 'User Engagement'; @@ -1811,16 +1831,13 @@ class AppLocalizationsEn extends AppLocalizations { 'Eligible Positive Interactions'; @override - String get positiveInteractionTypeSaveItem => - 'Save a content item (e.g., a headline)'; + String get positiveInteractionTypeSaveItem => 'Save a content item'; @override - String get positiveInteractionTypeFollowItem => - 'Follow an entity (e.g., a topic, source, or country)'; + String get positiveInteractionTypeFollowItem => 'Follow an entity'; @override - String get positiveInteractionTypeShareContent => - 'Share a content item (e.g., a headline)'; + String get positiveInteractionTypeShareContent => 'Share a content item'; @override String get positiveInteractionTypeSaveFilter => 'Create a saved filter'; @@ -2241,4 +2258,113 @@ class AppLocalizationsEn extends AppLocalizations { String itemDeletedSnackbar(String itemType, String itemName) { return '$itemType \"$itemName\" deleted.'; } + + @override + String get adPlatformConfigurationDescription => + 'Select the primary ad provider and configure their respective ad unit IDs.'; + + @override + String get feedAdSettingsDescription => + 'Control ad visibility, type, and frequency within the user\'s content feed.'; + + @override + String get navigationAdConfigDescription => + 'Configure interstitial ads that appear during user navigation.'; + + @override + String get feedDecoratorLinkAccountDescription => + 'Prompts guest users to create a full account.'; + + @override + String get feedDecoratorUpgradeDescription => + 'Prompts standard users to upgrade to a premium subscription.'; + + @override + String get feedDecoratorRateAppDescription => + 'Prompts users to rate the application in the app store.'; + + @override + String get feedDecoratorEnableNotificationsDescription => + 'Prompts users to enable push notifications.'; + + @override + String get feedDecoratorSuggestedTopicsDescription => + 'Shows a collection of topics the user might be interested in following.'; + + @override + String get feedDecoratorSuggestedSourcesDescription => + 'Shows a collection of sources the user might be interested in following.'; + + @override + String get enableGlobalAdsDescription => + 'Globally activates or deactivates all advertisements within the application.'; + + @override + String get enableFeedAdsDescription => + 'Controls the visibility of all ads within content feeds.'; + + @override + String visibleToRoleDescription(String roleName) { + return 'When enabled, this feature will be active for users with the \'$roleName\' role.'; + } + + @override + String get enableDecoratorDescription => + 'Globally activates or deactivates this decorator for all eligible users.'; + + @override + String get enableNavigationAdsDescription => + 'Controls the visibility of interstitial ads that appear during user navigation.'; + + @override + String get enableHeadlineReportingDescription => + 'Allows users to report individual headlines for issues like misinformation or clickbait.'; + + @override + String get enableSourceReportingDescription => + 'Allows users to report entire news sources for issues like low quality or bias.'; + + @override + String get enableCommentReportingDescription => + 'Allows users to report individual comments for moderation.'; + + @override + String get pushNotificationDeliveryTypeBreakingOnlyDescription => + 'Enable to allow users to subscribe to immediate alerts for breaking news.'; + + @override + String get pushNotificationDeliveryTypeDailyDigestDescription => + 'Enable to allow users to subscribe to a daily summary of relevant news.'; + + @override + String get pushNotificationDeliveryTypeWeeklyRoundupDescription => + 'Enable to allow users to subscribe to a weekly roundup of relevant news.'; + + @override + String get positiveInteractionTypeSaveItemDescription => + 'Counts when a user bookmark a headline.'; + + @override + String get positiveInteractionTypeFollowItemDescription => + 'Counts when a user follows a headline topic, source, or country.'; + + @override + String get positiveInteractionTypeShareContentDescription => + 'Counts when a user shares a headline.'; + + @override + String get positiveInteractionTypeSaveFilterDescription => + 'Counts when a user creates a saved filter.'; + + @override + String get internalPromptLogicDescription => + 'Define the conditions that trigger the enjoyment prompt, such as the number of user actions and cooldown periods.'; + + @override + String get eligiblePositiveInteractionsDescription => + 'Select which user actions are counted as \'positive interactions\' to trigger the enjoyment prompt.'; + + @override + String get followUpActionsDescription => + 'Configure what happens after a user responds to the enjoyment prompt, such as requesting a store review.'; } diff --git a/lib/l10n/arb/app_ar.arb b/lib/l10n/arb/app_ar.arb index 70baa956..6844f8ee 100644 --- a/lib/l10n/arb/app_ar.arb +++ b/lib/l10n/arb/app_ar.arb @@ -127,7 +127,7 @@ "@source": { "description": "تسمية المصدر" }, - "appConfiguration": "إعدادات التطبيق", + "appConfiguration": "التحكم المركزي", "@appConfiguration": { "description": "تسمية عنصر التنقل لإعدادات التطبيق" }, @@ -139,7 +139,7 @@ "@settings": { "description": "تسمية عنصر التنقل للإعدادات" }, - "appConfigurationPageTitle": "إعدادات التطبيق", + "appConfigurationPageTitle": "التحكم المركزي عن بعد", "@appConfigurationPageTitle": { "description": "عنوان صفحة إعدادات التطبيق" }, @@ -207,7 +207,7 @@ "@forceUpdateTab": { "description": "عنوان تبويب تحديث إجباري" }, - "appConfigSaveSuccessMessage": "تم حفظ إعدادات التطبيق بنجاح!", + "appConfigSaveSuccessMessage": "تم حفظ الإعدادات عن بعد بنجاح. ستعكس تطبيقات الجوال هذه التغييرات عند تشغيلها التالي.", "@appConfigSaveSuccessMessage": { "description": "رسالة شريط التنبيه لحفظ إعدادات التطبيق بنجاح" }, @@ -2082,7 +2082,7 @@ "@feedItemClickBehaviorTitle": { "description": "عنوان إعداد سلوك النقر على عنصر الموجز." }, - "feedItemClickBehaviorDescription": "اختر المتصفح الذي يفتح عند نقر المستخدم على عنوان في الموجز.", + "feedItemClickBehaviorDescription": "قم بتعيين المتصفح الافتراضي لفتح العناوين. يمكن للمستخدمين تجاوز هذا الإعداد في إعدادات الموجز الخاصة بهم في التطبيق.", "@feedItemClickBehaviorDescription": { "description": "وصف إعداد سلوك النقر على عنصر الموجز." }, @@ -2098,6 +2098,26 @@ "@userLimitsTitle": { "description": "عنوان قسم حدود المستخدم القابل للتوسيع." }, + "userLimitsDescription": "تحديد حدود للميزات والمحتوى الخاص بالمستخدم.", + "@userLimitsDescription": { + "description": "وصف قسم حدود المستخدم القابل للتوسيع." + }, + "appStatusAndUpdatesDescription": "التحكم في الحالة التشغيلية للتطبيق وإدارة متطلبات التحديث.", + "@appStatusAndUpdatesDescription": { + "description": "وصف قسم حالة التطبيق والتحديثات القابل للتوسيع." + }, + "advertisementsDescription": "إدارة جميع إعدادات الإعلانات، بما في ذلك الضوابط العالمية والمنصات والمواضع.", + "@advertisementsDescription": { + "description": "وصف قسم الإعلانات القابل للتوسيع." + }, + "notificationsDescription": "تكوين نظام الإشعارات الفورية، بما في ذلك المزودين وأنواع التسليم.", + "@notificationsDescription": { + "description": "وصف قسم الإشعارات القابل للتوسيع." + }, + "feedDescription": "التحكم في سلوك ومظهر موجز محتوى المستخدم.", + "@feedDescription": { + "description": "وصف قسم الموجز القابل للتوسيع." + }, "notificationSubscriptionBreakingOnlyDescription": "حد الاشتراكات التي ترسل تنبيهات فورية للأخبار العاجلة للعناوين المطابقة.", "@notificationSubscriptionBreakingOnlyDescription": { "description": "وصف لحد اشتراك إشعارات الأخبار العاجلة." @@ -2134,7 +2154,7 @@ "@communityAndEngagementTitle": { "description": "عنوان قسم المجتمع والمشاركة القابل للتوسيع." }, - "communityAndEngagementDescription": "إدارة تفاعلات المستخدمين، والإبلاغ عن المحتوى، ونظام مراجعات التطبيق الداخلي.", + "communityAndEngagementDescription": "تكوين أدوات تفاعل المستخدمين والإبلاغ. لضمان المساءلة، هذه الميزات غير متاحة للمستخدمين الضيوف داخل تطبيق الجوال، بغض النظر عن الإعدادات المكونة هنا.", "@communityAndEngagementDescription": { "description": "وصف قسم المجتمع والمشاركة القابل للتوسيع." }, @@ -2254,15 +2274,15 @@ "@eligiblePositiveInteractionsTitle": { "description": "عنوان قسم التفاعلات الإيجابية المؤهلة." }, - "positiveInteractionTypeSaveItem": "حفظ عنصر محتوى (مثل عنوان رئيسي)", + "positiveInteractionTypeSaveItem": "حفظ عنصر محتوى", "@positiveInteractionTypeSaveItem": { "description": "تسمية نوع التفاعل الإيجابي 'حفظ عنصر'." }, - "positiveInteractionTypeFollowItem": "متابعة كيان (مثل موضوع أو مصدر أو بلد)", + "positiveInteractionTypeFollowItem": "متابعة كيان ", "@positiveInteractionTypeFollowItem": { "description": "تسمية نوع التفاعل الإيجابي 'متابعة عنصر'." }, - "positiveInteractionTypeShareContent": "مشاركة عنصر محتوى (مثل عنوان رئيسي)", + "positiveInteractionTypeShareContent": "مشاركة عنصر محتوى", "@positiveInteractionTypeShareContent": { "description": "تسمية نوع التفاعل الإيجابي 'مشاركة محتوى'." }, @@ -2318,7 +2338,7 @@ "@commentStatus": { "description": "تسمية لحالة الإشراف على تعليق ضمن تفاعل." }, -"hasCommentFilterLabel": "تحتوي على تعليقات", + "hasCommentFilterLabel": "تحتوي على تعليقات", "@hasCommentFilterLabel": { "description": "تسمية لمفتاح تصفية التفاعلات بناءً على وجود تعليق." }, @@ -2858,5 +2878,118 @@ "example": "Breaking News Story" } } + }, + "adPlatformConfigurationDescription": "اختر مزود الإعلانات الأساسي وقم بتكوين معرفات الوحدات الإعلانية الخاصة به.", + "@adPlatformConfigurationDescription": { + "description": "وصف قسم تكوين منصة الإعلانات القابل للتوسيع." + }, + "feedAdSettingsDescription": "تحكم في رؤية الإعلانات ونوعها وتكرارها داخل موجز محتوى المستخدم.", + "@feedAdSettingsDescription": { + "description": "وصف قسم إعدادات إعلانات الموجز القابل للتوسيع." + }, + "navigationAdConfigDescription": "تكوين الإعلانات البينية التي تظهر أثناء تنقل المستخدم.", + "@navigationAdConfigDescription": { + "description": "وصف قسم إعدادات إعلانات التنقل القابل للتوسيع." + }, + "feedDecoratorLinkAccountDescription": "يطالب المستخدمين الضيوف بإنشاء حساب كامل.", + "@feedDecoratorLinkAccountDescription": { + "description": "وصف لزينة 'ربط الحساب' في الموجز." + }, + "feedDecoratorUpgradeDescription": "يطالب المستخدمين العاديين بالترقية إلى اشتراك مميز.", + "@feedDecoratorUpgradeDescription": { + "description": "وصف لزينة 'الترقية' في الموجز." + }, + "feedDecoratorRateAppDescription": "يطالب المستخدمين بتقييم التطبيق في متجر التطبيقات.", + "@feedDecoratorRateAppDescription": { + "description": "وصف لزينة 'تقييم التطبيق' في الموجز." + }, + "feedDecoratorEnableNotificationsDescription": "يطالب المستخدمين بتمكين الإشعارات الفورية.", + "@feedDecoratorEnableNotificationsDescription": { + "description": "وصف لزينة 'تفعيل الإشعارات' في الموجز." + }, + "feedDecoratorSuggestedTopicsDescription": "يعرض مجموعة من المواضيع التي قد يهتم المستخدم بمتابعتها.", + "@feedDecoratorSuggestedTopicsDescription": { + "description": "وصف لزينة 'المواضيع المقترحة' في الموجز." + }, + "feedDecoratorSuggestedSourcesDescription": "يعرض مجموعة من المصادر التي قد يهتم المستخدم بمتابعتها.", + "@feedDecoratorSuggestedSourcesDescription": { + "description": "وصف لزينة 'المصادر المقترحة' في الموجز." + }, + "enableGlobalAdsDescription": "ينشط أو يعطل عالميًا جميع الإعلانات داخل التطبيق.", + "@enableGlobalAdsDescription": { + "description": "وصف لمفتاح تفعيل الإعلانات العالمي." + }, + "enableFeedAdsDescription": "يتحكم في رؤية جميع الإعلانات داخل موجزات المحتوى.", + "@enableFeedAdsDescription": { + "description": "وصف لمفتاح تفعيل إعلانات الموجز." + }, + "visibleToRoleDescription": "عند التمكين، ستكون هذه الميزة نشطة للمستخدمين الذين لديهم دور '{roleName}'.", + "@visibleToRoleDescription": { + "description": "وصف عام لمفتاح الرؤية الخاص بدور معين.", + "placeholders": { + "roleName": { + "type": "String" + } + } + }, + "enableDecoratorDescription": "ينشط أو يعطل عالميًا هذه الزينة لجميع المستخدمين المؤهلين.", + "@enableDecoratorDescription": { + "description": "وصف لمفتاح تفعيل الزينة." + }, + "enableNavigationAdsDescription": "يتحكم في رؤية الإعلانات البينية التي تظهر أثناء تنقل المستخدم.", + "@enableNavigationAdsDescription": { + "description": "وصف لمفتاح تفعيل إعلانات التنقل." + }, + "enableHeadlineReportingDescription": "يسمح للمستخدمين بالإبلاغ عن العناوين الفردية لمشاكل مثل المعلومات المضللة أو العناوين المضللة.", + "@enableHeadlineReportingDescription": { + "description": "وصف لمفتاح الإبلاغ عن العناوين." + }, + "enableSourceReportingDescription": "يسمح للمستخدمين بالإبلاغ عن مصادر الأخبار بأكملها لمشاكل مثل الجودة المنخفضة أو التحيز.", + "@enableSourceReportingDescription": { + "description": "وصف لمفتاح الإبلاغ عن المصادر." + }, + "enableCommentReportingDescription": "يسمح للمستخدمين بالإبلاغ عن التعليقات الفردية للإشراف عليها.", + "@enableCommentReportingDescription": { + "description": "وصف لمفتاح الإبلاغ عن التعليقات." + }, + "pushNotificationDeliveryTypeBreakingOnlyDescription": "تفعيل للسماح للمستخدمين بالاشتراك في التنبيهات الفورية للأخبار العاجلة.", + "@pushNotificationDeliveryTypeBreakingOnlyDescription": { + "description": "وصف لمفتاح نوع التسليم 'الأخبار العاجلة'." + }, + "pushNotificationDeliveryTypeDailyDigestDescription": "تفعيل للسماح للمستخدمين بالاشتراك في ملخص يومي للأخبار ذات الصلة.", + "@pushNotificationDeliveryTypeDailyDigestDescription": { + "description": "وصف لمفتاح نوع التسليم 'الملخص اليومي'." + }, + "pushNotificationDeliveryTypeWeeklyRoundupDescription": "تفعيل للسماح للمستخدمين بالاشتراك في ملخص أسبوعي للأخبار ذات الصلة.", + "@pushNotificationDeliveryTypeWeeklyRoundupDescription": { + "description": "وصف لمفتاح نوع التسليم 'حصاد الأسبوع'." + }, + "positiveInteractionTypeSaveItemDescription": "يحتسب عندما يحفظ المستخدم عنوان رئيسي.", + "@positiveInteractionTypeSaveItemDescription": { + "description": "وصف لمفتاح نوع التفاعل الإيجابي 'حفظ عنصر'." + }, + "positiveInteractionTypeFollowItemDescription": "يحتسب عندما يتابع المستخدم موضوعًا أو مصدرًا أو بلدًا مثل لعنوان رئيسي.", + "@positiveInteractionTypeFollowItemDescription": { + "description": "وصف لمفتاح نوع التفاعل الإيجابي 'متابعة عنصر'." + }, + "positiveInteractionTypeShareContentDescription": "يحتسب عندما يشارك المستخدم عنوان رئيسي.", + "@positiveInteractionTypeShareContentDescription": { + "description": "وصف لمفتاح نوع التفاعل الإيجابي 'مشاركة محتوى'." + }, + "positiveInteractionTypeSaveFilterDescription": "يحتسب عندما ينشئ المستخدم مرشحًا محفوظًا.", + "@positiveInteractionTypeSaveFilterDescription": { + "description": "وصف لمفتاح نوع التفاعل الإيجابي 'حفظ مرشح'." + }, + "internalPromptLogicDescription": "تحديد الشروط التي تؤدي إلى ظهور موجه الاستمتاع، مثل عدد إجراءات المستخدم وفترات التهدئة.", + "@internalPromptLogicDescription": { + "description": "وصف لإعدادات منطق الموجه الداخلي." + }, + "eligiblePositiveInteractionsDescription": "اختر إجراءات المستخدم التي تُحتسب 'كتفاعلات إيجابية' لتشغيل موجه الاستمتاع.", + "@eligiblePositiveInteractionsDescription": { + "description": "وصف لإعدادات التفاعلات الإيجابية المؤهلة." + }, + "followUpActionsDescription": "تكوين ما يحدث بعد استجابة المستخدم لموجه الاستمتاع، مثل طلب مراجعة المتجر.", + "@followUpActionsDescription": { + "description": "وصف لإعدادات إجراءات المتابعة." } } \ No newline at end of file diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index f9940e7d..97d630c6 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -127,7 +127,7 @@ "@source": { "description": "Label for the a singular source" }, - "appConfiguration": "App Configuration", + "appConfiguration": "Remote Config", "@appConfiguration": { "description": "Label for the app configuration navigation item" }, @@ -139,7 +139,7 @@ "@settings": { "description": "Label for the settings navigation item" }, - "appConfigurationPageTitle": "App Configuration", + "appConfigurationPageTitle": "Remote Configuration", "@appConfigurationPageTitle": { "description": "Title for the App Configuration page" }, @@ -207,7 +207,7 @@ "@forceUpdateTab": { "description": "Tab title for Force Update" }, - "appConfigSaveSuccessMessage": "App configuration saved successfully!", + "appConfigSaveSuccessMessage": "Remote configuration saved successfully. Mobile clients will update on their next launch.", "@appConfigSaveSuccessMessage": { "description": "Snackbar message for successful app configuration save" }, @@ -2078,7 +2078,7 @@ "@feedItemClickBehaviorTitle": { "description": "Title for the feed item click behavior setting." }, - "feedItemClickBehaviorDescription": "Select which browser opens when a user taps on a headline in the feed.", + "feedItemClickBehaviorDescription": "Set the default browser for opening headlines. This can be overridden by users in their app's feed settings.", "@feedItemClickBehaviorDescription": { "description": "Description for the feed item click behavior setting." }, @@ -2094,6 +2094,26 @@ "@userLimitsTitle": { "description": "Title for the User Limits expansion tile." }, + "userLimitsDescription": "Define limits for user-specific features and content.", + "@userLimitsDescription": { + "description": "Description for the User Limits expansion tile." + }, + "appStatusAndUpdatesDescription": "Control the application's operational status and manage update requirements.", + "@appStatusAndUpdatesDescription": { + "description": "Description for the App Status & Updates expansion tile." + }, + "advertisementsDescription": "Manage all advertisement settings, including global controls, platforms, and placements.", + "@advertisementsDescription": { + "description": "Description for the Advertisements expansion tile." + }, + "notificationsDescription": "Configure the push notification system, including providers and delivery types.", + "@notificationsDescription": { + "description": "Description for the Notifications expansion tile." + }, + "feedDescription": "Control the behavior and appearance of the user's content feed.", + "@feedDescription": { + "description": "Description for the Feed expansion tile." + }, "notificationSubscriptionBreakingOnlyDescription": "Limit for subscriptions that send immediate alerts for matching headlines.", "@notificationSubscriptionBreakingOnlyDescription": { "description": "Description for the breaking news notification subscription limit." @@ -2130,7 +2150,7 @@ "@communityAndEngagementTitle": { "description": "Title for the Community & Engagement expansion tile." }, - "communityAndEngagementDescription": "Manage user interactions, content reporting, and the internal app reporting system.", + "communityAndEngagementDescription": "Configure user engagement and reporting tools. To ensure accountability, these features are unavailable for guest users within the mobile app, irrespective of the settings configured here.", "@communityAndEngagementDescription": { "description": "Description for the Community & Engagement expansion tile." }, @@ -2250,15 +2270,15 @@ "@eligiblePositiveInteractionsTitle": { "description": "Title for the expansion tile for eligible positive interactions." }, - "positiveInteractionTypeSaveItem": "Save a content item (e.g., a headline)", + "positiveInteractionTypeSaveItem": "Save a content item", "@positiveInteractionTypeSaveItem": { "description": "Label for the 'save item' positive interaction type." }, - "positiveInteractionTypeFollowItem": "Follow an entity (e.g., a topic, source, or country)", + "positiveInteractionTypeFollowItem": "Follow an entity", "@positiveInteractionTypeFollowItem": { "description": "Label for the 'follow item' positive interaction type." }, - "positiveInteractionTypeShareContent": "Share a content item (e.g., a headline)", + "positiveInteractionTypeShareContent": "Share a content item", "@positiveInteractionTypeShareContent": { "description": "Label for the 'share content' positive interaction type." }, @@ -2854,5 +2874,118 @@ "example": "Breaking News Story" } } + }, + "adPlatformConfigurationDescription": "Select the primary ad provider and configure their respective ad unit IDs.", + "@adPlatformConfigurationDescription": { + "description": "Description for the Ad Platform Configuration expansion tile." + }, + "feedAdSettingsDescription": "Control ad visibility, type, and frequency within the user's content feed.", + "@feedAdSettingsDescription": { + "description": "Description for the Feed Ad Settings expansion tile." + }, + "navigationAdConfigDescription": "Configure interstitial ads that appear during user navigation.", + "@navigationAdConfigDescription": { + "description": "Description for the Navigation Ad Settings expansion tile." + }, + "feedDecoratorLinkAccountDescription": "Prompts guest users to create a full account.", + "@feedDecoratorLinkAccountDescription": { + "description": "Description for the 'Link Account' feed decorator." + }, + "feedDecoratorUpgradeDescription": "Prompts standard users to upgrade to a premium subscription.", + "@feedDecoratorUpgradeDescription": { + "description": "Description for the 'Upgrade' feed decorator." + }, + "feedDecoratorRateAppDescription": "Prompts users to rate the application in the app store.", + "@feedDecoratorRateAppDescription": { + "description": "Description for the 'Rate App' feed decorator." + }, + "feedDecoratorEnableNotificationsDescription": "Prompts users to enable push notifications.", + "@feedDecoratorEnableNotificationsDescription": { + "description": "Description for the 'Enable Notifications' feed decorator." + }, + "feedDecoratorSuggestedTopicsDescription": "Shows a collection of topics the user might be interested in following.", + "@feedDecoratorSuggestedTopicsDescription": { + "description": "Description for the 'Suggested Topics' feed decorator." + }, + "feedDecoratorSuggestedSourcesDescription": "Shows a collection of sources the user might be interested in following.", + "@feedDecoratorSuggestedSourcesDescription": { + "description": "Description for the 'Suggested Sources' feed decorator." + }, + "enableGlobalAdsDescription": "Globally activates or deactivates all advertisements within the application.", + "@enableGlobalAdsDescription": { + "description": "Description for the global ad enablement switch." + }, + "enableFeedAdsDescription": "Controls the visibility of all ads within content feeds.", + "@enableFeedAdsDescription": { + "description": "Description for the feed ad enablement switch." + }, + "visibleToRoleDescription": "When enabled, this feature will be active for users with the '{roleName}' role.", + "@visibleToRoleDescription": { + "description": "Generic description for a role-specific visibility switch.", + "placeholders": { + "roleName": { + "type": "String" + } + } + }, + "enableDecoratorDescription": "Globally activates or deactivates this decorator for all eligible users.", + "@enableDecoratorDescription": { + "description": "Description for the decorator enablement switch." + }, + "enableNavigationAdsDescription": "Controls the visibility of interstitial ads that appear during user navigation.", + "@enableNavigationAdsDescription": { + "description": "Description for the navigation ad enablement switch." + }, + "enableHeadlineReportingDescription": "Allows users to report individual headlines for issues like misinformation or clickbait.", + "@enableHeadlineReportingDescription": { + "description": "Description for the headline reporting switch." + }, + "enableSourceReportingDescription": "Allows users to report entire news sources for issues like low quality or bias.", + "@enableSourceReportingDescription": { + "description": "Description for the source reporting switch." + }, + "enableCommentReportingDescription": "Allows users to report individual comments for moderation.", + "@enableCommentReportingDescription": { + "description": "Description for the comment reporting switch." + }, + "pushNotificationDeliveryTypeBreakingOnlyDescription": "Enable to allow users to subscribe to immediate alerts for breaking news.", + "@pushNotificationDeliveryTypeBreakingOnlyDescription": { + "description": "Description for the 'Breaking News' delivery type switch." + }, + "pushNotificationDeliveryTypeDailyDigestDescription": "Enable to allow users to subscribe to a daily summary of relevant news.", + "@pushNotificationDeliveryTypeDailyDigestDescription": { + "description": "Description for the 'Daily Digest' delivery type switch." + }, + "pushNotificationDeliveryTypeWeeklyRoundupDescription": "Enable to allow users to subscribe to a weekly roundup of relevant news.", + "@pushNotificationDeliveryTypeWeeklyRoundupDescription": { + "description": "Description for the 'Weekly Roundup' delivery type switch." + }, + "positiveInteractionTypeSaveItemDescription": "Counts when a user bookmark a headline.", + "@positiveInteractionTypeSaveItemDescription": { + "description": "Description for the 'save item' positive interaction type switch." + }, + "positiveInteractionTypeFollowItemDescription": "Counts when a user follows a headline topic, source, or country.", + "@positiveInteractionTypeFollowItemDescription": { + "description": "Description for the 'follow item' positive interaction type switch." + }, + "positiveInteractionTypeShareContentDescription": "Counts when a user shares a headline.", + "@positiveInteractionTypeShareContentDescription": { + "description": "Description for the 'share content' positive interaction type switch." + }, + "positiveInteractionTypeSaveFilterDescription": "Counts when a user creates a saved filter.", + "@positiveInteractionTypeSaveFilterDescription": { + "description": "Description for the 'save filter' positive interaction type switch." + }, + "internalPromptLogicDescription": "Define the conditions that trigger the enjoyment prompt, such as the number of user actions and cooldown periods.", + "@internalPromptLogicDescription": { + "description": "Description for the internal prompt logic settings." + }, + "eligiblePositiveInteractionsDescription": "Select which user actions are counted as 'positive interactions' to trigger the enjoyment prompt.", + "@eligiblePositiveInteractionsDescription": { + "description": "Description for the eligible positive interactions settings." + }, + "followUpActionsDescription": "Configure what happens after a user responds to the enjoyment prompt, such as requesting a store review.", + "@followUpActionsDescription": { + "description": "Description for the follow-up actions settings." } } \ No newline at end of file