feat:参照研听的基础工程

This commit is contained in:
jingyun
2026-06-18 15:02:28 +08:00
commit 364fc837b3
367 changed files with 16495 additions and 0 deletions
@@ -0,0 +1,123 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../../common/domain/metal_type.dart';
import '../data/market_models.dart';
import '../data/mock_market_repository.dart';
import 'market_controller.dart';
final exchangeCalculatorControllerProvider =
StateNotifierProvider<
ExchangeCalculatorController,
ExchangeCalculatorState
>((ref) {
final market = ref.watch(marketControllerProvider);
final repository = ref.watch(mockMarketRepositoryProvider);
return ExchangeCalculatorController(
repository: repository,
initialMetal: market.selectedMetal,
);
});
class ExchangeCalculatorState {
const ExchangeCalculatorState({
required this.metal,
required this.channels,
required this.selectedChannel,
required this.gram,
required this.amount,
required this.swapped,
});
final MetalType metal;
final List<ExchangeChannel> channels;
final ExchangeChannel selectedChannel;
final double gram;
final double amount;
final bool swapped;
ExchangeCalculatorState copyWith({
MetalType? metal,
List<ExchangeChannel>? channels,
ExchangeChannel? selectedChannel,
double? gram,
double? amount,
bool? swapped,
}) {
return ExchangeCalculatorState(
metal: metal ?? this.metal,
channels: channels ?? this.channels,
selectedChannel: selectedChannel ?? this.selectedChannel,
gram: gram ?? this.gram,
amount: amount ?? this.amount,
swapped: swapped ?? this.swapped,
);
}
}
class ExchangeCalculatorController
extends StateNotifier<ExchangeCalculatorState> {
ExchangeCalculatorController({
required MockMarketRepository repository,
required MetalType initialMetal,
}) : _repository = repository,
super(_initialState(repository, initialMetal));
final MockMarketRepository _repository;
void selectMetal(MetalType metal) {
final channels = _repository.channelsFor(metal);
final selected = channels.first;
state = state.copyWith(
metal: metal,
channels: channels,
selectedChannel: selected,
amount: state.gram * selected.pricePerGram,
);
}
void selectChannel(String channelId) {
final selected = state.channels.firstWhere(
(channel) => channel.id == channelId,
orElse: () => state.channels.first,
);
state = state.copyWith(
selectedChannel: selected,
amount: state.gram * selected.pricePerGram,
);
}
void setGram(double gram) {
state = state.copyWith(
gram: gram,
amount: gram * state.selectedChannel.pricePerGram,
);
}
void setAmount(double amount) {
state = state.copyWith(
amount: amount,
gram: amount / state.selectedChannel.pricePerGram,
);
}
void toggleSwapped() {
state = state.copyWith(swapped: !state.swapped);
}
static ExchangeCalculatorState _initialState(
MockMarketRepository repository,
MetalType metal,
) {
final channels = repository.channelsFor(metal);
final selected = channels.first;
const gram = 50.0;
return ExchangeCalculatorState(
metal: metal,
channels: channels,
selectedChannel: selected,
gram: gram,
amount: gram * selected.pricePerGram,
swapped: false,
);
}
}
@@ -0,0 +1,73 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../../common/domain/metal_type.dart';
import '../data/market_models.dart';
import '../data/mock_market_repository.dart';
final marketControllerProvider =
StateNotifierProvider<MarketController, MarketState>((ref) {
final repository = ref.watch(mockMarketRepositoryProvider);
return MarketController(repository);
});
class MarketState {
const MarketState({
required this.selectedMetal,
required this.period,
required this.quote,
required this.points,
required this.quotes,
});
final MetalType selectedMetal;
final MarketPeriod period;
final MetalQuote quote;
final List<MarketPoint> points;
final List<MetalQuote> quotes;
MarketState copyWith({
MetalType? selectedMetal,
MarketPeriod? period,
MetalQuote? quote,
List<MarketPoint>? points,
List<MetalQuote>? quotes,
}) {
return MarketState(
selectedMetal: selectedMetal ?? this.selectedMetal,
period: period ?? this.period,
quote: quote ?? this.quote,
points: points ?? this.points,
quotes: quotes ?? this.quotes,
);
}
}
class MarketController extends StateNotifier<MarketState> {
MarketController(this._repository)
: super(
MarketState(
selectedMetal: MetalType.gold,
period: MarketPeriod.h24,
quote: _repository.quoteFor(MetalType.gold),
points: _repository.chartFor(MetalType.gold, MarketPeriod.h24),
quotes: _repository.getQuotes(),
),
);
final MockMarketRepository _repository;
void selectMetal(MetalType metal) {
state = state.copyWith(
selectedMetal: metal,
quote: _repository.quoteFor(metal),
points: _repository.chartFor(metal, state.period),
);
}
void selectPeriod(MarketPeriod period) {
state = state.copyWith(
period: period,
points: _repository.chartFor(state.selectedMetal, period),
);
}
}