deposit_provider.dart 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import 'package:flutter_riverpod/flutter_riverpod.dart';
  2. import '../core/network/dio_client.dart';
  3. import '../data/models/asset/recharge_order.dart';
  4. import '../data/models/asset/recharge_record.dart';
  5. import '../data/services/asset_service.dart';
  6. import '../data/services/recharge_service.dart';
  7. // ── On-chain deposit (order flow + WalletConnect) ───────────────────
  8. class DepositState {
  9. final List<RechargeParentCoin> parentCoins;
  10. final List<RechargeFlatNetworkOption> flatNetworks;
  11. final int selectedParentIndex;
  12. final int selectedFlatIndex;
  13. final RechargeOrderDetail? currentOrder;
  14. final bool loadingParents;
  15. final bool childrenLoading;
  16. final bool orderSubmitting;
  17. final bool hashSubmitting;
  18. final bool walletPayBusy;
  19. final String? errorMessage;
  20. const DepositState({
  21. this.parentCoins = const [],
  22. this.flatNetworks = const [],
  23. this.selectedParentIndex = 0,
  24. this.selectedFlatIndex = 0,
  25. this.currentOrder,
  26. this.loadingParents = false,
  27. this.childrenLoading = false,
  28. this.orderSubmitting = false,
  29. this.hashSubmitting = false,
  30. this.walletPayBusy = false,
  31. this.errorMessage,
  32. });
  33. RechargeParentCoin? get selectedParent =>
  34. parentCoins.isNotEmpty && selectedParentIndex < parentCoins.length
  35. ? parentCoins[selectedParentIndex]
  36. : null;
  37. RechargeFlatNetworkOption? get selectedNetwork =>
  38. flatNetworks.isNotEmpty && selectedFlatIndex < flatNetworks.length
  39. ? flatNetworks[selectedFlatIndex]
  40. : null;
  41. DepositState copyWith({
  42. List<RechargeParentCoin>? parentCoins,
  43. List<RechargeFlatNetworkOption>? flatNetworks,
  44. int? selectedParentIndex,
  45. int? selectedFlatIndex,
  46. RechargeOrderDetail? currentOrder,
  47. bool? loadingParents,
  48. bool? childrenLoading,
  49. bool? orderSubmitting,
  50. bool? hashSubmitting,
  51. bool? walletPayBusy,
  52. String? errorMessage,
  53. bool clearError = false,
  54. bool clearOrder = false,
  55. }) {
  56. return DepositState(
  57. parentCoins: parentCoins ?? this.parentCoins,
  58. flatNetworks: flatNetworks ?? this.flatNetworks,
  59. selectedParentIndex: selectedParentIndex ?? this.selectedParentIndex,
  60. selectedFlatIndex: selectedFlatIndex ?? this.selectedFlatIndex,
  61. currentOrder: clearOrder ? null : (currentOrder ?? this.currentOrder),
  62. loadingParents: loadingParents ?? this.loadingParents,
  63. childrenLoading: childrenLoading ?? this.childrenLoading,
  64. orderSubmitting: orderSubmitting ?? this.orderSubmitting,
  65. hashSubmitting: hashSubmitting ?? this.hashSubmitting,
  66. walletPayBusy: walletPayBusy ?? this.walletPayBusy,
  67. errorMessage: clearError ? null : (errorMessage ?? this.errorMessage),
  68. );
  69. }
  70. }
  71. class DepositNotifier extends Notifier<DepositState> {
  72. @override
  73. DepositState build() {
  74. Future.microtask(loadParentCoins);
  75. return const DepositState(loadingParents: true);
  76. }
  77. Future<void> loadParentCoins() async {
  78. state = state.copyWith(loadingParents: true, clearError: true);
  79. try {
  80. final dio = ref.read(dioClientProvider);
  81. final list = await RechargeService(dio).getRechargeParents();
  82. var idx = state.selectedParentIndex;
  83. if (idx >= list.length) {
  84. idx = 0;
  85. }
  86. state = state.copyWith(
  87. parentCoins: list,
  88. selectedParentIndex: idx,
  89. loadingParents: false,
  90. clearError: true,
  91. );
  92. if (list.isNotEmpty) {
  93. await loadChildrenForParent(list[idx].name);
  94. } else {
  95. state = state.copyWith(flatNetworks: [], selectedFlatIndex: 0);
  96. }
  97. } catch (e) {
  98. state = state.copyWith(
  99. loadingParents: false,
  100. errorMessage: e.toString(),
  101. parentCoins: [],
  102. flatNetworks: [],
  103. );
  104. }
  105. }
  106. Future<void> loadChildrenForParent(String coinName) async {
  107. state = state.copyWith(childrenLoading: true, clearError: true);
  108. try {
  109. final dio = ref.read(dioClientProvider);
  110. final nets =
  111. await RechargeService(dio).getChildrenWithNetwork(coinName: coinName);
  112. state = state.copyWith(
  113. flatNetworks: nets,
  114. selectedFlatIndex: 0,
  115. childrenLoading: false,
  116. clearError: true,
  117. );
  118. } catch (e) {
  119. state = state.copyWith(
  120. childrenLoading: false,
  121. errorMessage: e.toString(),
  122. flatNetworks: [],
  123. );
  124. }
  125. }
  126. Future<void> selectParent(int index) async {
  127. if (index < 0 || index >= state.parentCoins.length) {
  128. return;
  129. }
  130. state = state.copyWith(selectedParentIndex: index);
  131. final p = state.parentCoins[index];
  132. await loadChildrenForParent(p.name);
  133. }
  134. void selectFlatNetwork(int index) {
  135. if (index >= 0 && index < state.flatNetworks.length) {
  136. state = state.copyWith(selectedFlatIndex: index);
  137. }
  138. }
  139. Future<void> createRechargeOrder(String amount) async {
  140. final opt = state.selectedNetwork;
  141. if (opt == null) {
  142. state = state.copyWith(errorMessage: '请先选择充值网络');
  143. return;
  144. }
  145. state = state.copyWith(orderSubmitting: true, clearError: true);
  146. try {
  147. final dio = ref.read(dioClientProvider);
  148. final order = await RechargeService(dio).createRechargeOrder(
  149. coinName: opt.coinName,
  150. networkConfigId: opt.networkConfigId,
  151. amount: amount,
  152. );
  153. state = state.copyWith(
  154. currentOrder: order,
  155. orderSubmitting: false,
  156. clearError: true,
  157. );
  158. } catch (e) {
  159. state = state.copyWith(
  160. orderSubmitting: false,
  161. errorMessage: e.toString(),
  162. );
  163. }
  164. }
  165. Future<void> submitTxHash(String txHash) async {
  166. final o = state.currentOrder;
  167. if (o == null || o.orderNo.isEmpty) {
  168. return;
  169. }
  170. state = state.copyWith(hashSubmitting: true, clearError: true);
  171. try {
  172. final dio = ref.read(dioClientProvider);
  173. final updated = await RechargeService(dio).submitTxHash(
  174. orderNo: o.orderNo,
  175. txHash: txHash,
  176. );
  177. state = state.copyWith(
  178. currentOrder: updated,
  179. hashSubmitting: false,
  180. clearError: true,
  181. );
  182. } catch (e) {
  183. state = state.copyWith(
  184. hashSubmitting: false,
  185. errorMessage: e.toString(),
  186. );
  187. }
  188. }
  189. void clearCurrentOrder() {
  190. state = state.copyWith(clearOrder: true);
  191. }
  192. void setWalletPayBusy(bool v) {
  193. state = state.copyWith(walletPayBusy: v);
  194. }
  195. void clearError() {
  196. state = state.copyWith(clearError: true);
  197. }
  198. Future<void> refresh() => loadParentCoins();
  199. }
  200. final depositProvider =
  201. NotifierProvider<DepositNotifier, DepositState>(DepositNotifier.new);
  202. // ── Recharge History (legacy list API) ──────────────────────────────
  203. class RechargeHistoryState {
  204. final List<RechargeRecord> records;
  205. final bool isLoading;
  206. final bool hasMore;
  207. final int currentPage;
  208. final String? errorMessage;
  209. const RechargeHistoryState({
  210. this.records = const [],
  211. this.isLoading = false,
  212. this.hasMore = true,
  213. this.currentPage = 1,
  214. this.errorMessage,
  215. });
  216. RechargeHistoryState copyWith({
  217. List<RechargeRecord>? records,
  218. bool? isLoading,
  219. bool? hasMore,
  220. int? currentPage,
  221. String? errorMessage,
  222. }) =>
  223. RechargeHistoryState(
  224. records: records ?? this.records,
  225. isLoading: isLoading ?? this.isLoading,
  226. hasMore: hasMore ?? this.hasMore,
  227. currentPage: currentPage ?? this.currentPage,
  228. errorMessage: errorMessage,
  229. );
  230. }
  231. class RechargeHistoryNotifier extends Notifier<RechargeHistoryState> {
  232. static const _pageSize = 10;
  233. @override
  234. RechargeHistoryState build() {
  235. Future.microtask(_loadFirst);
  236. return const RechargeHistoryState(isLoading: true);
  237. }
  238. Future<void> _loadFirst() async {
  239. state = state.copyWith(isLoading: true, errorMessage: null);
  240. try {
  241. final dio = ref.read(dioClientProvider);
  242. final records =
  243. await AssetService(dio).getRechargeList(pageNo: 1, pageSize: _pageSize);
  244. state = state.copyWith(
  245. records: records,
  246. isLoading: false,
  247. currentPage: 1,
  248. hasMore: records.length >= _pageSize,
  249. );
  250. } catch (e) {
  251. state = state.copyWith(isLoading: false, errorMessage: e.toString());
  252. }
  253. }
  254. Future<void> refresh() => _loadFirst();
  255. Future<void> loadMore() async {
  256. if (state.isLoading || !state.hasMore) {
  257. return;
  258. }
  259. state = state.copyWith(isLoading: true);
  260. try {
  261. final nextPage = state.currentPage + 1;
  262. final dio = ref.read(dioClientProvider);
  263. final records = await AssetService(dio)
  264. .getRechargeList(pageNo: nextPage, pageSize: _pageSize);
  265. state = state.copyWith(
  266. records: [...state.records, ...records],
  267. isLoading: false,
  268. currentPage: nextPage,
  269. hasMore: records.length >= _pageSize,
  270. );
  271. } catch (e) {
  272. state = state.copyWith(isLoading: false, errorMessage: e.toString());
  273. }
  274. }
  275. }
  276. final rechargeHistoryProvider =
  277. NotifierProvider<RechargeHistoryNotifier, RechargeHistoryState>(
  278. RechargeHistoryNotifier.new,
  279. );