Files
jinzhi/lib/features/ads/application/startup_ad_service.dart
T
2026-08-24 19:07:31 +08:00

58 lines
2.1 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../common/router/app_router.dart';
import '../data/ads_api_client.dart';
import '../presentation/splash_ad_dialog.dart';
import 'splash_ad_controller.dart';
final startupAdResolvedProvider = StateProvider<bool>((_) => false);
abstract final class StartupAdService {
static Future<void>? _running;
static Future<void> showIfAvailable(BuildContext context, WidgetRef ref) =>
_running ??= _show(context, ref);
static Future<void> _show(BuildContext context, WidgetRef ref) async {
final controller = ref.read(splashAdControllerProvider);
try {
final entry = await controller.coldLaunchDecision();
if (entry != null && context.mounted) {
final result = await showGeneralDialog<SplashAdResult>(
context: context,
useRootNavigator: true,
barrierDismissible: false,
barrierColor: Colors.black,
pageBuilder: (ctx, _, _) => SplashAdDialog(
entry: entry,
onShown: () => unawaited(controller.markShown(entry)),
onClick: () async {
final id = ref.read(adsApiClientProvider).newClickId();
final uri = entry.ad.clickUri(id);
if (uri != null) {
unawaited(
ref
.read(adsApiClientProvider)
.report(entry.ad, 'ad_click', clickId: id),
);
if (entry.ad.openMode == AdOpenMode.inApp) {
context.push(
'${AppRoutes.web}?url=${Uri.encodeComponent(uri.toString())}',
);
} else {
await launchUrl(uri, mode: LaunchMode.externalApplication);
}
}
},
),
);
if (result == SplashAdResult.skipped) unawaited(controller.skip(entry));
}
} finally {
ref.read(startupAdResolvedProvider.notifier).state = true;
unawaited(controller.refresh());
}
}
}