mnemo_cards/games/ads_example/lib/vast_webview_page.dart
2025-11-11 02:55:41 +03:00

299 lines
9.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'vast_webview_player.dart';
/// Example widget displaying VAST ads using WebView and vast-player library.
class VastWebViewPage extends StatefulWidget {
/// Constructs a [VastWebViewPage].
const VastWebViewPage({super.key});
@override
State<VastWebViewPage> createState() => _VastWebViewPageState();
}
class _VastWebViewPageState extends State<VastWebViewPage>
with WidgetsBindingObserver {
// Last state received in `didChangeAppLifecycleState`.
AppLifecycleState _lastLifecycleState = AppLifecycleState.resumed;
// Whether the widget should be displaying the content video. The content
// player is hidden while Ads are playing.
bool _shouldShowContentVideo = false;
// Контроллер для ввода URL
late final TextEditingController _urlController = TextEditingController()
..text = _defaultVastUrl;
static const _defaultVastUrl =
'https://mediatoday.ru/c/ads.xml?pid=10548&vr=1&rid=5432234&dl=https://google.com';
// VAST URL для загрузки рекламы
String _vastUrl = _defaultVastUrl;
// Состояние рекламы
bool _isAdPlaying = false;
String _adStatus = '';
// Ключ для принудительного пересоздания WebView
Key _webViewKey = UniqueKey();
@override
void initState() {
super.initState();
// Adds this instance as an observer for `AppLifecycleState` changes.
WidgetsBinding.instance.addObserver(this);
// Устанавливаем начальный URL в контроллер
_urlController.text = _vastUrl;
}
void _onAdComplete() {
setState(() {
_shouldShowContentVideo = true;
_isAdPlaying = false;
_adStatus = 'Реклама завершена';
});
}
void _onAdError() {
print('Ad error occurred in VastWebViewPage');
setState(() {
_shouldShowContentVideo = true;
_isAdPlaying = false;
_adStatus = 'Ошибка рекламы - проверьте URL и сетевые настройки';
});
}
void _onAdClick() {
setState(() {
_adStatus = 'Клик по рекламе - открываем ссылку...';
});
print('Ad clicked - opening link in browser');
// Показываем уведомление пользователю
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Открываем ссылку рекламы в браузере'),
duration: Duration(seconds: 2),
backgroundColor: Colors.blue,
),
);
}
void _onAdStarted() {
setState(() {
_isAdPlaying = true;
_adStatus = 'Реклама началась';
});
}
void _onAdStopped() {
setState(() {
_shouldShowContentVideo = true;
_isAdPlaying = false;
_adStatus = 'Реклама остановлена пользователем';
});
}
void _onAdLoaded() {
setState(() {
_adStatus = 'Реклама загружена';
});
}
void _onAdVideoStart() {
setState(() {
_adStatus = 'Видео рекламы началось';
});
}
void _onAdVideoComplete() {
setState(() {
_adStatus = 'Видео рекламы завершено';
});
}
void _onAdImpression() {
setState(() {
_adStatus = 'Показ рекламы зафиксирован';
});
}
void _loadAdWithCustomUrl() {
final newUrl = _urlController.text.trim();
if (newUrl.isNotEmpty) {
setState(() {
_vastUrl = newUrl;
_shouldShowContentVideo = false;
_adStatus = 'Загрузка рекламы...';
_isAdPlaying = false;
// Создаем новый ключ для принудительного пересоздания WebView
_webViewKey = UniqueKey();
});
print('Loading new VAST ad from URL: $newUrl');
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Пожалуйста, введите URL'),
backgroundColor: Colors.red,
),
);
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
if (!_shouldShowContentVideo) {
// Возобновляем рекламу
}
case AppLifecycleState.inactive:
// Пауза рекламы
if (!_shouldShowContentVideo &&
_lastLifecycleState == AppLifecycleState.resumed) {
// Пауза рекламы
}
case AppLifecycleState.hidden:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
}
_lastLifecycleState = state;
}
@override
void dispose() {
_urlController.dispose();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('VAST WebView Player'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: Column(
spacing: 20,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Поле ввода URL
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[300]!),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'URL для загрузки VAST рекламы:',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 12),
TextField(
controller: _urlController,
decoration: const InputDecoration(
hintText: 'Введите URL VAST рекламы...',
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
),
style: const TextStyle(fontSize: 14),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _loadAdWithCustomUrl,
icon: const Icon(Icons.download),
label: const Text('Загрузить рекламу'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
),
),
const SizedBox(width: 12),
ElevatedButton.icon(
onPressed: () {
_urlController.text = _defaultVastUrl;
_loadAdWithCustomUrl();
},
icon: const Icon(Icons.refresh),
label: const Text('Сброс'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey,
foregroundColor: Colors.white,
),
),
],
),
],
),
),
// Статус рекламы
if (_adStatus.isNotEmpty)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.blue),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
_isAdPlaying ? Icons.play_arrow : Icons.info,
color: Colors.blue,
),
const SizedBox(width: 8),
Expanded(
child: Text(
_adStatus,
style: const TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
// Видео контейнер
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: VastWebViewPlayer(
key: _webViewKey,
vastUrl: _vastUrl,
onAdComplete: _onAdComplete,
onAdError: _onAdError,
onAdClick: _onAdClick,
onAdStarted: _onAdStarted,
onAdStopped: _onAdStopped,
onAdLoaded: _onAdLoaded,
onAdVideoStart: _onAdVideoStart,
onAdVideoComplete: _onAdVideoComplete,
onAdImpression: _onAdImpression,
),
),
),
],
),
);
}
}