11import 'package:core/core.dart' ;
22import 'package:flutter/material.dart' ;
3+ import 'package:flutter_news_app_mobile_client_full_source_code/l10n/l10n.dart' ;
34import 'package:ui_kit/ui_kit.dart' ;
45
56/// {@template call_to_action_decorator_widget}
67/// A widget to display a call-to-action feed decorator.
78///
89/// This widget presents a card with a title, description, and a call-to-action
910/// button.
11+ /// It now includes a dismiss option in a popup menu.
1012/// {@endtemplate}
1113class CallToActionDecoratorWidget extends StatelessWidget {
1214 /// {@macro call_to_action_decorator_widget}
1315 const CallToActionDecoratorWidget ({
1416 required this .item,
1517 required this .onCallToAction,
18+ this .onDismiss,
1619 super .key,
1720 });
1821
@@ -22,44 +25,69 @@ class CallToActionDecoratorWidget extends StatelessWidget {
2225 /// Callback function when the call-to-action button is pressed.
2326 final ValueSetter <String > onCallToAction;
2427
28+ /// An optional callback that is triggered when the user dismisses the
29+ /// decorator.
30+ final VoidCallback ? onDismiss;
31+
2532 @override
2633 Widget build (BuildContext context) {
27- // final l10n = context.l10n;
34+ final l10n = AppLocalizationsX ( context) .l10n;
2835 final theme = Theme .of (context);
2936
3037 return Card (
3138 margin: const EdgeInsets .symmetric (
3239 horizontal: AppSpacing .lg,
3340 vertical: AppSpacing .md,
3441 ),
35- child: Padding (
36- padding: const EdgeInsets .all (AppSpacing .lg),
37- child: Column (
38- crossAxisAlignment: CrossAxisAlignment .start,
39- children: [
40- Text (
41- item.title,
42- style: theme.textTheme.titleLarge,
43- maxLines: 2 ,
44- overflow: TextOverflow .ellipsis,
45- ),
46- const SizedBox (height: AppSpacing .sm),
47- Text (
48- item.description,
49- style: theme.textTheme.bodyMedium,
50- maxLines: 3 ,
51- overflow: TextOverflow .ellipsis,
42+ child: Stack (
43+ children: [
44+ Padding (
45+ padding: const EdgeInsets .all (AppSpacing .lg),
46+ child: Column (
47+ crossAxisAlignment: CrossAxisAlignment .start,
48+ children: [
49+ Text (
50+ item.title,
51+ style: theme.textTheme.titleLarge,
52+ maxLines: 2 ,
53+ overflow: TextOverflow .ellipsis,
54+ ),
55+ const SizedBox (height: AppSpacing .sm),
56+ Text (
57+ item.description,
58+ style: theme.textTheme.bodyMedium,
59+ maxLines: 3 ,
60+ overflow: TextOverflow .ellipsis,
61+ ),
62+ const SizedBox (height: AppSpacing .lg),
63+ Align (
64+ alignment: Alignment .bottomRight,
65+ child: ElevatedButton (
66+ onPressed: () => onCallToAction (item.callToActionUrl),
67+ child: Text (item.callToActionText),
68+ ),
69+ ),
70+ ],
5271 ),
53- const SizedBox (height: AppSpacing .lg),
54- Align (
55- alignment: Alignment .bottomRight,
56- child: ElevatedButton (
57- onPressed: () => onCallToAction (item.callToActionUrl),
58- child: Text (item.callToActionText),
72+ ),
73+ if (onDismiss != null )
74+ Positioned (
75+ top: AppSpacing .xs,
76+ right: AppSpacing .xs,
77+ child: PopupMenuButton <void >(
78+ icon: const Icon (Icons .more_vert),
79+ tooltip: l10n.manageFiltersDeleteTooltip,
80+ onSelected: (_) => onDismiss !(),
81+ itemBuilder: (BuildContext context) => [
82+ PopupMenuItem <void >(
83+ value: null ,
84+ // TODO(fulleni): Replace with a localized string.
85+ child: Text (l10n.savedFiltersMenuDelete),
86+ ),
87+ ],
5988 ),
6089 ),
61- ],
62- ),
90+ ],
6391 ),
6492 );
6593 }
0 commit comments