From f02e42b7f3dbcd48f1161a713319490bd3e23110 Mon Sep 17 00:00:00 2001 From: Efrain Date: Sun, 27 Feb 2022 16:28:56 -0500 Subject: [PATCH] [Application] Added initial donations bloc --- lib/application/bloc.dart | 1 + lib/application/donations/donations_bloc.dart | 63 +++++++++++++++++++ .../donations/donations_event.dart | 14 +++++ .../donations/donations_state.dart | 20 ++++++ lib/injection.dart | 11 ++++ 5 files changed, 109 insertions(+) create mode 100644 lib/application/donations/donations_bloc.dart create mode 100644 lib/application/donations/donations_event.dart create mode 100644 lib/application/donations/donations_state.dart diff --git a/lib/application/bloc.dart b/lib/application/bloc.dart index d711e65f4..7e131866e 100644 --- a/lib/application/bloc.dart +++ b/lib/application/bloc.dart @@ -12,6 +12,7 @@ export 'character/character_bloc.dart'; export 'characters/characters_bloc.dart'; export 'custom_build/custom_build_bloc.dart'; export 'custom_builds/custom_builds_bloc.dart'; +export 'donations/donations_bloc.dart'; export 'elements/elements_bloc.dart'; export 'game_codes/game_codes_bloc.dart'; export 'home/home_bloc.dart'; diff --git a/lib/application/donations/donations_bloc.dart b/lib/application/donations/donations_bloc.dart new file mode 100644 index 000000000..d3394cd06 --- /dev/null +++ b/lib/application/donations/donations_bloc.dart @@ -0,0 +1,63 @@ +import 'package:bloc/bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:shiori/domain/models/models.dart'; +import 'package:shiori/domain/services/network_service.dart'; +import 'package:shiori/domain/services/purchase_service.dart'; + +part 'donations_bloc.freezed.dart'; +part 'donations_event.dart'; +part 'donations_state.dart'; + +class DonationsBloc extends Bloc { + final PurchaseService _purchaseService; + final NetworkService _networkService; + + static int maxUserIdLength = 20; + + DonationsBloc(this._purchaseService, this._networkService) : super(const DonationsState.loading()); + + @override + Stream mapEventToState(DonationsEvent event) async* { + if (!await _networkService.isInternetAvailable()) { + yield const DonationsState.initial(packages: [], isInitialized: false, noInternetConnection: true); + return; + } + + if (!await _purchaseService.isPlatformSupported()) { + yield const DonationsState.initial(packages: [], isInitialized: false, noInternetConnection: false); + return; + } + + if (!_purchaseService.isInitialized) { + await _purchaseService.init(); + } + + final currentState = state; + final s = await event.map( + init: (_) => _init(), + restorePurchases: (e) => _restorePurchases(e.userId), + purchase: (e) => _purchase(e), + ); + + yield s; + + if ((s is _PurchaseCompleted && s.error) || (s is _RestoreCompleted && s.error)) { + yield currentState; + } + } + + Future _init() async { + final packages = await _purchaseService.getInAppPurchases(); + return DonationsState.initial(packages: packages, isInitialized: _purchaseService.isInitialized, noInternetConnection: false); + } + + Future _restorePurchases(String userId) async { + final restored = await _purchaseService.restorePurchases(userId); + return DonationsState.restoreCompleted(error: !restored); + } + + Future _purchase(_Purchase e) async { + final succeed = await _purchaseService.purchase(e.userId, e.identifier, e.offeringIdentifier); + return DonationsState.purchaseCompleted(error: !succeed); + } +} diff --git a/lib/application/donations/donations_event.dart b/lib/application/donations/donations_event.dart new file mode 100644 index 000000000..b87d5a155 --- /dev/null +++ b/lib/application/donations/donations_event.dart @@ -0,0 +1,14 @@ +part of 'donations_bloc.dart'; + +@freezed +class DonationsEvent with _$DonationsEvent { + const factory DonationsEvent.init() = _Init; + + const factory DonationsEvent.restorePurchases({required String userId}) = _RestorePurchases; + + const factory DonationsEvent.purchase({ + required String userId, + required String identifier, + required String offeringIdentifier, + }) = _Purchase; +} diff --git a/lib/application/donations/donations_state.dart b/lib/application/donations/donations_state.dart new file mode 100644 index 000000000..4dc1e8a3b --- /dev/null +++ b/lib/application/donations/donations_state.dart @@ -0,0 +1,20 @@ +part of 'donations_bloc.dart'; + +@freezed +class DonationsState with _$DonationsState { + const factory DonationsState.loading() = _Loading; + + const factory DonationsState.initial({ + required List packages, + required bool isInitialized, + required bool noInternetConnection, + }) = _InitialState; + + const factory DonationsState.purchaseCompleted({ + required bool error, + }) = _PurchaseCompleted; + + const factory DonationsState.restoreCompleted({ + required bool error, + }) = _RestoreCompleted; +} diff --git a/lib/injection.dart b/lib/injection.dart index 5462b7b5c..185947fb8 100644 --- a/lib/injection.dart +++ b/lib/injection.dart @@ -10,6 +10,7 @@ import 'package:shiori/domain/services/locale_service.dart'; import 'package:shiori/domain/services/logging_service.dart'; import 'package:shiori/domain/services/network_service.dart'; import 'package:shiori/domain/services/notification_service.dart'; +import 'package:shiori/domain/services/purchase_service.dart'; import 'package:shiori/domain/services/settings_service.dart'; import 'package:shiori/domain/services/telemetry_service.dart'; import 'package:shiori/infrastructure/infrastructure.dart'; @@ -136,6 +137,12 @@ class Injection { return CustomBuildsBloc(dataService); } + static DonationsBloc get donationsBloc { + final purchaseService = getIt(); + final networkService = getIt(); + return DonationsBloc(purchaseService, networkService); + } + //TODO: USE THIS PROP // static CalculatorAscMaterialsItemBloc get calculatorAscMaterialsItemBloc { // final genshinService = getIt(); @@ -215,5 +222,9 @@ class Injection { final changelogProvider = ChangelogProviderImpl(loggingService, networkService); getIt.registerSingleton(changelogProvider); + + final purchaseService = PurchaseServiceImpl(loggingService); + await purchaseService.init(); + getIt.registerSingleton(purchaseService); } }