spot_coin_cache_provider.dart 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import 'package:flutter_riverpod/flutter_riverpod.dart';
  2. import '../core/network/dio_client.dart';
  3. import '../data/services/spot_service.dart';
  4. /// 单币种配置(来自 spot/v1/config/coin/list)
  5. class SpotCoinConfig {
  6. final String coin;
  7. final String icon;
  8. final int scale; // 余额显示小数位数(coinScale/scale/minScale)
  9. final int volumePre; // 数量精度(volumePre,覆盖 scale)
  10. /// 前台展示小数位(后端 showPrecision,与 ConfigCoinSymbol 一致)
  11. final int showPrecision;
  12. const SpotCoinConfig({
  13. required this.coin,
  14. this.icon = '',
  15. this.scale = 8,
  16. this.volumePre = 8,
  17. this.showPrecision = 0,
  18. });
  19. /// 资产列表等「按币种展示数量」的小数位:仅用后端 showPrecision;未配置(≤0)时默认 2
  20. int get assetDisplayDecimals =>
  21. showPrecision > 0 ? showPrecision.clamp(0, 18) : 2;
  22. factory SpotCoinConfig.fromJson(Map<String, dynamic> json) {
  23. final coin = (json['symbol'] ?? json['coinId'] ?? json['coin'] ?? '')
  24. .toString()
  25. .toUpperCase();
  26. final scale =
  27. ((json['coinScale'] ?? json['scale'] ?? json['minScale']) as num?)
  28. ?.toInt() ??
  29. 8;
  30. final volumePre =
  31. (json['volumePre'] as num?)?.toInt() ?? scale;
  32. final showPrecision =
  33. (json['showPrecision'] as num?)?.toInt() ?? 0;
  34. return SpotCoinConfig(
  35. coin: coin,
  36. icon: json['icon'] as String? ?? '',
  37. scale: scale,
  38. volumePre: volumePre,
  39. showPrecision: showPrecision,
  40. );
  41. }
  42. }
  43. /// 全局现货币种缓存 — 缓存 spot/v1/config/coin/list 返回的所有币种信息
  44. /// 键为大写币种符号(如 "BTC", "USDT"),供现货资产列表查询图标和余额精度
  45. class SpotCoinCacheNotifier extends Notifier<Map<String, SpotCoinConfig>> {
  46. @override
  47. Map<String, SpotCoinConfig> build() {
  48. Future.microtask(_load);
  49. return {};
  50. }
  51. Future<void> _load() async {
  52. try {
  53. final dio = ref.read(dioClientProvider);
  54. final coins = await SpotService(dio).getCoins();
  55. final configs = coins
  56. .map(SpotCoinConfig.fromJson)
  57. .where((c) => c.coin.isNotEmpty);
  58. state = {for (final c in configs) c.coin: c};
  59. } catch (_) {}
  60. }
  61. Future<void> refresh() => _load();
  62. }
  63. final spotCoinCacheProvider =
  64. NotifierProvider<SpotCoinCacheNotifier, Map<String, SpotCoinConfig>>(
  65. SpotCoinCacheNotifier.new,
  66. );
  67. /// 键统一为大写,与 [SpotCoinCacheNotifier] 中 map 一致
  68. SpotCoinConfig? lookupSpotCoinConfig(
  69. Map<String, SpotCoinConfig> map,
  70. String coin,
  71. ) {
  72. final k = coin.trim().toUpperCase();
  73. if (k.isEmpty) return null;
  74. return map[k];
  75. }
  76. /// 仅使用现货币种配置里的 icon(去空白);空串表示只显示字母占位,与「资产→现货」一致
  77. String spotCoinIconUrl(Map<String, SpotCoinConfig> map, String coin) {
  78. final raw = lookupSpotCoinConfig(map, coin)?.icon ?? '';
  79. return raw.trim();
  80. }