import 'package:flutter/foundation.dart'; import 'license_service.dart'; import 'models.dart'; import 'order_api.dart'; import 'payment_service.dart'; enum PayState { idle, loading, success, failed } @immutable class PaywallUiState { final PayState state; final String? message; final Plan? selectedPlan; const PaywallUiState({ this.state = PayState.idle, this.message, this.selectedPlan, }); } class PaywallViewModel extends ChangeNotifier { final OrderApi orderApi; final LicenseService licenseService; final Map services; PaywallUiState _state = const PaywallUiState(); PaywallUiState get state => _state; List _plans = const []; bool _plansLoading = false; String? _plansError; /// 套餐价格方案(来自后端,客户端不硬编码) List get plans => _plans; bool get plansLoading => _plansLoading; String? get plansError => _plansError; PaywallViewModel({ required this.orderApi, required this.licenseService, required this.services, }); /// 进充值页时拉取套餐;已有数据或加载中跳过,失败可重试 Future loadPlans() async { if (_plans.isNotEmpty || _plansLoading) return; _plansLoading = true; _plansError = null; notifyListeners(); try { _plans = await orderApi.fetchPlans(); } on SessionExpiredException { _plansError = '登录已失效,请重新登录后再充值'; } on OrderApiException catch (e) { _plansError = e.message; } finally { _plansLoading = false; notifyListeners(); } } void selectPlan(Plan? plan) { _state = PaywallUiState(selectedPlan: plan); notifyListeners(); } /// 发起支付;成功后刷新授权并通知页面进入相机 Future pay(PayChannel channel) async { final plan = _state.selectedPlan; if (plan == null) return null; final service = services[channel]; if (service == null) return null; _state = PaywallUiState(state: PayState.loading, selectedPlan: plan); notifyListeners(); try { final result = await service.pay(plan, channel); if (!result.success) { _state = PaywallUiState( state: PayState.failed, message: result.message ?? '支付失败,请重试', selectedPlan: plan, ); notifyListeners(); return null; } final license = await licenseService.refresh(); _state = PaywallUiState( state: PayState.success, selectedPlan: plan, ); notifyListeners(); return license; } on SessionExpiredException { _state = PaywallUiState( state: PayState.failed, message: '登录已失效,请重新登录后再充值', selectedPlan: plan, ); notifyListeners(); return null; } on OrderApiException catch (e) { _state = PaywallUiState( state: PayState.failed, message: '支付不可用: ${e.message}', selectedPlan: plan, ); notifyListeners(); return null; } } void reset() { _state = const PaywallUiState(); notifyListeners(); } }