import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../core/network/dio_client.dart'; import '../data/models/asset/recharge_order.dart'; import '../data/models/asset/recharge_record.dart'; import '../data/services/asset_service.dart'; import '../data/services/recharge_service.dart'; // ── On-chain deposit (order flow + WalletConnect) ─────────────────── class DepositState { final List parentCoins; final List flatNetworks; final int selectedParentIndex; final int selectedFlatIndex; final RechargeOrderDetail? currentOrder; final bool loadingParents; final bool childrenLoading; final bool orderSubmitting; final bool hashSubmitting; final bool walletPayBusy; final String? errorMessage; const DepositState({ this.parentCoins = const [], this.flatNetworks = const [], this.selectedParentIndex = 0, this.selectedFlatIndex = 0, this.currentOrder, this.loadingParents = false, this.childrenLoading = false, this.orderSubmitting = false, this.hashSubmitting = false, this.walletPayBusy = false, this.errorMessage, }); RechargeParentCoin? get selectedParent => parentCoins.isNotEmpty && selectedParentIndex < parentCoins.length ? parentCoins[selectedParentIndex] : null; RechargeFlatNetworkOption? get selectedNetwork => flatNetworks.isNotEmpty && selectedFlatIndex < flatNetworks.length ? flatNetworks[selectedFlatIndex] : null; DepositState copyWith({ List? parentCoins, List? flatNetworks, int? selectedParentIndex, int? selectedFlatIndex, RechargeOrderDetail? currentOrder, bool? loadingParents, bool? childrenLoading, bool? orderSubmitting, bool? hashSubmitting, bool? walletPayBusy, String? errorMessage, bool clearError = false, bool clearOrder = false, }) { return DepositState( parentCoins: parentCoins ?? this.parentCoins, flatNetworks: flatNetworks ?? this.flatNetworks, selectedParentIndex: selectedParentIndex ?? this.selectedParentIndex, selectedFlatIndex: selectedFlatIndex ?? this.selectedFlatIndex, currentOrder: clearOrder ? null : (currentOrder ?? this.currentOrder), loadingParents: loadingParents ?? this.loadingParents, childrenLoading: childrenLoading ?? this.childrenLoading, orderSubmitting: orderSubmitting ?? this.orderSubmitting, hashSubmitting: hashSubmitting ?? this.hashSubmitting, walletPayBusy: walletPayBusy ?? this.walletPayBusy, errorMessage: clearError ? null : (errorMessage ?? this.errorMessage), ); } } class DepositNotifier extends Notifier { @override DepositState build() { Future.microtask(loadParentCoins); return const DepositState(loadingParents: true); } Future loadParentCoins() async { state = state.copyWith(loadingParents: true, clearError: true); try { final dio = ref.read(dioClientProvider); final list = await RechargeService(dio).getRechargeParents(); var idx = state.selectedParentIndex; if (idx >= list.length) { idx = 0; } state = state.copyWith( parentCoins: list, selectedParentIndex: idx, loadingParents: false, clearError: true, ); if (list.isNotEmpty) { await loadChildrenForParent(list[idx].name); } else { state = state.copyWith(flatNetworks: [], selectedFlatIndex: 0); } } catch (e) { state = state.copyWith( loadingParents: false, errorMessage: e.toString(), parentCoins: [], flatNetworks: [], ); } } Future loadChildrenForParent(String coinName) async { state = state.copyWith(childrenLoading: true, clearError: true); try { final dio = ref.read(dioClientProvider); final nets = await RechargeService(dio).getChildrenWithNetwork(coinName: coinName); state = state.copyWith( flatNetworks: nets, selectedFlatIndex: 0, childrenLoading: false, clearError: true, ); } catch (e) { state = state.copyWith( childrenLoading: false, errorMessage: e.toString(), flatNetworks: [], ); } } Future selectParent(int index) async { if (index < 0 || index >= state.parentCoins.length) { return; } state = state.copyWith(selectedParentIndex: index); final p = state.parentCoins[index]; await loadChildrenForParent(p.name); } void selectFlatNetwork(int index) { if (index >= 0 && index < state.flatNetworks.length) { state = state.copyWith(selectedFlatIndex: index); } } Future createRechargeOrder(String amount) async { final opt = state.selectedNetwork; if (opt == null) { state = state.copyWith(errorMessage: '请先选择充值网络'); return; } state = state.copyWith(orderSubmitting: true, clearError: true); try { final dio = ref.read(dioClientProvider); final order = await RechargeService(dio).createRechargeOrder( coinName: opt.coinName, networkConfigId: opt.networkConfigId, amount: amount, ); state = state.copyWith( currentOrder: order, orderSubmitting: false, clearError: true, ); } catch (e) { state = state.copyWith( orderSubmitting: false, errorMessage: e.toString(), ); } } Future submitTxHash(String txHash) async { final o = state.currentOrder; if (o == null || o.orderNo.isEmpty) { return; } state = state.copyWith(hashSubmitting: true, clearError: true); try { final dio = ref.read(dioClientProvider); final updated = await RechargeService(dio).submitTxHash( orderNo: o.orderNo, txHash: txHash, ); state = state.copyWith( currentOrder: updated, hashSubmitting: false, clearError: true, ); } catch (e) { state = state.copyWith( hashSubmitting: false, errorMessage: e.toString(), ); } } void clearCurrentOrder() { state = state.copyWith(clearOrder: true); } void setWalletPayBusy(bool v) { state = state.copyWith(walletPayBusy: v); } void clearError() { state = state.copyWith(clearError: true); } Future refresh() => loadParentCoins(); } final depositProvider = NotifierProvider(DepositNotifier.new); // ── Recharge History (legacy list API) ────────────────────────────── class RechargeHistoryState { final List records; final bool isLoading; final bool hasMore; final int currentPage; final String? errorMessage; const RechargeHistoryState({ this.records = const [], this.isLoading = false, this.hasMore = true, this.currentPage = 1, this.errorMessage, }); RechargeHistoryState copyWith({ List? records, bool? isLoading, bool? hasMore, int? currentPage, String? errorMessage, }) => RechargeHistoryState( records: records ?? this.records, isLoading: isLoading ?? this.isLoading, hasMore: hasMore ?? this.hasMore, currentPage: currentPage ?? this.currentPage, errorMessage: errorMessage, ); } class RechargeHistoryNotifier extends Notifier { static const _pageSize = 10; @override RechargeHistoryState build() { Future.microtask(_loadFirst); return const RechargeHistoryState(isLoading: true); } Future _loadFirst() async { state = state.copyWith(isLoading: true, errorMessage: null); try { final dio = ref.read(dioClientProvider); final records = await AssetService(dio).getRechargeList(pageNo: 1, pageSize: _pageSize); state = state.copyWith( records: records, isLoading: false, currentPage: 1, hasMore: records.length >= _pageSize, ); } catch (e) { state = state.copyWith(isLoading: false, errorMessage: e.toString()); } } Future refresh() => _loadFirst(); Future loadMore() async { if (state.isLoading || !state.hasMore) { return; } state = state.copyWith(isLoading: true); try { final nextPage = state.currentPage + 1; final dio = ref.read(dioClientProvider); final records = await AssetService(dio) .getRechargeList(pageNo: nextPage, pageSize: _pageSize); state = state.copyWith( records: [...state.records, ...records], isLoading: false, currentPage: nextPage, hasMore: records.length >= _pageSize, ); } catch (e) { state = state.copyWith(isLoading: false, errorMessage: e.toString()); } } } final rechargeHistoryProvider = NotifierProvider( RechargeHistoryNotifier.new, );