feat:参照研听的基础工程
This commit is contained in:
@@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user