//公共服务api接口 import 'package:hgdj/hj_model/home/video_list_model.dart'; import 'package:hgdj/hj_model/list_base_model.dart'; import 'package:hgdj/tools_base/event_bus/events.dart'; import 'package:hgdj/tools_base/net/http_manager.dart'; import '../../alert/vip_guide/guide_manager.dart'; import '../../alert/vip_guide/guide_push_model.dart'; import '../../hj_model/banner/comment_top_banner_model.dart'; import '../../hj_model/home/plate_model.dart'; import '../../hj_model/home/update_marker_model.dart'; import '../../hj_model/mine/follow_user_list_model.dart'; import '../../hj_model/mine/happy/happy_model.dart'; import '../../hj_model/mine/task_center_data.dart'; import '../../hj_model/splash/domain_source_model.dart'; import '../../tools_base/event_bus/event_bus_util.dart'; class CommonService { /// 获取远端配置 static Future fetchRemoteConfig() async { final result = await httpManager.fetchResponseByGET( '/ping/domain', jsonTransformation: (json) => DomainSourceModel.fromJson(json), ); // 请求/解析失败时 result.data 为 null,返回可空类型, // 避免把 null 强转成非空 DomainSourceModel 触发 type 'Null' is not a subtype 崩溃 return result.isSuccess ? result.data as DomainSourceModel? : null; } /// 刷新用户分层弹窗配置(paymentStatusPopup / paymentGuide),[keys] 指定刷新分块,以后新增本地自己加 /// 返回 paymentPopup 分块(status / cardId / config 图片配置),写回 Config 由调用方处理; /// paymentGuide 分块直接写进 [GuideManager],不经调用方 static Future refreshPayPopup({List? keys}) async { final result = await httpManager.fetchResponseByGET( '/ping/domain/refresh', param: {'keys': keys}, jsonTransformation: (json) { GuideManager().update(json['paymentGuide']); //付费引导开关(登录/退登/开通会员后分层会变) // 容错:后端未返回有效 paymentPopup(null/非对象/空对象)时返回 null,调用方据此不替换本地状态 final popup = json['paymentPopup']; if (popup is! Map || popup.isEmpty) return null; return PayTierModel.fromJson(json['paymentPopup']); }, ); return result.isSuccess ? result.data as PayTierModel? : null; } /// 首页内容更新红点标记 static Future fetchUpdateMarkers() async { final result = await httpManager.fetchResponseByGET( '/content/update-markers', jsonTransformation: (json) => HomeUpdateMarkersResp.fromJson(json), ); return result.isSuccess ? result.data : null; } /// 活动结束或轮询时获取最新 banner 数据 static Future pingBanner(String id) async { final result = await httpManager.fetchResponseByGET( '/ping/banner/$id', jsonTransformation: (json) => BannerJumpEntity.fromJson(json), ); return result.isSuccess ? result.data as BannerJumpEntity? : null; } /// 按场景拉取 Banner 列表(如评论置顶 COMMENT_TOP) static Future> fetchBannerList( {required String scene}) async { final result = await httpManager.fetchResponseByGET( '/banner/list', param: {'scene': scene}, jsonTransformation: (json) { final list = json['list'] as List?; if (list == null) return []; final items = list .map((e) => CommentTopBannerModel.fromJson( e is Map ? Map.from(e) : null)) .toList(); items.sort((a, b) => (b.sort ?? 0).compareTo(a.sort ?? 0)); return items; }, ); //失败时 data 是没经过 jsonTransformation 的原始结构,硬 as 会抛,直接给空列表 if (!result.isSuccess) return []; return result.data as List? ?? []; } //获取模块数据 static Future getTagMarks() async { final result = await httpManager.fetchResponseByGET( '/modules/list', param: {}, jsonTransformation: (json) => HomePlateModel.fromJson(json), ); return result.isSuccess ? result.data : null; } //发起点赞 //SP:长视频 SHORT:短视频 COVER:图文帖子 PIC:图集帖子 SEED_LINK:种子/黄油帖子 TAG:标签 COMMENT:评论 video:动漫 image:漫画 text:小说 static Future sendLike(String? objID, String? type) async { final param = {'objID': objID, 'type': type}; final result = await httpManager.fetchResponseByPOST( '/thumbsUp', param: param, ); if (result.isSuccess) { eventBus.emit(CollectStatusModel( id: objID, isLiked: true, type: type, likeCountDelta: 1)); } return result.isSuccess; } //取消点赞 //SP:长视频 SHORT:短视频 COVER:图文帖子 PIC:图集帖子 SEED_LINK:种子/黄油帖子 TAG:标签 COMMENT:评论 video:动漫 image:漫画 text:小说 static Future cancelLike(String? objID, String? type, {List? objIDArr}) async { assert((type != null && type.isNotEmpty), 'cancelLike type 不能为空'); List ids = []; if (objIDArr?.isNotEmpty == true) { ids.addAll(objIDArr!); } else { ids.add(objID ?? ""); } final param = {'objIDs': ids, 'type': type}; final result = await httpManager.fetchResponseByPOST( '/thumbsDown', param: param, ); if (result.isSuccess) { eventBus.emit(CollectStatusModel( id: objID, isLiked: false, type: type, likeCountDelta: -1)); } return result.isSuccess; } /// 获取我关注用户发的视频 /// type 为0 获取用户所有动态, 1为获取用户全部视频 static Future fetchFollowDynamics( {int page = 1, int size = 20, int? uid, int? type, String? newsType}) async { final param = { 'pageSize': size, 'pageNumber': page, 'uid': uid, 'type': type, 'newsType': newsType }; param.removeWhere((k, v) => v == null); final result = await httpManager.fetchResponseByGET('/follow/dynamics/list', param: param, jsonTransformation: (json) => VideoListResp.fromJson(json)); return result.isSuccess ? result.data : null; } //获取关注列表 static Future?> getFollowUsers({ required int pageNumber, required int pageSize, int? uid, int? followUserType, }) async { final param = { 'pageNumber': pageNumber, 'pageSize': pageSize, 'uid': uid, 'type': followUserType, }; param.removeWhere((k, v) => v == null); final result = await httpManager.fetchResponseByGET('/follow/list', param: param, jsonTransformation: (json) { return ListBaseModel.fromJson(json); }); return result.isSuccess ? result.data : null; } //获取金主广告列表 static Future happyList() async { final result = await httpManager.fetchResponseByGET( '/recreation/list', param: {}, jsonTransformation: (json) => HappyModel.fromJson(json), ); return result.isSuccess ? result.data : null; } static Future getTaskList() async { final result = await httpManager.fetchResponseByGET( '/task/list', param: {}, jsonTransformation: (json) => TaskCenterData.fromJson(json), ); return result.isSuccess ? result.data : null; } static Future doTask(String? taskId, int? type) async { final result = await httpManager.fetchResponseByPOST( '/task/do', param: {'taskId': taskId, 'type': type}, jsonTransformation: (json) => TaskCenterData.fromJson(json), ); return result.isSuccess; } //推荐视频列表 static Future getRecommendList({ required int pageNumber, required int pageSize, String? tagId, String? newsType, }) async { final param = { 'pageNumber': pageNumber, 'pageSize': pageSize, 'tagId': tagId, 'newsType': newsType, }; param.removeWhere((k, v) => v == null); final result = await httpManager.fetchResponseByGET('/vid/recommend/list', param: param, jsonTransformation: (json) { return VideoListResp.fromJson(json); }); return result.isSuccess ? result.data : null; } //广告点击统计 广告类型 0:应用 1:广告 static Future adsClick(int? type) async { final result = await httpManager.fetchResponseByPOST( '/ads/click/stat', param: {'type': type}, ); return result.isSuccess; } /// 获取付费引导弹窗配置 /// [scene] 场景,VIP 内容上新固定传 VIP_CONTENT_UPDATE static Future fetchPaymentGuide(String scene) async { final result = await httpManager.fetchResponseByGET( '/payment/guide', param: {'scene': scene}, jsonTransformation: (json) => GuidePushModel.fromJson(json), ); return result.isSuccess ? result.data : null; } /// 上报付费引导弹窗已展示(只在弹窗真的展示出来后调,目前只有 VIP 内容上新横幅会上报) /// [requestId] 客户端每次展示生成的 UUID,接口按它幂等——失败重试要用同一个 static Future reportPaymentGuideImpression({ String? configId, required String scene, String? contentVersion, required String requestId, }) async { final result = await httpManager.fetchResponseByPOST( '/payment/guide/impression', param: { 'configId': configId, 'scene': scene, 'contentVersion': contentVersion ?? '', 'requestId': requestId, }, ); return result.isSuccess; } }