guru_sdk/guru_app/lib/controller/assets_aware.dart

144 lines
6.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'package:guru_app/financial/asset/assets_model.dart';
import 'package:guru_app/financial/asset/assets_store.dart';
import 'package:guru_app/financial/financial_manager.dart';
import 'package:guru_app/financial/iap/iap_manager.dart';
import 'package:guru_app/financial/iap/iap_model.dart';
import 'package:guru_app/financial/igb/igb_manager.dart';
import 'package:guru_app/financial/igb/igb_product.dart';
import 'package:guru_app/financial/igc/igc_manager.dart';
import 'package:guru_app/financial/igc/igc_model.dart';
import 'package:guru_app/financial/product/product_store.dart';
import 'package:guru_app/financial/reward/reward_manager.dart';
import 'package:guru_app/financial/reward/reward_model.dart';
import 'package:guru_app/guru_app.dart';
import 'package:guru_app/inventory/db/inventory_database.dart';
import 'package:guru_app/inventory/inventory_manager.dart';
import 'package:guru_app/test/test_guru_app_creator.dart';
import 'package:guru_utils/collection/collectionutils.dart';
import 'package:guru_utils/datetime/datetime_utils.dart';
import 'package:guru_utils/extensions/extensions.dart';
import 'package:guru_utils/controller/controller.dart';
/// Created by Haoyi on 2022/4/7
mixin AssetsAware on LifecycleController {
final BehaviorSubject<ProductStore<IapProduct>> _productStoreSubject =
BehaviorSubject.seeded(ProductStore());
ProductStore<IapProduct> get currentProductStore => _productStoreSubject.value;
AssetsStore<Asset> get currentIapAssetStore => IapManager.instance.purchasedStore;
AssetsStore<Asset> get currentRewardedStore => RewardManager.instance.rewardedStore;
Stream<ProductStore<IapProduct>> get observableProductStore => _productStoreSubject.stream;
Stream<AssetsStore<Asset>> get observableIapPurchased => IapManager.instance.observableAssetStore;
Stream<AssetsStore<Asset>> get observableRewarded => RewardManager.instance.observableAssetStore;
Stream<AssetsStore<Asset>> get observableAssets => FinancialManager.instance.observableAssets;
int _latestRefreshIapProductTimestamp = 0;
bool get isIapCanceled => IapManager.instance.latestIapCause == IapCause.canceled;
bool get isIapError => IapManager.instance.latestIapCause == IapCause.error;
int get currentIgcBalance => IgcManager.instance.currentBalance;
Stream<int> get observableIgcBalance => IgcManager.instance.observableCurrentBalance;
Stream<Map<String, InventoryItem>> get observableInventoryItems =>
InventoryManager.instance.observableData;
Future restorePurchases() async {
return await IapManager.instance.restorePurchases();
}
Future clearIapAssets() async {
return await IapManager.instance.clearAssetRecord();
}
void observeIapProducts(Set<TransactionIntent> intents) {
addSubscription(IapManager.instance.observableProductDetails.listen((details) async {
final productStore = await IapManager.instance.buildProducts(intents);
_productStoreSubject.addEx(productStore);
}));
}
void refreshIapProducts() async {
final now = DateTimeUtils.currentTimeInMillis();
if (now - _latestRefreshIapProductTimestamp > DateTimeUtils.minuteInMillis) {
IapManager.instance.refreshProducts();
_latestRefreshIapProductTimestamp = now;
} else {
Log.w("refreshIapProducts Too Frequency!", tag: "IAP");
}
}
Future<RewardProduct> buildRewardProduct(TransactionIntent intent) {
return RewardManager.instance.buildRewardProduct(intent);
}
Future<IgbProduct> buildIgbProduct(TransactionIntent intent) {
return IgbManager.instance.buildIgbProduct(intent);
}
int getInventoryBalance(String sku) {
return InventoryManager.instance.getData(sku)?.balance ?? 0;
}
TimeSensitiveData getInventoryTimeSensitiveData(String sku) {
return InventoryManager.instance.getData(sku)?.timeSensitive ?? const TimeSensitiveData();
}
/// 使用指定[sku]的道具,[amount]为使用数量,[action]的行为,[scene]为使用场景
/// useProp最终会得到一个行为上的收益因此这里为了方便针对道具使用进行统一的行为分析
/// 这里的 [action]和[scene]最终会通过 spend_virtual_currency 事件进行统一的统计
/// propCategory可以参照 [PropCategory] 中的定义
/// 具体参数对照如下:
/// - **`item_name`**: [intent] 如果这里指定了使用道具的意图,那么这里就会使用这个意图,否则使用场景,
/// - **`item_category`**: [category],
/// - **`virtual_currency_name`**: [propSku],
/// - **`value`**: [amount],
/// - **`balance`**: balance,
/// - **`scene`**: [scene],
/// - **`level_name`**: levelName
///
/// 返回值为是否成功使用道具,false表示道具不足,true表示使用成功
///
Future<bool> useProp(
String propSku,
String scene, {
int amount = 1,
String? intent,
String category = PropCategory.boosts,
bool timeSensitiveOnly = false,
int? transactionTs,
}) async {
final manifest = Manifest.action(category, scene,
extras: CollectionUtils.filterOutNulls({
ExtraReservedField.contentId: intent ?? scene, // 如果这里指定了使用道具的意图,那么这里就会使用这个意图,否则使用场景
ExtraReservedField.transactionTs: transactionTs // 如果这里指定了交易时间,那么就会使用这个时间,否则使用当前时间
}));
return await InventoryManager.instance.consume(
[StockItem.consumable(propSku, amount)], manifest,
timeSensitiveOnly: timeSensitiveOnly);
}
Future<bool> requestProduct(Product product, {String from = ""}) async {
if (product is IapProduct) {
return await IapManager.instance.buy(product);
} else if (product is IgcProduct) {
return await IgcManager.instance.purchase(product);
} else if (product is RewardProduct) {
return await RewardManager.instance.claim(product);
} else if (product is IgbProduct) {
return await IgbManager.instance.redeem(product);
} else {
return false;
}
}
}