Skip to content

Commit 7d8fb37

Browse files
authored
Merge pull request #139 from flutter-news-app-full-source-code/refactor/sync-with-core-package-update
Refactor/sync with core package update
2 parents 3b69ace + 92f91f6 commit 7d8fb37

File tree

11 files changed

+262
-52
lines changed

11 files changed

+262
-52
lines changed

lib/app_configuration/widgets/app_review_settings_form.dart

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class AppReviewSettingsForm extends StatefulWidget {
2626
}
2727

2828
class _AppReviewSettingsFormState extends State<AppReviewSettingsForm> {
29-
late final TextEditingController _positiveInteractionThresholdController;
29+
late final TextEditingController _interactionCycleThresholdController;
3030
late final TextEditingController _initialPromptCooldownController;
3131

3232
@override
@@ -46,8 +46,8 @@ class _AppReviewSettingsFormState extends State<AppReviewSettingsForm> {
4646

4747
void _initializeControllers() {
4848
final appReviewConfig = widget.remoteConfig.features.community.appReview;
49-
_positiveInteractionThresholdController = TextEditingController(
50-
text: appReviewConfig.positiveInteractionThreshold.toString(),
49+
_interactionCycleThresholdController = TextEditingController(
50+
text: appReviewConfig.interactionCycleThreshold.toString(),
5151
);
5252
_initialPromptCooldownController = TextEditingController(
5353
text: appReviewConfig.initialPromptCooldownDays.toString(),
@@ -56,8 +56,8 @@ class _AppReviewSettingsFormState extends State<AppReviewSettingsForm> {
5656

5757
void _updateControllers() {
5858
final appReviewConfig = widget.remoteConfig.features.community.appReview;
59-
_positiveInteractionThresholdController.text = appReviewConfig
60-
.positiveInteractionThreshold
59+
_interactionCycleThresholdController.text = appReviewConfig
60+
.interactionCycleThreshold
6161
.toString();
6262
_initialPromptCooldownController.text = appReviewConfig
6363
.initialPromptCooldownDays
@@ -66,7 +66,7 @@ class _AppReviewSettingsFormState extends State<AppReviewSettingsForm> {
6666

6767
@override
6868
void dispose() {
69-
_positiveInteractionThresholdController.dispose();
69+
_interactionCycleThresholdController.dispose();
7070
_initialPromptCooldownController.dispose();
7171
super.dispose();
7272
}
@@ -121,14 +121,14 @@ class _AppReviewSettingsFormState extends State<AppReviewSettingsForm> {
121121
expandedCrossAxisAlignment: CrossAxisAlignment.start,
122122
children: [
123123
AppConfigIntField(
124-
label: l10n.positiveInteractionThresholdLabel,
124+
label: l10n.interactionCycleThresholdLabel,
125125
description:
126-
l10n.positiveInteractionThresholdDescription,
127-
value: appReviewConfig.positiveInteractionThreshold,
126+
l10n.interactionCycleThresholdDescription,
127+
value: appReviewConfig.interactionCycleThreshold,
128128
onChanged: (value) {
129129
final newConfig = communityConfig.copyWith(
130130
appReview: appReviewConfig.copyWith(
131-
positiveInteractionThreshold: value,
131+
interactionCycleThreshold: value,
132132
),
133133
);
134134
widget.onConfigChanged(
@@ -140,7 +140,7 @@ class _AppReviewSettingsFormState extends State<AppReviewSettingsForm> {
140140
),
141141
);
142142
},
143-
controller: _positiveInteractionThresholdController,
143+
controller: _interactionCycleThresholdController,
144144
),
145145
AppConfigIntField(
146146
label: l10n.initialPromptCooldownLabel,
@@ -168,6 +168,63 @@ class _AppReviewSettingsFormState extends State<AppReviewSettingsForm> {
168168
},
169169
),
170170
),
171+
Padding(
172+
padding: const EdgeInsetsDirectional.only(
173+
start: AppSpacing.lg,
174+
),
175+
child: LayoutBuilder(
176+
builder: (context, constraints) {
177+
final isMobile = constraints.maxWidth < 600;
178+
return ExpansionTile(
179+
title: Text(l10n.eligiblePositiveInteractionsTitle),
180+
initiallyExpanded: !isMobile,
181+
childrenPadding: const EdgeInsetsDirectional.only(
182+
start: AppSpacing.lg,
183+
top: AppSpacing.md,
184+
bottom: AppSpacing.md,
185+
),
186+
expandedCrossAxisAlignment: CrossAxisAlignment.start,
187+
children: [
188+
...PositiveInteractionType.values.map(
189+
(interactionType) => SwitchListTile(
190+
title: Text(interactionType.l10n(context)),
191+
value: appReviewConfig
192+
.eligiblePositiveInteractions
193+
.contains(interactionType),
194+
onChanged: (value) {
195+
final currentInteractions =
196+
List<PositiveInteractionType>.from(
197+
appReviewConfig
198+
.eligiblePositiveInteractions,
199+
);
200+
if (value) {
201+
currentInteractions.add(interactionType);
202+
} else {
203+
currentInteractions.remove(interactionType);
204+
}
205+
final newAppReviewConfig = appReviewConfig
206+
.copyWith(
207+
eligiblePositiveInteractions:
208+
currentInteractions,
209+
);
210+
widget.onConfigChanged(
211+
widget.remoteConfig.copyWith(
212+
features: widget.remoteConfig.features
213+
.copyWith(
214+
community: communityConfig.copyWith(
215+
appReview: newAppReviewConfig,
216+
),
217+
),
218+
),
219+
);
220+
},
221+
),
222+
),
223+
],
224+
);
225+
},
226+
),
227+
),
171228
Padding(
172229
padding: const EdgeInsetsDirectional.only(
173230
start: AppSpacing.lg,
@@ -244,3 +301,19 @@ class _AppReviewSettingsFormState extends State<AppReviewSettingsForm> {
244301
);
245302
}
246303
}
304+
305+
extension on PositiveInteractionType {
306+
String l10n(BuildContext context) {
307+
final l10n = AppLocalizationsX(context).l10n;
308+
switch (this) {
309+
case PositiveInteractionType.saveItem:
310+
return l10n.positiveInteractionTypeSaveItem;
311+
case PositiveInteractionType.followItem:
312+
return l10n.positiveInteractionTypeFollowItem;
313+
case PositiveInteractionType.shareContent:
314+
return l10n.positiveInteractionTypeShareContent;
315+
case PositiveInteractionType.saveFilter:
316+
return l10n.positiveInteractionTypeSaveFilter;
317+
}
318+
}
319+
}

lib/community_management/view/engagements_page.dart

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,26 @@ class _EngagementsDataSource extends DataTableSource {
198198
return DataRow2(
199199
cells: [
200200
DataCell(
201-
Chip(
202-
label: Text(engagement.reaction.reactionType.name),
203-
backgroundColor: _getReactionColor(
204-
context,
205-
engagement.reaction.reactionType,
206-
),
207-
side: BorderSide.none,
208-
visualDensity: VisualDensity.compact,
209-
),
201+
engagement.reaction != null
202+
? Chip(
203+
label: Text(
204+
engagement.reaction!.reactionType.l10n(context),
205+
),
206+
backgroundColor: _getReactionColor(
207+
context,
208+
engagement.reaction!.reactionType,
209+
),
210+
side: BorderSide.none,
211+
visualDensity: VisualDensity.compact,
212+
)
213+
: Text(
214+
l10n.notAvailable,
215+
style: Theme.of(context).textTheme.bodySmall?.copyWith(
216+
color: Theme.of(
217+
context,
218+
).colorScheme.onSurface.withOpacity(0.6),
219+
),
220+
),
210221
),
211222
DataCell(
212223
Text(DateFormat('dd-MM-yyyy').format(engagement.createdAt.toLocal())),
@@ -243,3 +254,23 @@ class _EngagementsDataSource extends DataTableSource {
243254
}
244255
}
245256
}
257+
258+
extension on ReactionType {
259+
String l10n(BuildContext context) {
260+
final l10n = AppLocalizationsX(context).l10n;
261+
switch (this) {
262+
case ReactionType.like:
263+
return l10n.reactionTypeLike;
264+
case ReactionType.insightful:
265+
return l10n.reactionTypeInsightful;
266+
case ReactionType.amusing:
267+
return l10n.reactionTypeAmusing;
268+
case ReactionType.sad:
269+
return l10n.reactionTypeSad;
270+
case ReactionType.angry:
271+
return l10n.reactionTypeAngry;
272+
case ReactionType.skeptical:
273+
return l10n.reactionTypeSkeptical;
274+
}
275+
}
276+
}

lib/community_management/view/reports_page.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ class _ReportsDataSource extends DataTableSource {
227227
return colorScheme.primaryContainer.withOpacity(0.5);
228228
case ReportableEntity.source:
229229
return colorScheme.secondaryContainer.withOpacity(0.5);
230-
case ReportableEntity.engagement:
230+
case ReportableEntity.comment:
231231
return colorScheme.tertiaryContainer.withOpacity(0.5);
232232
}
233233
}

lib/l10n/app_localizations.dart

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3272,17 +3272,17 @@ abstract class AppLocalizations {
32723272
/// **'Activates the internal system that periodically asks users if they are enjoying the app.'**
32733273
String get enableAppFeedbackSystemDescription;
32743274

3275-
/// Label for the positive interaction threshold input field.
3275+
/// Label for the interaction cycle threshold input field.
32763276
///
32773277
/// In en, this message translates to:
3278-
/// **'Positive Interaction Threshold'**
3279-
String get positiveInteractionThresholdLabel;
3278+
/// **'Interaction Cycle Threshold'**
3279+
String get interactionCycleThresholdLabel;
32803280

3281-
/// Description for the positive interaction threshold input field.
3281+
/// Description for the interaction cycle threshold input field.
32823282
///
32833283
/// In en, this message translates to:
32843284
/// **'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.'**
3285-
String get positiveInteractionThresholdDescription;
3285+
String get interactionCycleThresholdDescription;
32863286

32873287
/// Label for the initial prompt cooldown input field.
32883288
///
@@ -3293,7 +3293,7 @@ abstract class AppLocalizations {
32933293
/// Description for the initial prompt cooldown input field.
32943294
///
32953295
/// In en, this message translates to:
3296-
/// **'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.'**
3296+
/// **'The number of days to wait before showing the enjoyment prompt for the first time, This cooldown ensures users are not asked until they used the app enough.'**
32973297
String get initialPromptCooldownDescription;
32983298

32993299
/// Label for the switch to request a store review after positive feedback.
@@ -3326,6 +3326,36 @@ abstract class AppLocalizations {
33263326
/// **'Internal Prompt Logic'**
33273327
String get internalPromptLogicTitle;
33283328

3329+
/// Title for the expansion tile for eligible positive interactions.
3330+
///
3331+
/// In en, this message translates to:
3332+
/// **'Eligible Positive Interactions'**
3333+
String get eligiblePositiveInteractionsTitle;
3334+
3335+
/// Label for the 'save item' positive interaction type.
3336+
///
3337+
/// In en, this message translates to:
3338+
/// **'Save a content item (e.g., a headline)'**
3339+
String get positiveInteractionTypeSaveItem;
3340+
3341+
/// Label for the 'follow item' positive interaction type.
3342+
///
3343+
/// In en, this message translates to:
3344+
/// **'Follow an entity (e.g., a topic, source, or country)'**
3345+
String get positiveInteractionTypeFollowItem;
3346+
3347+
/// Label for the 'share content' positive interaction type.
3348+
///
3349+
/// In en, this message translates to:
3350+
/// **'Share a content item (e.g., a headline)'**
3351+
String get positiveInteractionTypeShareContent;
3352+
3353+
/// Label for the 'save filter' positive interaction type.
3354+
///
3355+
/// In en, this message translates to:
3356+
/// **'Create a saved filter'**
3357+
String get positiveInteractionTypeSaveFilter;
3358+
33293359
/// Title for the nested expansion tile for app review follow-up actions.
33303360
///
33313361
/// In en, this message translates to:

lib/l10n/app_localizations_ar.dart

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,18 +1763,18 @@ class AppLocalizationsAr extends AppLocalizations {
17631763
'ينشط النظام الداخلي الذي يسأل المستخدمين بشكل دوري عما إذا كانوا يستمتعون بالتطبيق.';
17641764

17651765
@override
1766-
String get positiveInteractionThresholdLabel => 'عتبة التفاعل الإيجابي';
1766+
String get interactionCycleThresholdLabel => 'عتبة دورة التفاعل';
17671767

17681768
@override
1769-
String get positiveInteractionThresholdDescription =>
1769+
String get interactionCycleThresholdDescription =>
17701770
'يحدد عدد الإجراءات الإيجابية (مثل الحفظ، الإعجاب) المطلوبة لتشغيل موجه الاستمتاع. يظهر الموجه في كل مرة يكون فيها إجمالي الإجراءات الإيجابية للمستخدم من مضاعفات هذا الرقم.';
17711771

17721772
@override
17731773
String get initialPromptCooldownLabel => 'فترة تهدئة الموجه الأولي (أيام)';
17741774

17751775
@override
17761776
String get initialPromptCooldownDescription =>
1777-
'إذا رفض المستخدم الموجه، انتظر هذا العدد من الأيام قبل أن يكون مؤهلاً لرؤيته مرة أخرى. ملاحظة: تتحكم زينة \'تقييم التطبيق\' في قسم الموجز في تردد عرضها المنفصل.';
1777+
'عدد الأيام التي يجب الانتظار فيها قبل إظهار مطالبة الاستمتاع للمرة الأولى. تضمن فترة التهدئة هذه عدم سؤال المستخدمين حتى يستخدموا التطبيق بما فيه الكفاية.';
17781778

17791779
@override
17801780
String get requestStoreReviewLabel => 'طلب مراجعة المتجر بعد \'نعم\'';
@@ -1793,6 +1793,24 @@ class AppLocalizationsAr extends AppLocalizations {
17931793
@override
17941794
String get internalPromptLogicTitle => 'منطق الموجه الداخلي';
17951795

1796+
@override
1797+
String get eligiblePositiveInteractionsTitle => 'التفاعلات الإيجابية المؤهلة';
1798+
1799+
@override
1800+
String get positiveInteractionTypeSaveItem =>
1801+
'حفظ عنصر محتوى (مثل عنوان رئيسي)';
1802+
1803+
@override
1804+
String get positiveInteractionTypeFollowItem =>
1805+
'متابعة كيان (مثل موضوع أو مصدر أو بلد)';
1806+
1807+
@override
1808+
String get positiveInteractionTypeShareContent =>
1809+
'مشاركة عنصر محتوى (مثل عنوان رئيسي)';
1810+
1811+
@override
1812+
String get positiveInteractionTypeSaveFilter => 'إنشاء مرشح محفوظ';
1813+
17961814
@override
17971815
String get followUpActionsTitle => 'إجراءات المتابعة';
17981816

lib/l10n/app_localizations_en.dart

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,19 +1766,18 @@ class AppLocalizationsEn extends AppLocalizations {
17661766
'Activates the internal system that periodically asks users if they are enjoying the app.';
17671767

17681768
@override
1769-
String get positiveInteractionThresholdLabel =>
1770-
'Positive Interaction Threshold';
1769+
String get interactionCycleThresholdLabel => 'Interaction Cycle Threshold';
17711770

17721771
@override
1773-
String get positiveInteractionThresholdDescription =>
1772+
String get interactionCycleThresholdDescription =>
17741773
'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.';
17751774

17761775
@override
17771776
String get initialPromptCooldownLabel => 'Initial Prompt Cooldown (Days)';
17781777

17791778
@override
17801779
String get initialPromptCooldownDescription =>
1781-
'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.';
1780+
'The number of days to wait before showing the enjoyment prompt for the first time, This cooldown ensures users are not asked until they used the app enough.';
17821781

17831782
@override
17841783
String get requestStoreReviewLabel => 'Request Store Review After \'Yes\'';
@@ -1798,6 +1797,25 @@ class AppLocalizationsEn extends AppLocalizations {
17981797
@override
17991798
String get internalPromptLogicTitle => 'Internal Prompt Logic';
18001799

1800+
@override
1801+
String get eligiblePositiveInteractionsTitle =>
1802+
'Eligible Positive Interactions';
1803+
1804+
@override
1805+
String get positiveInteractionTypeSaveItem =>
1806+
'Save a content item (e.g., a headline)';
1807+
1808+
@override
1809+
String get positiveInteractionTypeFollowItem =>
1810+
'Follow an entity (e.g., a topic, source, or country)';
1811+
1812+
@override
1813+
String get positiveInteractionTypeShareContent =>
1814+
'Share a content item (e.g., a headline)';
1815+
1816+
@override
1817+
String get positiveInteractionTypeSaveFilter => 'Create a saved filter';
1818+
18011819
@override
18021820
String get followUpActionsTitle => 'Follow-up Actions';
18031821

0 commit comments

Comments
 (0)