feat:参照研听的基础工程
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import '../../../common/domain/metal_type.dart';
|
||||
import '../../market/data/mock_market_repository.dart';
|
||||
import '../data/asset_models.dart';
|
||||
import '../data/mock_asset_repository.dart';
|
||||
|
||||
final assetPortfolioControllerProvider =
|
||||
StateNotifierProvider<AssetPortfolioController, PortfolioSummary>((ref) {
|
||||
final holdings = ref.watch(mockAssetRepositoryProvider).loadHoldings();
|
||||
final market = ref.watch(mockMarketRepositoryProvider);
|
||||
return AssetPortfolioController(
|
||||
holdings: holdings,
|
||||
spotPriceFor: (metal) => market.quoteFor(metal).spotPrice,
|
||||
changeFor: (metal) => market.quoteFor(metal).changeAmount,
|
||||
);
|
||||
});
|
||||
|
||||
class AssetPortfolioController extends StateNotifier<PortfolioSummary> {
|
||||
AssetPortfolioController({
|
||||
required List<GoldAssetHolding> holdings,
|
||||
required double Function(MetalType metal) spotPriceFor,
|
||||
required double Function(MetalType metal) changeFor,
|
||||
this.recycleDiscount = 0.97,
|
||||
}) : _holdings = holdings,
|
||||
_spotPriceFor = spotPriceFor,
|
||||
_changeFor = changeFor,
|
||||
super(
|
||||
_buildSummary(
|
||||
holdings: holdings,
|
||||
spotPriceFor: spotPriceFor,
|
||||
changeFor: changeFor,
|
||||
recycleDiscount: recycleDiscount,
|
||||
),
|
||||
);
|
||||
|
||||
final List<GoldAssetHolding> _holdings;
|
||||
final double Function(MetalType metal) _spotPriceFor;
|
||||
final double Function(MetalType metal) _changeFor;
|
||||
final double recycleDiscount;
|
||||
|
||||
void addHolding(GoldAssetHolding holding) {
|
||||
_holdings.add(holding);
|
||||
state = _buildSummary(
|
||||
holdings: _holdings,
|
||||
spotPriceFor: _spotPriceFor,
|
||||
changeFor: _changeFor,
|
||||
recycleDiscount: recycleDiscount,
|
||||
);
|
||||
}
|
||||
|
||||
static PortfolioSummary _buildSummary({
|
||||
required List<GoldAssetHolding> holdings,
|
||||
required double Function(MetalType metal) spotPriceFor,
|
||||
required double Function(MetalType metal) changeFor,
|
||||
required double recycleDiscount,
|
||||
}) {
|
||||
final active = holdings
|
||||
.where((holding) => holding.status == HoldingStatus.active)
|
||||
.toList(growable: false);
|
||||
final valuations = [
|
||||
for (final holding in active)
|
||||
HoldingValuation(
|
||||
holding: holding,
|
||||
materialValue: holding.materialValue(spotPriceFor(holding.metal)),
|
||||
todayChange:
|
||||
holding.weightGram * holding.purity * changeFor(holding.metal),
|
||||
),
|
||||
];
|
||||
|
||||
final totalValue = valuations.fold<double>(
|
||||
0,
|
||||
(sum, item) => sum + item.materialValue,
|
||||
);
|
||||
final todayChange = valuations.fold<double>(
|
||||
0,
|
||||
(sum, item) => sum + item.todayChange,
|
||||
);
|
||||
final totalCost = active.fold<double>(
|
||||
0,
|
||||
(sum, holding) => sum + (holding.costAmount ?? 0),
|
||||
);
|
||||
final totalWeight = active.fold<double>(
|
||||
0,
|
||||
(sum, holding) => sum + holding.weightGram,
|
||||
);
|
||||
|
||||
return PortfolioSummary(
|
||||
totalValue: totalValue,
|
||||
todayChangeAmount: todayChange,
|
||||
todayChangePercent: totalValue == 0 ? 0 : todayChange / totalValue * 100,
|
||||
totalCost: totalCost,
|
||||
totalWeightGram: totalWeight,
|
||||
recycleReferenceValue: totalValue * recycleDiscount,
|
||||
breakdowns: [
|
||||
for (final metal in MetalType.values)
|
||||
_breakdownFor(metal, active, spotPriceFor),
|
||||
].where((item) => item.count > 0).toList(growable: false),
|
||||
holdings: valuations,
|
||||
);
|
||||
}
|
||||
|
||||
static MetalBreakdown _breakdownFor(
|
||||
MetalType metal,
|
||||
List<GoldAssetHolding> holdings,
|
||||
double Function(MetalType metal) spotPriceFor,
|
||||
) {
|
||||
final items = holdings.where((holding) => holding.metal == metal).toList();
|
||||
return MetalBreakdown(
|
||||
metal: metal,
|
||||
value: items.fold<double>(
|
||||
0,
|
||||
(sum, holding) => sum + holding.materialValue(spotPriceFor(metal)),
|
||||
),
|
||||
weightGram: items.fold<double>(
|
||||
0,
|
||||
(sum, holding) => sum + holding.weightGram,
|
||||
),
|
||||
count: items.length,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user