diff --git a/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk b/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk index e4325ce..0aa02ee 100644 Binary files a/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk and b/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk differ diff --git a/lib/features/subscription/buy_subscription_model.dart b/lib/features/subscription/buy_subscription_model.dart new file mode 100644 index 0000000..0a61380 --- /dev/null +++ b/lib/features/subscription/buy_subscription_model.dart @@ -0,0 +1,3 @@ +class BuySubscriptionModel { + +} \ No newline at end of file diff --git a/lib/features/subscription/subscription_api.dart b/lib/features/subscription/subscription_api.dart new file mode 100644 index 0000000..dcbc516 --- /dev/null +++ b/lib/features/subscription/subscription_api.dart @@ -0,0 +1,40 @@ +import 'dart:typed_data'; + +import 'package:dio/dio.dart'; +import 'package:mnemo_cards_common/mnemo_cards_common.dart'; + +import '../../managers/repository/api.dart'; + +class SubscriptionApi with Api { + final Dio _dio; + + SubscriptionApi(this._dio); + + // buy page dto if not available + Future getPackBuy(String id) async { + final r = await _dio.get( + '$path/pack/buy/$id', + options: Options( + sendTimeout: Duration(seconds: 5), + receiveTimeout: Duration(seconds: 5), + ), + ); + return (r.data as String).decode(CardPackBuyDto.fromJson); + } + + /// cards zip archive for available pack + /// unavailable packs transfer images by base64 + Future packImagesArchive(String packId) async { + final response = await _dio.get( + '$path/pack/cards/$packId', + options: Options( + responseType: ResponseType.bytes, + ), + ); + final data = response.data; + if (data == null) { + return Uint8List.fromList([]); + } + return data; + } +} diff --git a/lib/features/yandex_ads/yandex_ads.dart b/lib/features/yandex_ads/yandex_ads.dart index 6b1f006..9820f2f 100644 --- a/lib/features/yandex_ads/yandex_ads.dart +++ b/lib/features/yandex_ads/yandex_ads.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:developer'; import 'package:flutter/widgets.dart'; @@ -8,7 +9,7 @@ class YandexAds { BoxConstraints constraints, { required String id, String? key, - VoidCallback? onLoaded, + VoidCallback? onLoaded, }) { return BannerAd( adUnitId: id, @@ -39,4 +40,56 @@ class YandexAds { // Called when an impression is recorded for an ad. }); } + + static RewardedAd? _preloadedAd; + + static Future loadRewardedAd() async { + final completer = Completer(); + final _rewardedAdLoader = await RewardedAdLoader.create( + onAdLoaded: (RewardedAd rewardedAd) { + _preloadedAd = rewardedAd; + completer.complete(rewardedAd); + }, + onAdFailedToLoad: (error) { + completer.complete(null); + }, + ); + await _rewardedAdLoader.loadAd( + adRequestConfiguration: AdRequestConfiguration( + adUnitId: 'R-M-3761037-1', + ), + ); + return completer.future; + } + + static Future showRewardedAd( + Function(Reward reward) onRewarded, { + maxAttempts = 2, + }) async { + if (_preloadedAd == null) { + final _loadedAd = await loadRewardedAd(); + if (_loadedAd == null) { + return false; + } + } + final _ad = _preloadedAd; + _preloadedAd = null; + _ad?.setAdEventListener( + eventListener: RewardedAdEventListener(onAdDismissed: () { + _ad.destroy(); + }, onAdFailedToShow: (e) { + _ad.destroy(); + if (maxAttempts-- > 0) { + showRewardedAd(onRewarded, maxAttempts: maxAttempts); + } + }, onAdShown: () { + // _ad.destroy(); + }, onRewarded: (r) { + onRewarded(r); + _ad.destroy(); + })); + await _ad?.show(); + final reward = await _ad?.waitForDismiss(); + return reward != null; + } } diff --git a/lib/main.dart b/lib/main.dart index 5a120cf..4d1be98 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -89,7 +89,7 @@ void main() async { await locator.previewPackPoller.init(); await locator.packUpdater.init(); print('initing complete ${stopwatch.elapsedMilliseconds}'); - if (!kIsWeb) await MobileAds.initialize(); + if (!kIsWeb) unawaited(MobileAds.initialize()); print('mobile ads ${stopwatch.elapsedMilliseconds}'); print('runApp ${stopwatch.elapsedMilliseconds}'); runApp(const MyApp()); diff --git a/lib/pages/profile_page.dart b/lib/pages/profile_page.dart index 8a40ac8..8e7c207 100644 --- a/lib/pages/profile_page.dart +++ b/lib/pages/profile_page.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:mnemo_cards/domain/router/app_router.dart'; import 'package:mnemo_cards/domain/router/app_router.gr.dart'; +import 'package:mnemo_cards/features/yandex_ads/yandex_ads.dart'; import 'package:mnemo_cards/flags.dart'; import 'package:mnemo_cards/main.dart'; import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; @@ -145,6 +146,17 @@ class ProfilePage extends StatelessWidget { height: 5, color: borderGray.withOpacity(0.2), ), + if (SHOW_ADMIN) + SimpleTile(title: Text('Посмотреть рекламу'), onTap: () { + YandexAds.showRewardedAd((r) { + showErrorDialog('Вы получили\n${r.amount} ${r.type}'); + }); + },), + if (SHOW_ADMIN) + Divider( + height: 5, + color: borderGray.withOpacity(0.2), + ), SimpleTile.text( text: 'Написать в телеграм', onTap: () => launchUrl( diff --git a/lib/widgets/buy_subscription_widget.dart b/lib/widgets/buy_subscription_widget.dart new file mode 100644 index 0000000..7cae818 --- /dev/null +++ b/lib/widgets/buy_subscription_widget.dart @@ -0,0 +1,31 @@ +import 'package:flutter/cupertino.dart'; +import 'package:mnemo_cards/main.dart'; +import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; + +import '../di/injector.dart'; +import '../di/locator.dart'; +import '../domain/router/app_router.dart'; +import '../features/packs/packs_api.dart'; + +class MobileBuySubscriptionWidget extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return BuySubscriptionWidget(onBuySubscription: onBuySubscription); + } + + Future onBuySubscription() async { + final user = locator.userManager.userStateHolder.user; + if (user == null) { + AppRouter.openAuthOrProfile(); + return; + } + if (user.subscription) { + return; + } + final packsApi = getIt.get(); + // final buyDto = await packsApi.getPackBuy(id).catchError((_) => null); + } + + const MobileBuySubscriptionWidget(); +} \ No newline at end of file diff --git a/lib/widgets/enter_promo_code_widget.dart b/lib/widgets/enter_promo_code_widget.dart index 3be13fc..302493c 100644 --- a/lib/widgets/enter_promo_code_widget.dart +++ b/lib/widgets/enter_promo_code_widget.dart @@ -5,8 +5,6 @@ import '../di/locator.dart'; class MobileEnterPromoCodeWidget extends StatelessWidget { - - @override Widget build(BuildContext context) { return EnterPromoCodeWidget(onApplyPromoCode: onApplyPromoCode);