Files

121 lines
3.1 KiB
Dart

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<PayChannel, PaymentService> services;
PaywallUiState _state = const PaywallUiState();
PaywallUiState get state => _state;
List<Plan> _plans = const [];
bool _plansLoading = false;
String? _plansError;
/// 套餐价格方案(来自后端,客户端不硬编码)
List<Plan> get plans => _plans;
bool get plansLoading => _plansLoading;
String? get plansError => _plansError;
PaywallViewModel({
required this.orderApi,
required this.licenseService,
required this.services,
});
/// 进充值页时拉取套餐;已有数据或加载中跳过,失败可重试
Future<void> 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<LicenseStatus?> 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();
}
}