import 'package:flutter/material.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:provider/provider.dart'; import '../estado/estado_entitlement.dart'; import '../servicios/servicio_anuncios.dart'; /// Entitlement-aware top-banner slot (Design ADR-6, ad-display spec /// "Persistent Top Banner, Never Overlapping Content"). Collapses to /// `SizedBox.shrink()` — zero reserved space, zero layout impact — whenever /// the user is premium OR no ad has finished loading yet; only a /// successfully loaded [BannerAd] renders a sized box around an [AdWidget]. /// Callers place this as a plain sibling in a `Column` ABOVE the existing /// body (`app.dart`'s `_PaginaPrincipalState.build`) — this widget itself /// never wraps its parent in a `Stack`/overlay. class BannerAnuncioSuperior extends StatefulWidget { const BannerAnuncioSuperior({super.key}); @override State createState() => _BannerAnuncioSuperiorState(); } class _BannerAnuncioSuperiorState extends State { BannerAd? _bannerAd; bool _cargado = false; @override void didChangeDependencies() { super.didChangeDependencies(); final servicio = context.read(); if (_bannerAd == null && servicio.debeMostrarBanner) { _cargarBanner(); } } void _cargarBanner() { // Fire-and-forget: a failure (no plugin channel in `flutter test`, no // fill, offline) leaves `_bannerAd` `null` forever, which keeps this // widget collapsed — exactly the same degrade-to-shrink path a genuine // load failure takes in production. Never throws out of this method. final anuncio = BannerAd( size: AdSize.banner, adUnitId: bannerAdUnitIdPrueba, request: const AdRequest(), listener: BannerAdListener( onAdLoaded: (ad) { if (!mounted) { ad.dispose(); return; } setState(() { _bannerAd = ad as BannerAd; _cargado = true; }); }, onAdFailedToLoad: (ad, error) { ad.dispose(); }, ), ); anuncio.load().catchError((_) {}); } @override void dispose() { _bannerAd?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final entitlement = context.watch(); if (entitlement.esPremium) return const SizedBox.shrink(); // Instant vanish-on-purchase (ad-display spec "Ads Vanish Immediately // On Purchase"): even a banner that finished loading BEFORE this // transition is dropped, never shown to a now-premium user. if (!_cargado || _bannerAd == null) return const SizedBox.shrink(); final ad = _bannerAd!; return SizedBox( width: ad.size.width.toDouble(), height: ad.size.height.toDouble(), child: AdWidget(ad: ad), ); } }