import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../core/api/api_client.dart'; import '../core/auth/auth_state.dart'; import '../models/license.dart'; import '../repositories/license_repository.dart'; export '../models/license.dart'; final licenseRepositoryProvider = Provider( (ref) => LicenseRepository(ref.read(apiClientProvider)), ); final licenseProvider = AsyncNotifierProvider(LicenseNotifier.new); class LicenseNotifier extends AsyncNotifier { @override Future build() async { ref.watch(authStateProvider.select((s) => s.user?.shopId)); return _fetch(); } Future _fetch() async { try { return await ref.read(licenseRepositoryProvider).getInfo(); } catch (_) { return null; } } Future reload() async { state = const AsyncValue.loading(); state = AsyncValue.data(await _fetch()); } /// 后台静默刷新(供心跳调用):不闪 loading; /// 仅在成功拿到结果时更新(含「确无授权」的 null), /// 网络/瞬时错误则保留上次状态,避免把已有授权误刷成「未激活」。 /// 会话被撤销(401)由 ApiClient 拦截器统一处理(触发登出),与此无关。 Future refresh() async { try { final info = await ref.read(licenseRepositoryProvider).getInfo(); state = AsyncValue.data(info); } catch (_) { // 保留上次状态 } } /// 直接采纳心跳 /auth/ping 回带的授权概况,免去单独再请求 /license/info。 /// [raw] 为后端 LicenseInfoView 的 JSON(与 /license/info 同构); /// 为 null 表示「确无有效授权」,与 reload/refresh 拿到 null 语义一致。 void applyServerInfo(dynamic raw) { final info = raw == null ? null : LicenseInfo.fromJson(Map.from(raw as Map)); state = AsyncValue.data(info); } }