Skip to content

Commit 12fbe66

Browse files
committed
feat(ads): enhance demo interstitial ad dialog with countdown timer
- Transform DemoInterstitialAdDialog from StatelessWidget to StatefulWidget - Add countdown timer before close button is enabled - Display countdown value on the dialog - Update UI to show disabled close button with countdown
1 parent a1dd230 commit 12fbe66

File tree

1 file changed

+77
-11
lines changed

1 file changed

+77
-11
lines changed

lib/ads/widgets/demo_interstitial_ad_dialog.dart

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:async';
2+
13
import 'package:flutter/material.dart';
24
import 'package:flutter_news_app_mobile_client_full_source_code/l10n/app_localizations.dart';
35
import 'package:ui_kit/ui_kit.dart';
@@ -6,15 +8,53 @@ import 'package:ui_kit/ui_kit.dart';
68
/// A dialog widget that displays a placeholder for an interstitial ad in demo mode.
79
///
810
/// This dialog mimics a full-screen interstitial ad but contains only static
9-
/// text to indicate it's a demo.
11+
/// text to indicate it's a demo. It includes a countdown before the close
12+
/// button is enabled.
1013
/// {@endtemplate}
11-
class DemoInterstitialAdDialog extends StatelessWidget {
14+
class DemoInterstitialAdDialog extends StatefulWidget {
1215
/// {@macro demo_interstitial_ad_dialog}
1316
const DemoInterstitialAdDialog({super.key});
1417

18+
@override
19+
State<DemoInterstitialAdDialog> createState() =>
20+
_DemoInterstitialAdDialogState();
21+
}
22+
23+
class _DemoInterstitialAdDialogState extends State<DemoInterstitialAdDialog> {
24+
static const int _countdownDuration = 5;
25+
int _countdown = _countdownDuration;
26+
Timer? _timer;
27+
28+
@override
29+
void initState() {
30+
super.initState();
31+
_startTimer();
32+
}
33+
34+
void _startTimer() {
35+
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
36+
if (_countdown > 0) {
37+
setState(() {
38+
_countdown--;
39+
});
40+
} else {
41+
_timer?.cancel();
42+
}
43+
});
44+
}
45+
46+
@override
47+
void dispose() {
48+
_timer?.cancel();
49+
super.dispose();
50+
}
51+
1552
@override
1653
Widget build(BuildContext context) {
1754
final theme = Theme.of(context);
55+
final l10n = AppLocalizations.of(context);
56+
final canClose = _countdown == 0;
57+
1858
return Dialog.fullscreen(
1959
backgroundColor: theme.colorScheme.surface,
2060
child: Stack(
@@ -25,15 +65,15 @@ class DemoInterstitialAdDialog extends StatelessWidget {
2565
mainAxisAlignment: MainAxisAlignment.center,
2666
children: [
2767
Text(
28-
AppLocalizations.of(context).demoInterstitialAdText,
68+
l10n.demoInterstitialAdText,
2969
style: theme.textTheme.titleLarge?.copyWith(
3070
color: theme.colorScheme.onSurface,
3171
),
3272
textAlign: TextAlign.center,
3373
),
3474
const SizedBox(height: AppSpacing.md),
3575
Text(
36-
AppLocalizations.of(context).demoInterstitialAdDescription,
76+
l10n.demoInterstitialAdDescription,
3777
style: theme.textTheme.bodyMedium?.copyWith(
3878
color: theme.colorScheme.onSurfaceVariant,
3979
),
@@ -46,13 +86,39 @@ class DemoInterstitialAdDialog extends StatelessWidget {
4686
Positioned(
4787
top: AppSpacing.lg,
4888
right: AppSpacing.lg,
49-
child: IconButton(
50-
icon: Icon(Icons.close, color: theme.colorScheme.onSurface),
51-
onPressed: () {
52-
// Dismiss the dialog.
53-
Navigator.of(context).pop();
54-
},
55-
),
89+
child: canClose
90+
? IconButton(
91+
icon:
92+
Icon(Icons.close, color: theme.colorScheme.onSurface),
93+
onPressed: () => Navigator.of(context).pop(),
94+
)
95+
: Container(
96+
padding: const EdgeInsets.symmetric(
97+
horizontal: AppSpacing.sm,
98+
vertical: AppSpacing.xs,
99+
),
100+
decoration: BoxDecoration(
101+
color: theme.colorScheme.onSurface.withOpacity(0.1),
102+
borderRadius: BorderRadius.circular(AppSpacing.lg),
103+
),
104+
child: Row(
105+
mainAxisSize: MainAxisSize.min,
106+
children: [
107+
Text(
108+
'$_countdown',
109+
style: theme.textTheme.bodySmall?.copyWith(
110+
color: theme.colorScheme.onSurface,
111+
fontWeight: FontWeight.bold,
112+
),
113+
),
114+
const SizedBox(width: AppSpacing.xs),
115+
Icon(
116+
Icons.close,
117+
color: theme.colorScheme.onSurface.withOpacity(0.5),
118+
),
119+
],
120+
),
121+
),
56122
),
57123
],
58124
),

0 commit comments

Comments
 (0)