167 lines
6.1 KiB
Dart
167 lines
6.1 KiB
Dart
import 'package:guru_app/analytics/guru_analytics.dart';
|
|
import 'package:guru_app/database/guru_db.dart';
|
|
import 'package:guru_app/financial/asset/assets_model.dart';
|
|
import 'package:guru_app/financial/asset/assets_store.dart';
|
|
import 'package:guru_app/financial/data/db/order_database.dart';
|
|
import 'package:guru_app/financial/igc/igc_model.dart';
|
|
import 'package:guru_app/financial/manifest/manifest_manager.dart';
|
|
import 'package:guru_app/financial/product/product_model.dart';
|
|
import 'package:guru_app/guru_app.dart';
|
|
import 'package:guru_app/property/app_property.dart';
|
|
import 'package:guru_utils/extensions/extensions.dart';
|
|
import 'package:guru_utils/log/log.dart';
|
|
import 'package:guru_utils/property/app_property.dart';
|
|
|
|
/// Created by Haoyi on 2023/2/18
|
|
|
|
class IgcManager {
|
|
static final IgcManager _instance = IgcManager._();
|
|
|
|
static IgcManager get instance => _instance;
|
|
|
|
final BehaviorSubject<int> _balanceSubject = BehaviorSubject.seeded(0);
|
|
|
|
final BehaviorSubject<AssetsStore<Asset>> _assetStoreSubject =
|
|
BehaviorSubject.seeded(AssetsStore<Asset>.inactive());
|
|
|
|
Stream<AssetsStore<Asset>> get observableAssetStore => _assetStoreSubject.stream;
|
|
|
|
AssetsStore<Asset> get purchasedStore => _assetStoreSubject.value;
|
|
|
|
int get currentBalance => _balanceSubject.value;
|
|
|
|
Stream<int> get observableCurrentBalance => _balanceSubject.stream;
|
|
|
|
final CompositeSubscription subscriptions = CompositeSubscription();
|
|
|
|
IgcManager._();
|
|
|
|
Future init() async {
|
|
final attachedGems = (await AppProperty.getInstance().isFirstUseGemsFeature())
|
|
? GuruApp.instance.appSpec.deployment.initIgc
|
|
: 0;
|
|
final _balance = await AppProperty.getInstance().accumulateIgc(attachedGems);
|
|
_balanceSubject.addEx(_balance);
|
|
GuruAnalytics.instance.setUserProperty("coin", _balance.toString());
|
|
|
|
final iapIgc = await AppProperty.getInstance().getIapIgc();
|
|
GuruAnalytics.instance.setUserProperty("iap_coin", iapIgc.toString());
|
|
|
|
final noIapIgcGems = await AppProperty.getInstance().getNoIapIgc();
|
|
GuruAnalytics.instance.setUserProperty("noniap_coin", noIapIgcGems.toString());
|
|
await reloadAssets();
|
|
}
|
|
|
|
Future reloadAssets() async {
|
|
final orders = await GuruDB.instance
|
|
.selectOrders(method: TransactionMethod.igc, attrs: [TransactionAttributes.asset]);
|
|
final newAssetStore = AssetsStore<Asset>();
|
|
for (var order in orders) {
|
|
final productId = order.productId;
|
|
Log.v("init order:${order.sku} $productId");
|
|
newAssetStore.addAsset(Asset(productId, order));
|
|
}
|
|
_assetStoreSubject.addEx(newAssetStore);
|
|
}
|
|
|
|
Future clearAssets({String? category, TransactionMethod? method}) async {
|
|
await GuruDB.instance.clearOrders(category: category, method: method);
|
|
final newAssetStore = purchasedStore.clone()..clearAsset(category: category, method: method);
|
|
_assetStoreSubject.addEx(newAssetStore);
|
|
}
|
|
|
|
Future<bool> accumulate(int igc, TransactionMethod method, {String? scene}) async {
|
|
try {
|
|
int newBalance = await AppProperty.getInstance().accumulateIgc(igc);
|
|
try {
|
|
if (method == TransactionMethod.iap) {
|
|
final iapIgc = await AppProperty.getInstance().accumulateIapIgc(igc);
|
|
await GuruAnalytics.instance.setUserProperty("iap_coin", iapIgc.toString());
|
|
} else {
|
|
final noniapIgc = await AppProperty.getInstance().accumulateNoIapIgc(igc);
|
|
await GuruAnalytics.instance.setUserProperty("noniap_coin", noniapIgc.toString());
|
|
}
|
|
await GuruAnalytics.instance.setUserProperty("coin", newBalance.toString());
|
|
} catch (throwable, stacktrace) {
|
|
Log.w("accumulate error $throwable", syncFirebase: true, syncCrashlytics: true);
|
|
}
|
|
_balanceSubject.add(newBalance);
|
|
|
|
GuruAnalytics.instance.logEarnVirtualCurrency(
|
|
virtualCurrencyName: "coin",
|
|
method: scene ?? convertTransactionMethodName(method),
|
|
balance: newBalance,
|
|
value: igc);
|
|
return true;
|
|
} catch (error, stacktrace) {
|
|
Log.v("accumulate error:$error $stacktrace");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Future clear() async {
|
|
final result = await AppProperty.getInstance().clearAllIgc();
|
|
if (result) {
|
|
_balanceSubject.add(0);
|
|
}
|
|
}
|
|
|
|
Future<IgcProduct> buildIgcProduct(TransactionIntent intent) async {
|
|
final manifest = await ManifestManager.instance.createManifest(intent);
|
|
return IgcProduct(intent.productId, manifest, intent.igcCost);
|
|
}
|
|
|
|
Future<bool> purchase(IgcProduct product) async {
|
|
Log.v("Igc buy");
|
|
|
|
final purchasedItem = purchasedStore.getAsset(product.productId);
|
|
if (purchasedItem != null) {
|
|
Log.v("Coin buy ${purchasedItem.productId} direct success!");
|
|
return true;
|
|
}
|
|
return _requestPurchase(product);
|
|
}
|
|
|
|
Future<bool> _requestPurchase(IgcProduct product) async {
|
|
if (currentBalance < product.cost || product.cost < 0) {
|
|
Log.v("_requestPurchase error! $currentBalance price:${product.cost}");
|
|
return false;
|
|
}
|
|
try {
|
|
final int newBalance = await AppProperty.getInstance().consumeIgc(product.cost);
|
|
await GuruAnalytics.instance.setUserProperty("coin", newBalance.toString());
|
|
|
|
if (currentBalance != newBalance) {
|
|
_balanceSubject.add(newBalance);
|
|
}
|
|
|
|
if (product.cost != 0) {
|
|
GuruAnalytics.instance.logSpendCredits(
|
|
product.productId.sku, product.manifest.category, product.cost,
|
|
virtualCurrencyName: "coin", balance: newBalance, scene: product.manifest.scene);
|
|
}
|
|
|
|
if (!product.productId.isConsumable) {
|
|
final order = product.createOrder();
|
|
await GuruDB.instance.upsertOrder(order: order).catchError((error) {
|
|
Log.v("upsertOrder error!$error");
|
|
return false;
|
|
});
|
|
final newPurchasedStore = purchasedStore.clone();
|
|
newPurchasedStore.addAsset(Asset(product.productId, order));
|
|
_assetStoreSubject.addEx(newPurchasedStore);
|
|
}
|
|
return true;
|
|
} catch (error, stacktrace) {
|
|
Log.v("error $error, $stacktrace");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void dispose() {
|
|
// _productStoreSubject.close();
|
|
_assetStoreSubject.close();
|
|
_balanceSubject.close();
|
|
}
|
|
}
|