初始化
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hgdj/hj_utils/api_service/mine_service.dart';
|
||||
import 'package:hgdj/hj_utils/date_time_util.dart';
|
||||
import 'package:hgdj/hj_utils/light_model.dart';
|
||||
import 'package:hgdj/tools_base/ad_manager.dart';
|
||||
import 'package:hgdj/tools_base/debug_log.dart';
|
||||
import 'package:hgdj/tools_base/toast.dart';
|
||||
|
||||
import '../../config/config.dart';
|
||||
import '../../hj_model/user/user_info_model.dart';
|
||||
import '../../hj_model/user/wallet_model.dart';
|
||||
import '../../hj_model/video_model.dart';
|
||||
import '../../hj_utils/store_keys.dart';
|
||||
import '../../hj_utils/text_util.dart';
|
||||
import '../../track_event_manager/device_service.dart';
|
||||
import '../net/net_manager.dart';
|
||||
|
||||
/// 全局用户状态(登录信息、钱包、锁屏密码),ChangeNotifier 单例
|
||||
final globalStore = GlobalStore();
|
||||
|
||||
class GlobalStore extends ChangeNotifier {
|
||||
static final GlobalStore _instance = GlobalStore._();
|
||||
GlobalStore._();
|
||||
factory GlobalStore() => _instance;
|
||||
|
||||
// VIP 等级(对应服务端 vipLevel)
|
||||
static const int vipNormal = 0; // 普通用户
|
||||
static const int vipBasic = 1; // 普通会员
|
||||
static const int vipSuper = 2; // 超级会员
|
||||
static const int vipDarkWeb = 3; // 暗网会员
|
||||
static const int vipSwap = 4; // 换妻会员
|
||||
|
||||
final password = <int>[]; // 锁屏密码
|
||||
bool isUnlocked = false; // 本次是否已通过锁屏校验
|
||||
UserInfoModel? meInfo; // 个人信息
|
||||
WalletModel? wallet; // 钱包信息
|
||||
|
||||
/// 短剧权益从无到有的那一刻。后台加卡不会推给客户端,只有重新拉到用户信息才知道,
|
||||
/// 还挂着付费墙/正在放试看的短剧盯着它重问一次服务端
|
||||
final dramaCardGained = ValueNotifier(0);
|
||||
|
||||
/// 启动时从本地读取锁屏密码
|
||||
Future<void> init() async {
|
||||
final nativePass = await lightKV.getString(StoreKeys.PASSWORD_LOCK);
|
||||
if (nativePass == null) return;
|
||||
try {
|
||||
password.addAll(List<int>.from(json.decode(nativePass)));
|
||||
} catch (e) {
|
||||
debugLog('锁屏密码解析失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置锁屏密码
|
||||
Future<bool?> setLockPassword(List<int> input) async {
|
||||
final res =
|
||||
await lightKV.setString(StoreKeys.PASSWORD_LOCK, json.encode(input));
|
||||
if (res == true) {
|
||||
showToast('设置密码成功');
|
||||
//落盘写的是 input(覆盖),内存也得覆盖;addAll 会把旧密码留在前面,与落盘的对不上
|
||||
password
|
||||
..clear()
|
||||
..addAll(input);
|
||||
notifyListeners();
|
||||
return true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// 关闭锁屏密码(需校验原密码)
|
||||
Future<bool?> closeLockPassword(List<int> input) async {
|
||||
if (input.join('') != password.join('')) {
|
||||
showToast('密码验证失败,请重新输入~');
|
||||
return false;
|
||||
}
|
||||
final res =
|
||||
await lightKV.setString(StoreKeys.PASSWORD_LOCK, json.encode([]));
|
||||
if (res == true) {
|
||||
showToast('取消锁屏密码成功');
|
||||
password.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// 校验锁屏密码
|
||||
Future<bool?> checkLockPassword(List<int> input) async {
|
||||
if (input.join('') != password.join('')) {
|
||||
showToast('密码验证失败,请重新输入~');
|
||||
return false;
|
||||
}
|
||||
isUnlocked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 会员等级,没登录 / 没下发都按普通用户算
|
||||
int get _level => meInfo?.vipLevel ?? vipNormal;
|
||||
|
||||
/// 是否为当前用户
|
||||
bool isMe(int? uid) => uid != null && (meInfo?.uid ?? 0) == uid;
|
||||
|
||||
/// 是否充值 VIP(不包括推广)
|
||||
bool get isRechargeVIP => (meInfo?.isVip ?? false) && _level > vipNormal;
|
||||
|
||||
/// VIP(包括推广)
|
||||
bool get isVIP => meInfo?.isVip ?? false;
|
||||
|
||||
/// 有没有短剧卡:/mine/info 的 dramaExpire 晚于当前时间就是有
|
||||
bool get hasDramaCard => DateTimeUtil.isExpireDate(meInfo?.dramaExpire);
|
||||
|
||||
/// 暗网会员及以上
|
||||
bool get isAWVIP => _level >= vipDarkWeb;
|
||||
|
||||
/// 恰好是超级会员
|
||||
bool get isSuperVip => _level == vipSuper;
|
||||
|
||||
/// 超级会员及以上
|
||||
bool get isSuperUp => _level >= vipSuper;
|
||||
|
||||
/// 换妻会员及以上
|
||||
bool get isVIPTopLevel => _level >= vipSwap;
|
||||
|
||||
/// ab测试:按 showType 原地剔除当前用户看不到的视频
|
||||
/// showType 0-所有的人都可以看 1-奇数可看 2-偶数可看
|
||||
void filterShowType(List<VideoModel> list) {
|
||||
final hideType = (meInfo?.uid ?? 0) % 2 == 0 ? 1 : 2; //偶数 uid 看不到「奇数可看」的
|
||||
list.removeWhere((e) => e.showType == hideType);
|
||||
}
|
||||
|
||||
/// 会员状态文案:会员显示到期时间,非会员显示下载次数引导;[hasVipName] 是否拼接会员名称
|
||||
String vipTip({bool hasVipName = true}) {
|
||||
final vipName = meInfo?.vipName ?? '';
|
||||
if (_level > vipNormal) {
|
||||
return '${(hasVipName && vipName.isNotEmpty) ? '$vipName ' : ''} ${DateTimeUtil.utcTurnYear(meInfo?.vipExpireDate, char: '-')}';
|
||||
}
|
||||
return '开通会员免费看大片 剩余可下载次数${wallet?.downloadCount ?? 0}';
|
||||
}
|
||||
|
||||
/// 刷新钱包信息
|
||||
Future<WalletModel?> refreshWallet({bool refresh = true}) async {
|
||||
wallet = await MineService.fetchWalletData();
|
||||
if (refresh) notifyListeners();
|
||||
return wallet;
|
||||
}
|
||||
|
||||
/// 二维码登录
|
||||
/// [refresh] 是否刷新关联 globalStore 状态的页面,==false 则仅发起网络请求
|
||||
Future<UserInfoModel?> loginByQr(String qr,
|
||||
{String paste = "", bool refresh = true}) async {
|
||||
//1.存下当前 token,扫码失败要还原
|
||||
final token = await netManager.getToken();
|
||||
//2.设置 token 为空,否则获取的二维码也是老账号
|
||||
netManager.setToken('');
|
||||
//3.获取二维码账号信息,可能有其他项目的二维码,导致返回为空
|
||||
final userInfo = await MineService.devLogin(
|
||||
"",
|
||||
qr,
|
||||
DeviceInfoService.devType,
|
||||
Platform.operatingSystem,
|
||||
Config.innerVersion,
|
||||
DeviceInfoService.buildID,
|
||||
"",
|
||||
paste,
|
||||
);
|
||||
return _onLogin(userInfo, token, refresh);
|
||||
}
|
||||
|
||||
/// 设备登录
|
||||
/// [refresh] 刷新所有 user 全局状态
|
||||
Future<UserInfoModel?> loginByDevice(String deviceId,
|
||||
{String paste = "", bool refresh = true}) async {
|
||||
final userInfo = await MineService.devLogin(
|
||||
deviceId,
|
||||
"",
|
||||
DeviceInfoService.devType,
|
||||
Platform.operatingSystem,
|
||||
Config.innerVersion,
|
||||
DeviceInfoService.buildID,
|
||||
DeviceInfoService.getDevToken(deviceId),
|
||||
paste,
|
||||
);
|
||||
return _onLogin(userInfo, null, refresh);
|
||||
}
|
||||
|
||||
/// 手机号登录
|
||||
/// [refresh] 刷新所有 user 全局状态
|
||||
Future<UserInfoModel?> loginByMobile(String mobile, String code,
|
||||
{String paste = "", bool refresh = true}) async {
|
||||
final userInfo = await MineService.mobileLogin(
|
||||
mobile,
|
||||
code,
|
||||
DeviceInfoService.deviceId,
|
||||
DeviceInfoService.devType,
|
||||
Platform.operatingSystem,
|
||||
Config.innerVersion,
|
||||
DeviceInfoService.buildID,
|
||||
paste,
|
||||
);
|
||||
showToast(userInfo != null ? '登录成功' : '登录失败');
|
||||
|
||||
if (TextUtil.isNotEmpty(userInfo?.token)) {
|
||||
netManager.setToken(userInfo?.token);
|
||||
}
|
||||
if (userInfo != null && refresh) {
|
||||
_setMe(userInfo);
|
||||
await AdManager().refresh(userInfo); //换号后重算免广告策略
|
||||
notifyListeners();
|
||||
}
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
/// 写入用户信息,顺便盯住短剧权益的这一下从无到有
|
||||
void _setMe(UserInfoModel userInfo) {
|
||||
final had = hasDramaCard;
|
||||
meInfo = userInfo;
|
||||
if (!had && hasDramaCard) dramaCardGained.value++;
|
||||
}
|
||||
|
||||
/// 处理登录结果:写 token、按需刷新;失败时还原原 token
|
||||
Future<UserInfoModel?> _onLogin(
|
||||
UserInfoModel? userInfo, String? oldToken, bool refresh) async {
|
||||
if (userInfo != null) {
|
||||
if (TextUtil.isNotEmpty(userInfo.token)) {
|
||||
await netManager.setToken(userInfo.token);
|
||||
}
|
||||
if (refresh) {
|
||||
_setMe(userInfo);
|
||||
await AdManager().refresh(userInfo); //设备登录/扫码换号后重算免广告策略
|
||||
notifyListeners();
|
||||
}
|
||||
} else if (oldToken != null) {
|
||||
//登录失败,还原 token
|
||||
netManager.setToken(oldToken);
|
||||
}
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
/// 更新并获取用户信息;[map] 为空则仅拉取用户信息
|
||||
/// [refresh] 刷新所有 user 全局状态(会触发 Consumer 包裹的 widget 重建)
|
||||
Future<UserInfoModel?> updateUserInfo(
|
||||
{Map<String, dynamic>? map, bool refresh = true}) async {
|
||||
// 传了 map 才是更新,更新成功后再拉取最新信息
|
||||
final isUpdate = (map?.keys.length ?? 0) > 0;
|
||||
if (isUpdate) {
|
||||
final ok = await MineService.updateUserInfo(map!);
|
||||
if (!ok) return null;
|
||||
}
|
||||
final userInfo = await MineService.getUserInfo();
|
||||
if (refresh && userInfo != null) {
|
||||
_setMe(userInfo);
|
||||
notifyListeners();
|
||||
}
|
||||
// 与原实现一致:更新分支返回新拉取的 userInfo,纯获取分支返回 meInfo
|
||||
return isUpdate ? userInfo : meInfo;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user