83 lines
2.0 KiB
Dart
83 lines
2.0 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../application/splash_ad_controller.dart';
|
|
import 'ad_media.dart';
|
|
|
|
enum SplashAdResult { clicked, skipped, completed }
|
|
|
|
class SplashAdDialog extends StatefulWidget {
|
|
const SplashAdDialog({
|
|
super.key,
|
|
required this.entry,
|
|
required this.onClick,
|
|
required this.onShown,
|
|
});
|
|
final SplashAdEntry entry;
|
|
final Future<void> Function() onClick;
|
|
final VoidCallback onShown;
|
|
@override
|
|
State<SplashAdDialog> createState() => _SplashAdDialogState();
|
|
}
|
|
|
|
class _SplashAdDialogState extends State<SplashAdDialog> {
|
|
Timer? timer;
|
|
late int remain;
|
|
bool opening = false;
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
remain = widget.entry.ad.countdownSeconds.clamp(1, 5);
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
widget.onShown();
|
|
});
|
|
timer = Timer.periodic(const Duration(seconds: 1), (_) {
|
|
if (remain <= 1) {
|
|
Navigator.of(context).pop(SplashAdResult.completed);
|
|
} else if (mounted) {
|
|
setState(() => remain--);
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
timer?.cancel();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> open() async {
|
|
if (opening) return;
|
|
opening = true;
|
|
timer?.cancel();
|
|
await widget.onClick();
|
|
if (mounted) Navigator.of(context).pop(SplashAdResult.clicked);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) => Material(
|
|
color: Colors.black,
|
|
child: Stack(
|
|
children: [
|
|
Positioned.fill(
|
|
child: GestureDetector(
|
|
onTap: open,
|
|
child: AdMedia(
|
|
ad: widget.entry.ad,
|
|
assetPath: widget.entry.assetPath,
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
top: MediaQuery.paddingOf(context).top + 16,
|
|
right: 18,
|
|
child: FilledButton(
|
|
onPressed: () => Navigator.of(context).pop(SplashAdResult.skipped),
|
|
child: Text('跳过 ${remain}s'),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|