fix(iap): address code review defects in freemium/IAP change
Build & Deploy PluriWave / Análisis de código (push) Successful in 42s
Build & Deploy PluriWave / Build APK + AAB release (push) Failing after 4m23s

Fixes 9 of 10 review findings (10th requires a manual Play Console
step, no code change):

1. app.dart/banner_anuncio_superior.dart: move the top SafeArea inside
   BannerAnuncioSuperior so it only reserves status-bar height when an
   ad actually renders, restoring edge-to-edge layout for premium and
   free-unloaded users.
2. servicio_anuncios.dart: bound every interstitial await (load,
   presentation, and the injected implementation itself) with
   injectable timeouts so a callback that never fires can no longer
   hang a caller.
3. estado_entitlement.dart/hoja_premium.dart: expose a typed
   resultadoUsuario signal for purchase/restore failures and
   restore-found-nothing, with dedicated localized messages
   (compraError, restauracionSinCompras) across all 13 locales --
   never the raw developer/exception string.
4. main.dart/servicio_consentimiento.dart: add a GDPR/UMP consent flow
   (ConsentInformation/ConsentForm) that gates Mobile Ads SDK init on
   canRequestAds(); premium users never see a consent form; failures
   degrade to no ads instead of crashing or blocking startup.
6. servicio_anuncios.dart: track real ad presentation
   (onAdShowedFullScreenContent) so a failed-to-show interstitial no
   longer consumes a session cap slot.
7. banner_anuncio_superior.dart: add an explicit load-attempted guard
   so repeated didChangeDependencies (e.g. entitlement notifyListeners
   during a purchase) can only ever trigger one banner load attempt.
8. servicio_anuncios.dart: make esPremium a required constructor
   parameter, matching the hardened contract already applied to
   EstadoAlarmas/EstadoGrabacion/EstadoRadio.
9. hoja_premium.dart: add a dedicated premiumActivo localized string
   instead of reusing the equalizer's equalizerActive translation,
   across all 13 locales.

All fixes implemented RED-first (failing test before production
code). Full suite: 1261 passed, 2 pre-existing skips, 0 failures.
flutter analyze: 5 pre-existing issues only, 0 new.

