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 createState() => _VastWebViewPageState(); } class _VastWebViewPageState extends State 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: [ // Поле ввода 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, ), ), ), ], ), ); } }