[version set]
This commit is contained in:
2026-08-12 16:10:46 +02:00
parent 94f354a7c1
commit 9cfa5ac17d
40 changed files with 1194 additions and 68 deletions
+18
View File
@@ -3349,6 +3349,24 @@ abstract class AppLocalizations {
/// In es, this message translates to:
/// **'Restaurar compras'**
String get restaurarCompras;
/// No description provided for @compraError.
///
/// In es, this message translates to:
/// **'No se ha podido completar la compra. Inténtalo de nuevo.'**
String get compraError;
/// No description provided for @restauracionSinCompras.
///
/// In es, this message translates to:
/// **'No hemos encontrado ninguna compra anterior en esta cuenta.'**
String get restauracionSinCompras;
/// No description provided for @premiumActivo.
///
/// In es, this message translates to:
/// **'Premium activo'**
String get premiumActivo;
}
class _AppLocalizationsDelegate
+10
View File
@@ -1853,4 +1853,14 @@ class AppLocalizationsAr extends AppLocalizations {
@override
String get restaurarCompras => 'استعادة المشتريات';
@override
String get compraError => 'تعذّر إتمام عملية الشراء. حاول مرة أخرى.';
@override
String get restauracionSinCompras =>
'لم نجد أي عملية شراء سابقة في هذا الحساب.';
@override
String get premiumActivo => 'النسخة المميزة مفعّلة';
}
+10
View File
@@ -1864,4 +1864,14 @@ class AppLocalizationsBn extends AppLocalizations {
@override
String get restaurarCompras => 'কেনাকাটা পুনরুদ্ধার করুন';
@override
String get compraError => 'কেনাকাটা সম্পূর্ণ করা যায়নি। আবার চেষ্টা করুন।';
@override
String get restauracionSinCompras =>
'এই অ্যাকাউন্টে আমরা আগের কোনো কেনাকাটা খুঁজে পাইনি।';
@override
String get premiumActivo => 'প্রিমিয়াম সক্রিয়';
}
+11
View File
@@ -1877,4 +1877,15 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get restaurarCompras => 'Käufe wiederherstellen';
@override
String get compraError =>
'Der Kauf konnte nicht abgeschlossen werden. Bitte versuche es erneut.';
@override
String get restauracionSinCompras =>
'Wir haben auf diesem Konto keinen früheren Kauf gefunden.';
@override
String get premiumActivo => 'Premium aktiv';
}
+11
View File
@@ -1856,4 +1856,15 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get restaurarCompras => 'Restore purchases';
@override
String get compraError =>
'We couldn\'t complete the purchase. Please try again.';
@override
String get restauracionSinCompras =>
'We didn\'t find any previous purchase on this account.';
@override
String get premiumActivo => 'Premium active';
}
+11
View File
@@ -1870,4 +1870,15 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get restaurarCompras => 'Restaurar compras';
@override
String get compraError =>
'No se ha podido completar la compra. Inténtalo de nuevo.';
@override
String get restauracionSinCompras =>
'No hemos encontrado ninguna compra anterior en esta cuenta.';
@override
String get premiumActivo => 'Premium activo';
}
+11
View File
@@ -1883,4 +1883,15 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get restaurarCompras => 'Restaurer les achats';
@override
String get compraError =>
'Impossible de finaliser l\'achat. Veuillez réessayer.';
@override
String get restauracionSinCompras =>
'Nous n\'avons trouvé aucun achat antérieur sur ce compte.';
@override
String get premiumActivo => 'Premium actif';
}
+10
View File
@@ -1857,4 +1857,14 @@ class AppLocalizationsHi extends AppLocalizations {
@override
String get restaurarCompras => 'खरीदारी पुनर्स्थापित करें';
@override
String get compraError => 'खरीद पूरी नहीं हो सकी। कृपया फिर से प्रयास करें।';
@override
String get restauracionSinCompras =>
'इस खाते में हमें कोई पिछली खरीद नहीं मिली।';
@override
String get premiumActivo => 'प्रीमियम सक्रिय';
}
+11
View File
@@ -1867,4 +1867,15 @@ class AppLocalizationsId extends AppLocalizations {
@override
String get restaurarCompras => 'Pulihkan pembelian';
@override
String get compraError =>
'Pembelian tidak dapat diselesaikan. Silakan coba lagi.';
@override
String get restauracionSinCompras =>
'Kami tidak menemukan pembelian sebelumnya di akun ini.';
@override
String get premiumActivo => 'Premium aktif';
}
+11
View File
@@ -1880,4 +1880,15 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get restaurarCompras => 'Ripristina acquisti';
@override
String get compraError =>
'Non è stato possibile completare l\'acquisto. Riprova.';
@override
String get restauracionSinCompras =>
'Non abbiamo trovato acquisti precedenti su questo account.';
@override
String get premiumActivo => 'Premium attivo';
}
+9
View File
@@ -1803,4 +1803,13 @@ class AppLocalizationsJa extends AppLocalizations {
@override
String get restaurarCompras => '購入を復元';
@override
String get compraError => '購入を完了できませんでした。もう一度お試しください。';
@override
String get restauracionSinCompras => 'このアカウントでは以前の購入が見つかりませんでした。';
@override
String get premiumActivo => 'プレミアム有効';
}
+11
View File
@@ -1867,4 +1867,15 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get restaurarCompras => 'Restaurar compras';
@override
String get compraError =>
'Não foi possível concluir a compra. Tente novamente.';
@override
String get restauracionSinCompras =>
'Não encontramos nenhuma compra anterior nesta conta.';
@override
String get premiumActivo => 'Premium ativo';
}
+10
View File
@@ -1874,4 +1874,14 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get restaurarCompras => 'Восстановить покупки';
@override
String get compraError => 'Не удалось завершить покупку. Попробуйте ещё раз.';
@override
String get restauracionSinCompras =>
'Мы не нашли предыдущих покупок на этом аккаунте.';
@override
String get premiumActivo => 'Премиум активен';
}
+9
View File
@@ -1788,4 +1788,13 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get restaurarCompras => '恢复购买';
@override
String get compraError => '无法完成购买,请重试。';
@override
String get restauracionSinCompras => '未在此账户中找到以前的购买记录。';
@override
String get premiumActivo => '高级版已解锁';
}