diff --git a/assets/main/launcher.png b/assets/main/launcher.png new file mode 100644 index 0000000..30114e9 Binary files /dev/null and b/assets/main/launcher.png differ diff --git a/lib/common/api/api_request.dart b/lib/common/api/api_request.dart index 2e44200..f3d385a 100644 --- a/lib/common/api/api_request.dart +++ b/lib/common/api/api_request.dart @@ -39,17 +39,6 @@ class AppService { // 添加自定义拦截器 _dio.interceptors.add(NyNetworkIntercept()); - // 开发环境添加日志 - // if (!kReleaseMode) { - // _dio.interceptors.add(TalkerDioLogger( - // settings: TalkerDioLoggerSettings( - // printRequestHeaders: true, - // printRequestData: true, - // printResponseData: true, - // printResponseHeaders: false, - // ), - // )); - // } } /// 更新配置 @@ -279,7 +268,6 @@ class ApiRequest { throw Exception("retry failed (unreachable)"); } - // ============ 错误处理 ============ static HttpResult _handleError(DioException e) { final Response? resp = e.response; diff --git a/lib/common/api/api_string.dart b/lib/common/api/api_string.dart index 9259c15..06ab3b0 100644 --- a/lib/common/api/api_string.dart +++ b/lib/common/api/api_string.dart @@ -2,7 +2,7 @@ // https://api-glimzodf.glimzodf.com/glimzodf/ class ApiString { - static const String baseUrl = "https://api-glimzodf.glimzodf.com/"; + static const String baseUrl = "https://api-glimzodf.glimzodf.com/glimzodf"; static const String appName = 'Novyronst'; diff --git a/lib/common/api/ny_network_intercept.dart b/lib/common/api/ny_network_intercept.dart index 010275c..2d9c20e 100644 --- a/lib/common/api/ny_network_intercept.dart +++ b/lib/common/api/ny_network_intercept.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; -import 'package:logger/logger.dart'; +import 'package:novyronst/common/help/help_log.dart'; import 'package:novyronst/common/help/help_time.dart'; import 'package:novyronst/common/help/help_token.dart'; @@ -11,19 +11,18 @@ import '../help/help_encrypt.dart'; /// 网络请求拦截器 class NyNetworkIntercept extends Interceptor { - final bool enableLog = !kReleaseMode; - final Logger _logger = Logger(); + @override Future onRequest(RequestOptions options, RequestInterceptorHandler handler) async { - // 添加公共请求头 + await _addRequestHeaders(options); // 打印请求日志 - _logInfo("🔶 REQUEST [${options.method.toUpperCase()}] ${options.uri}"); - _logDebug("Headers: ${options.headers}"); + HelpLog.print("🔶 REQUEST [${options.method.toUpperCase()}] ${options.uri}"); + HelpLog.print("Headers: ${options.headers}"); if (options.data != null) { - _logDebug("Payload: ${options.data}"); + HelpLog.print("Payload: ${options.data}"); } handler.next(options); @@ -31,7 +30,7 @@ class NyNetworkIntercept extends Interceptor { @override void onResponse(Response response, ResponseInterceptorHandler handler) { - _logInfo("🟢 RESPONSE [${response.statusCode}] ${response.requestOptions.uri}"); + HelpLog.print("🟢 RESPONSE [${response.statusCode}] ${response.requestOptions.uri}"); // _logDebug("Body: ${response.data}"); // 处理 401 / 402 Token 过期 @@ -56,7 +55,7 @@ class NyNetworkIntercept extends Interceptor { final deStr = HelpEncrypt.deStr(response.data); response.data = jsonDecode(deStr); } catch (e) { - _logError("解密失败: $e"); + HelpLog.print("解密失败: $e"); } } @@ -65,14 +64,13 @@ class NyNetworkIntercept extends Interceptor { @override void onError(DioException err, ErrorInterceptorHandler handler) { - _logError("🔴 Error: ${err.message}"); + HelpLog.print("🔴 Error: ${err.message}", tag: 'in onError'); handler.next(err); } // ============ 私有方法 ============ Future _addRequestHeaders(RequestOptions options) async { - // 开发模式添加 security: false if (!kReleaseMode) { options.headers['security'] = 'false'; } @@ -80,7 +78,6 @@ class NyNetworkIntercept extends Interceptor { // 注入 Token final tokenManager = HelpToken(); final token = tokenManager.get(); - // print('查看token: $token'); if (token.isNotEmpty) { options.headers['Authorization'] = 'Bearer $token'; } @@ -104,7 +101,6 @@ class NyNetworkIntercept extends Interceptor { 'device-gaid': '', }); - // 处理 prevToken(从请求体中提取) await _handleOldToken(options); } @@ -117,25 +113,11 @@ class NyNetworkIntercept extends Interceptor { options.headers['Authorization'] = prevToken.toString(); } } - } catch (_) { - // 非 JSON 请求跳过 - } + } catch (_) {} } - void _logInfo(String message) { - if (enableLog) _logger.i(message); - } - - void _logDebug(String message) { - if (enableLog) _logger.d('💡 $message'); - } - - void _logError(String message) { - if (enableLog) _logger.e(message); - } void _handleError(dynamic e, bool error) { - _logError("🔴 Error: $e"); - // 这里可以根据需要处理错误提示 + HelpLog.print("🔴 Error: $e", tag: 'in ---- _handleError'); } } \ No newline at end of file diff --git a/lib/common/api/user_request.dart b/lib/common/api/user_request.dart index 67df43e..8410f16 100644 --- a/lib/common/api/user_request.dart +++ b/lib/common/api/user_request.dart @@ -2,6 +2,7 @@ import 'package:novyronst/common/api/api_request.dart'; import 'package:novyronst/common/api/api_string.dart'; import 'package:novyronst/common/help/help_log.dart'; +import 'package:novyronst/common/help/help_token.dart'; import 'package:novyronst/common/model/novyronst_user.dart'; import 'package:novyronst/common/model/register_model.dart'; @@ -38,4 +39,65 @@ class UserRequest { return null; }); } + + static Future eventCreateHis({ + required String shortPlayId, + required String videoId + }) { + // {"short_play_id": shortPlayId, "video_id": videoId} + Map params = {"short_play_id": shortPlayId, "video_id": videoId}; + return ApiRequest.post(ApiStringUser.eventCreateHistory, data: params).then((value) { + HelpLog.print(value.data, tag: "eventCreateHis"); + }); + } + + static Future eventEnterApp() { + return ApiRequest.post(ApiStringUser.eventUserEnterApp).then((value) {}); + } + + static Future eventOnline({String? oldToken}) { + String token = HelpToken().get(); + if (token == '') return Future.value(false); + final body = {}; + if (oldToken != null) body['token'] = oldToken; + return ApiRequest.post(ApiStringUser.eventUserOnline, data: body).then((value) { + return value.isSuccess; + }); + } + + static Future eventOLeaveApp({String? oldToken}) { + String token = HelpToken().get(); + if (token == '') return Future.value(false); + final body = {}; + if (oldToken != null) body['token'] = oldToken; + return ApiRequest.post(ApiStringUser.eventUserLeaveApp, data: body).then((value) { + return value.isSuccess; + }); + } + +// 上报播放时长 + static Future eventPlaySeconds({ + required int shortPlayId, + required int videoId, + required int seconds, + }) { + return ApiRequest.post(ApiStringUser.eventPlaySeconds, data: { + "short_play_id": shortPlayId, + "video_id": videoId, + "play_seconds": seconds, + }).then((value) {}); + } + + // 上报观看时长 + static Future eventWatchTime({ + required int shortPlayId, + required int seconds, + }) { + return ApiRequest.post(ApiStringUser.eventWatchTime, data: { + "short_play_id": shortPlayId, + // 时间戳的毫秒数 + "request_id": DateTime.now().millisecondsSinceEpoch, + "duration": seconds, + }).then((value) {}); + } } \ No newline at end of file diff --git a/lib/common/api/video_request.dart b/lib/common/api/video_request.dart index e69de29..3ed62cd 100644 --- a/lib/common/api/video_request.dart +++ b/lib/common/api/video_request.dart @@ -0,0 +1,181 @@ + + +import 'package:novyronst/common/api/api_request.dart'; +import 'package:novyronst/common/api/api_string.dart'; +import 'package:novyronst/common/help/help_log.dart'; +import 'package:novyronst/common/model/ny_category_model.dart'; +import 'package:novyronst/common/model/ny_drama_model.dart'; +import 'package:novyronst/common/model/ny_home_model.dart'; + +import '../model/ny_detail_model.dart'; + +class VideoRequest { + static Future> getHomeData() { + return ApiRequest.get(ApiStringVideo.getHomeModules).then((value) { + if (value.isSuccess) { + List? list = value.data['data']['list']; + List homeList = []; + if (list != null) { + homeList = list.map((e) => NyHomeModel.fromJson(e)).toList(); + } + return homeList; + } + return []; + }); + } + + static Future> getCategoriesList() { + return ApiRequest.get(ApiStringVideo.getCategoriesList).then((value) { + // SkyLog.print('vvvvv: ${value.data}'); + if (!value.isSuccess) return []; + + Map data = value.data['data']; + List? list = data['list']; + + List categoryList = []; + if (list != null) { + // id 28 不显示,删除 + categoryList = list.map((e) => NyCategoryModel.fromJson(e)).toList(); + categoryList.removeWhere((element) => element.id == 28); + categoryList.removeWhere((element) => element.name.length >= 10); + } + return categoryList; + }); + } + + static Future> getCategoriesDetail({ + required int categoryId, + int page = 1, + int pageSize = 20, + }) { + return ApiRequest.fetchPage( + ApiStringVideo.getCategoriesDetail, + page: page, + pageSize: pageSize, + extraParams: {'category_id': categoryId}, + fromJson: (json) => NyDramaModel.fromJson(json), + ); + } + + // getSearchHots + static Future> getSearchHots() { + return ApiRequest.get(ApiStringVideo.getSearchHots).then((value) { + if (value.isSuccess) { + HelpLog.print('getSearchHots: ${value.data}'); + List list = parseDataForList(value.data); + return list.map((e) => NyDramaModel.fromJson(e)).toList(); + } + return []; + }); + } + + // search + static Future> search({required String keyword}) { + return ApiRequest.get(ApiStringVideo.getSearch, queryParameters: { + 'search': keyword, + }).then((value) { + if (value.isSuccess) { + HelpLog.print('getSearchHots: ${value.data}'); + List list = parseDataForList(value.data); + return list.map((e) => NyDramaModel.fromJson(e)).toList(); + } + return []; + }); + } + + //getCollections + static Future> getCollections({ + int page = 1, + int pageSize = 10, + }) { + Map params = _setPage(page: page, pageSize: pageSize); + return ApiRequest.get( + ApiStringVideo.getCollections, + queryParameters: params, + ).then((value) { + if (value.isSuccess) { + HelpLog.print('getCollections: ${value.data}'); + List list = parseDataForList(value.data); + return list.map((e) => NyDramaModel.fromJson(e)).toList(); + } + return []; + }); + } + + // getHistory + static Future> getHistory({ + int page = 1, + int pageSize = 10, + }) { + Map params = _setPage(page: page, pageSize: pageSize); + return ApiRequest.get( + ApiStringVideo.getHistories, + queryParameters: params, + ).then((value) { + if (value.isSuccess) { + HelpLog.print('getHistory: ${value.data}'); + List list = parseDataForList(value.data); + return list.map((e) => NyDramaModel.fromJson(e)).toList(); + } + return []; + }); + } + + // getVideoDetail + static Future getVideoDetail({ + required int shortPlayId, + required int shortPlayVideoId, + }) { + Map params = {}; + params['short_play_id'] = shortPlayId; + params['short_play_video_id'] = shortPlayVideoId; + return ApiRequest.get( + ApiStringVideo.getVideoDetail, + queryParameters: params, + ).then((value) { + if (value.isSuccess) { + HelpLog.print('getVideoDetail: ${value.data['data']}'); + return NyDetailModel.fromJson(value.data['data']); + } + return null; + }); + } + + // collect + static Future collect({ + required int shortPlayId, + required int videoId, + }) { + Map params = {}; + params['short_play_id'] = shortPlayId; + params['video_id'] = videoId; + return ApiRequest.post(ApiStringVideo.collect, data: params).then((value) { + HelpLog.print('collecttttt: ${value.data}'); + if (value.isSuccess) {} + return value.isSuccess; + }); + } + + // cancelCollect + static Future cancelCollect({required int shortPlayId}) { + Map params = {}; + params['short_play_id'] = shortPlayId; + return ApiRequest.post(ApiStringVideo.cancelCollect, data: params).then(( + value, + ) { + HelpLog.print('cancelCollectttt: ${value.data}'); + if (value.isSuccess) {} + return value.isSuccess; + }); + } + + static Map _setPage({int page = 1, int pageSize = 10}) { + return {'current_page': page, 'page_size': pageSize}; + } + + static List parseDataForList(Map data) { + Map map = data['data']; + List? listData = map['list']; + return listData ?? []; + } +} \ No newline at end of file diff --git a/lib/common/help/help_image.dart b/lib/common/help/help_image.dart index 78b034d..ba57710 100644 --- a/lib/common/help/help_image.dart +++ b/lib/common/help/help_image.dart @@ -15,6 +15,7 @@ class ConstImage { static const String btCollectSel = "assets/main/bt_collect_seled.png"; static const String btMineSel = "assets/main/bt_mine_seled.png"; static const String spaceImg = "assets/main/space_img.png"; + static const String launcher = "assets/main/launcher.png"; /// imgs static const String searchBg = "assets/imgs/search_bg.png"; diff --git a/lib/common/help/help_pages.dart b/lib/common/help/help_pages.dart new file mode 100644 index 0000000..6778065 --- /dev/null +++ b/lib/common/help/help_pages.dart @@ -0,0 +1,35 @@ + +import 'package:get/get.dart'; +import 'package:novyronst/pages/play/pages/laucher_page.dart'; + +class HelpRouters { + static const String launcher = '/launcher'; +} + +class HelpPages { + static const initial = HelpRouters.launcher; + + static final List routes = [ + routePage(name: HelpRouters.launcher, page: ()=> LauncherPage()) + ]; +} + +GetPage routePage({ + required String name, + required GetPageBuilder page, + Bindings? binding, + Transition transition = Transition.rightToLeft, + Duration transitionDuration = const Duration(milliseconds: 300), + CustomTransition? customTransition, + bool popGesture = true, // Allow iOS swipe-back gesture by default +}) { + return GetPage( + name: name, + page: page, + binding: binding, + transition: transition, + transitionDuration: transitionDuration, + customTransition: customTransition, + popGesture: popGesture, // Pass through to GetPage + ); +} \ No newline at end of file diff --git a/lib/common/help/help_token.dart b/lib/common/help/help_token.dart index 56315b5..cbb3458 100644 --- a/lib/common/help/help_token.dart +++ b/lib/common/help/help_token.dart @@ -65,7 +65,6 @@ class HelpToken { } } - // ============ 便捷属性 ============ /// 判断 Token 是否为空 bool get isEmpty => get().isEmpty; @@ -82,7 +81,6 @@ class HelpToken { return null; } - // ============ 用户信息扩展(原项目没有,但建议加上) ============ /// 保存用户信息 void saveUserInfo(Map userInfo) { @@ -107,12 +105,9 @@ class HelpToken { return null; } - // ============ 私有存储方法 ============ String? _getFromStorage(String key) { try { - // 使用 SharedPreferences 同步获取(但 SharedPreferences 是异步的) - // 为了保持与原项目一致的同步接口,这里使用异步转同步 // 但更好的方式是在初始化时预加载 return _getFromStorageSync(key); } catch (e) { @@ -121,13 +116,9 @@ class HelpToken { } } - // 同步读取(注意:SharedPreferences 本身是异步的,这里用同步方式需要谨慎) String? _getFromStorageSync(String key) { // 由于 SharedPreferences 是异步的,我们使用一个全局缓存 - // 实际项目中建议在 main 中调用 init() 预加载 try { - // 这里为了简化,直接返回 null,实际应该用异步方式 - // 建议使用下面的异步版本 return null; } catch (_) { return null; diff --git a/lib/common/model/ny_category_model.dart b/lib/common/model/ny_category_model.dart new file mode 100644 index 0000000..a12e508 --- /dev/null +++ b/lib/common/model/ny_category_model.dart @@ -0,0 +1,24 @@ + +import 'package:novyronst/common/model/parse_model.dart'; + +class NyCategoryModel { + final int id; + final String name; + + const NyCategoryModel({required this.id, required this.name}); + + factory NyCategoryModel.fromJson(Map json) { + return NyCategoryModel( + id: parseInt(json['id']), + name: parseString(json['name']), + ); + } + + Map toJson() { + return {'id': id, 'name': name}; + } + + NyCategoryModel copyWith({int? id, String? name}) { + return NyCategoryModel(id: id ?? this.id, name: name ?? this.name); + } +} diff --git a/lib/common/model/ny_detail_model.dart b/lib/common/model/ny_detail_model.dart new file mode 100644 index 0000000..3e8a1e4 --- /dev/null +++ b/lib/common/model/ny_detail_model.dart @@ -0,0 +1,113 @@ + + +import 'package:novyronst/common/model/ny_drama_model.dart'; +import 'package:novyronst/common/model/ny_episode_model.dart'; +import 'package:novyronst/common/model/parse_model.dart'; + +class NyDetailModel { + final NyDramaModel? videoInfo; + final NyDramaModel? shortPlayInfo; + final List episodeList; + final String? businessModel; + bool? isCollect; + final bool? showShareCoin; + final int? shareCoin; + final int? revolution; + final String? userLevel; + final int? jumpType; + final int? jumpShortPlayId; + final List? checkPoint; + + NyDetailModel({ + required this.videoInfo, + this.shortPlayInfo, + required this.episodeList, + this.businessModel, + this.isCollect, + this.showShareCoin, + this.shareCoin, + this.revolution, + this.userLevel, + this.jumpType, + this.jumpShortPlayId, + this.checkPoint, + }); + + factory NyDetailModel.fromJson(Map json) { + return NyDetailModel( + videoInfo: parseMap(json['video_info']) == null + ? null + : NyDramaModel.fromJson(parseMap(json['video_info'])!), + shortPlayInfo: parseMap(json['shortPlayInfo']) == null + ? null + : NyDramaModel.fromJson(parseMap(json['shortPlayInfo'])!), + episodeList: parseModelList(json['episodeList'], NyEpisodeModel.fromJson), + businessModel: json['business_model'] as String?, + isCollect: json['is_collect'] == null + ? null + : parseBool(json['is_collect']), + showShareCoin: json['show_share_coin'] == null + ? null + : parseBool(json['show_share_coin']), + shareCoin: json['share_coin'] == null + ? null + : parseInt(json['share_coin']), + revolution: json['revolution'] == null + ? null + : parseInt(json['revolution']), + userLevel: json['user_level'] as String?, + jumpType: json['jump_type'] == null ? null : parseInt(json['jump_type']), + jumpShortPlayId: json['jump_short_play_id'] == null + ? null + : parseInt(json['jump_short_play_id']), + checkPoint: parseIntList(json['check_point']), + ); + } + + Map toJson() { + return { + 'video_info': videoInfo?.toJson(), + 'shortPlayInfo': shortPlayInfo?.toJson(), + 'episodeList': episodeList.map((item) => item.toJson()).toList(), + 'business_model': businessModel, + 'is_collect': isCollect, + 'show_share_coin': showShareCoin, + 'share_coin': shareCoin, + 'revolution': revolution, + 'user_level': userLevel, + 'jump_type': jumpType, + 'jump_short_play_id': jumpShortPlayId, + 'check_point': checkPoint, + }; + } + + NyDetailModel copyWith({ + NyDramaModel? videoInfo, + NyDramaModel? shortPlayInfo, + List? episodeList, + String? businessModel, + bool? isCollect, + bool? showShareCoin, + int? shareCoin, + int? revolution, + String? userLevel, + int? jumpType, + int? jumpShortPlayId, + List? checkPoint, + }) { + return NyDetailModel( + videoInfo: videoInfo ?? this.videoInfo, + shortPlayInfo: shortPlayInfo ?? this.shortPlayInfo, + episodeList: episodeList ?? this.episodeList, + businessModel: businessModel ?? this.businessModel, + isCollect: isCollect ?? this.isCollect, + showShareCoin: showShareCoin ?? this.showShareCoin, + shareCoin: shareCoin ?? this.shareCoin, + revolution: revolution ?? this.revolution, + userLevel: userLevel ?? this.userLevel, + jumpType: jumpType ?? this.jumpType, + jumpShortPlayId: jumpShortPlayId ?? this.jumpShortPlayId, + checkPoint: checkPoint ?? this.checkPoint, + ); + } +} diff --git a/lib/common/model/ny_drama_model.dart b/lib/common/model/ny_drama_model.dart new file mode 100644 index 0000000..b1829f0 --- /dev/null +++ b/lib/common/model/ny_drama_model.dart @@ -0,0 +1,185 @@ + +import 'package:novyronst/common/model/parse_model.dart'; + +import 'ny_category_model.dart'; + +class NyDramaModel { + final int? id; + final int shortId; + int? shortPlayId; + final String name; + final String description; + final String imageUrl; + final String horizontallyImg; + int collectTotal; + final int watchTotal; + final int episodeTotal; + final String? playSeconds; + bool? isCollect; + final String? videoUrl; + final Map? videoInfo; + final List? category; + final List? categoryList; + final String tagType; + int? episode; + final int? process; + final int? buyType; + final int? searchClickTotal; + final int? shortPlayVideoId; + final int? currentEpisode; + int? historyTime; + + + NyDramaModel({ + this.id, + required this.shortId, + this.shortPlayId, + required this.name, + required this.description, + required this.imageUrl, + required this.horizontallyImg, + required this.collectTotal, + required this.watchTotal, + required this.episodeTotal, + this.playSeconds, + this.isCollect, + this.videoUrl, + this.videoInfo, + this.category, + this.categoryList, + required this.tagType, + this.episode, + this.process, + this.buyType, + this.searchClickTotal, + this.shortPlayVideoId, + this.currentEpisode, + this.historyTime, + }); + + factory NyDramaModel.fromJson(Map json) { + return NyDramaModel( + id: json['id'] == null ? null : parseInt(json['id']), + shortId: parseInt(json['short_id']), + shortPlayId: json['short_play_id'] == null + ? null + : parseInt(json['short_play_id']), + name: parseString(json['name']), + description: parseString(json['description']), + imageUrl: parseString(json['image_url']), + horizontallyImg: parseString(json['horizontally_img']), + collectTotal: parseInt(json['collect_total']), + watchTotal: parseInt(json['watch_total']), + episodeTotal: parseInt(json['episode_total']), + playSeconds: json['play_seconds'] as String?, + isCollect: json['is_collect'] == null + ? null + : parseBool(json['is_collect']), + videoUrl: json['video_url'] as String?, + videoInfo: parseMap(json['video_info']), + category: parseStringList(json['category']), + categoryList: json['categoryList'] == null + ? null + : parseModelList(json['categoryList'], NyCategoryModel.fromJson), + tagType: parseString(json['tag_type']), + episode: json['episode'] == null ? null : parseInt(json['episode']), + process: json['process'] == null ? null : parseInt(json['process']), + buyType: json['buy_type'] == null ? null : parseInt(json['buy_type']), + searchClickTotal: json['search_click_total'] == null + ? null + : parseInt(json['search_click_total']), + shortPlayVideoId: json['short_play_video_id'] == null + ? null + : parseInt(json['short_play_video_id']), + currentEpisode: json['current_episode'] == null + ? null + : parseInt(json['current_episode']), + historyTime: json['history_time'] == null + ? null + : parseInt(json['history_time']), + ); + } + + Map toJson() { + return { + 'id': id, + 'short_id': shortId, + 'short_play_id': shortPlayId, + 'name': name, + 'description': description, + 'image_url': imageUrl, + 'horizontally_img': horizontallyImg, + 'collect_total': collectTotal, + 'watch_total': watchTotal, + 'episode_total': episodeTotal, + 'play_seconds': playSeconds, + 'is_collect': isCollect, + 'video_url': videoUrl, + 'video_info': videoInfo, + 'category': category, + 'categoryList': categoryList?.map((item) => item.toJson()).toList(), + 'tag_type': tagType, + 'episode': episode, + 'process': process, + 'buy_type': buyType, + 'search_click_total': searchClickTotal, + 'short_play_video_id': shortPlayVideoId, + 'current_episode': currentEpisode, + 'history_time': historyTime, + }; + } + + NyDramaModel copyWith({ + int? id, + int? shortId, + int? shortPlayId, + String? name, + String? description, + String? imageUrl, + String? horizontallyImg, + int? collectTotal, + int? watchTotal, + int? episodeTotal, + String? playSeconds, + bool? isCollect, + String? videoUrl, + Map? videoInfo, + List? category, + List? categoryList, + String? tagType, + int? episode, + int? process, + int? buyType, + int? searchClickTotal, + int? shortPlayVideoId, + int? currentEpisode, + int? historyTime, + }) { + return NyDramaModel( + id: id ?? this.id, + shortId: shortId ?? this.shortId, + shortPlayId: shortPlayId ?? this.shortPlayId, + name: name ?? this.name, + description: description ?? this.description, + imageUrl: imageUrl ?? this.imageUrl, + horizontallyImg: horizontallyImg ?? this.horizontallyImg, + collectTotal: collectTotal ?? this.collectTotal, + watchTotal: watchTotal ?? this.watchTotal, + episodeTotal: episodeTotal ?? this.episodeTotal, + playSeconds: playSeconds ?? this.playSeconds, + isCollect: isCollect ?? this.isCollect, + videoUrl: videoUrl ?? this.videoUrl, + videoInfo: videoInfo ?? this.videoInfo, + category: category ?? this.category, + categoryList: categoryList ?? this.categoryList, + tagType: tagType ?? this.tagType, + episode: episode ?? this.episode, + process: process ?? this.process, + buyType: buyType ?? this.buyType, + searchClickTotal: searchClickTotal ?? this.searchClickTotal, + shortPlayVideoId: shortPlayVideoId ?? this.shortPlayVideoId, + currentEpisode: currentEpisode ?? this.currentEpisode, + historyTime: historyTime ?? this.historyTime, + ); + } +} diff --git a/lib/common/model/ny_episode_model.dart b/lib/common/model/ny_episode_model.dart new file mode 100644 index 0000000..c7dcab7 --- /dev/null +++ b/lib/common/model/ny_episode_model.dart @@ -0,0 +1,93 @@ + +import 'package:novyronst/common/model/parse_model.dart'; + +class NyEpisodeModel { + final int id; + final int shortId; + final int shortPlayId; + final int shortPlayVideoId; + final int episode; + final String videoUrl; + final int? promiseViewAd; + final int iaaPopUp; + bool isLock; + String playSeconds; + int? viewAdCount; + + NyEpisodeModel({ + required this.id, + required this.shortId, + required this.shortPlayId, + required this.shortPlayVideoId, + required this.episode, + required this.videoUrl, + required this.playSeconds, + required this.isLock, + this.promiseViewAd, + required this.iaaPopUp, + required this.viewAdCount, + }); + + factory NyEpisodeModel.fromJson(Map json) { + return NyEpisodeModel( + id: parseInt(json['id']), + shortId: parseInt(json['short_id']), + shortPlayId: parseInt(json['short_play_id']), + shortPlayVideoId: parseInt(json['short_play_video_id']), + episode: parseInt(json['episode']), + videoUrl: parseString(json['video_url']), + playSeconds: parseString(json['play_seconds']), + isLock: parseBool(json['is_lock']), + promiseViewAd: json['promise_view_ad'] == null + ? null + : parseInt(json['promise_view_ad']), + iaaPopUp: parseInt(json['iaa_pop_up']), + viewAdCount: parseInt(json['view_ad_count']), + ); + } + + Map toJson() { + return { + 'id': id, + 'short_id': shortId, + 'short_play_id': shortPlayId, + 'short_play_video_id': shortPlayVideoId, + 'episode': episode, + 'video_url': videoUrl, + 'promise_view_ad': promiseViewAd, + 'iaa_pop_up': iaaPopUp, + 'is_lock': isLock, + 'play_seconds': playSeconds, + 'view_ad_count': viewAdCount, + }; + } + + NyEpisodeModel copyWith({ + int? id, + int? shortId, + int? shortPlayId, + int? shortPlayVideoId, + int? episode, + String? videoUrl, + bool? isLock, + String? playSeconds, + String? durationSeconds, + int? promiseViewAd, + int? viewAdCount, + int? iaaPopUp, + }) { + return NyEpisodeModel( + id: id ?? this.id, + shortId: shortId ?? this.shortId, + shortPlayId: shortPlayId ?? this.shortPlayId, + shortPlayVideoId: shortPlayVideoId ?? this.shortPlayVideoId, + episode: episode ?? this.episode, + videoUrl: videoUrl ?? this.videoUrl, + isLock: isLock ?? this.isLock, + playSeconds: playSeconds ?? this.playSeconds, + promiseViewAd: promiseViewAd ?? this.promiseViewAd, + viewAdCount: viewAdCount ?? this.viewAdCount, + iaaPopUp: iaaPopUp ?? this.iaaPopUp, + ); + } +} diff --git a/lib/common/model/ny_home_model.dart b/lib/common/model/ny_home_model.dart new file mode 100644 index 0000000..05d8e51 --- /dev/null +++ b/lib/common/model/ny_home_model.dart @@ -0,0 +1,39 @@ + +import 'ny_drama_model.dart'; + +class NyHomeModel { + final String? moduleKey; + final List dataList; + + const NyHomeModel({required this.moduleKey, required this.dataList}); + + factory NyHomeModel.fromJson(Map json) { + + final data = json['data']; + List videos = []; + + if (data is Map) { + final list = data['list']; + if (list is List) { + videos = list.map((e) => NyDramaModel.fromJson(e)).toList(); + } + } else if (data is List) { + videos = data.map((e) => NyDramaModel.fromJson(e)).toList(); + } + return NyHomeModel( + moduleKey: json['module_key'] as String?, + dataList: videos, + ); + } + + Map toJson() { + return {'module_key': moduleKey, 'dataList': dataList}; + } + + NyHomeModel copyWith({String? moduleKey, dynamic data}) { + return NyHomeModel( + moduleKey: moduleKey ?? this.moduleKey, + dataList: data ?? dataList, + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index db10f0a..b4676a4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,18 +3,26 @@ import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:novyronst/common/help/help_token.dart'; import 'package:novyronst/root/lib_export.dart'; import 'package:novyronst/root/root_page.dart'; +import 'package:novyronst/tools/util/ny_device_info.dart'; -void main() { +import 'common/help/help_pages.dart'; + +void main() async { WidgetsFlutterBinding.ensureInitialized(); - - + await initManage(); runApp(const RootApp()); } +Future initManage() async { + + await NyDeviceInfo.init(); + await HelpToken().init(); +} class RootApp extends StatefulWidget { @@ -50,12 +58,11 @@ class _RootAppState extends State with WidgetsBindingObserver { designSize: Size(375, 812), child: GetMaterialApp( debugShowCheckedModeBanner: false, - // translations: AppLanguage(), locale: widget.locale ?? Get.deviceLocale, fallbackLocale: const Locale('en'), initialBinding: AppBindings(), - // initialRoute: SkyPages.initial, - // getPages: SkyPages.routes, + initialRoute: HelpRouters.launcher, + getPages: HelpPages.routes, theme: ThemeData( colorScheme: ColorScheme.fromSeed( seedColor: ConstColor.themeColor, @@ -75,7 +82,6 @@ class _RootAppState extends State with WidgetsBindingObserver { ); }, ), - home: widget.home ?? RootPage(), onInit: () {}, ), ) diff --git a/lib/pages/first/pages/first_page.dart b/lib/pages/first/pages/first_page.dart index 16b0847..67bf623 100644 --- a/lib/pages/first/pages/first_page.dart +++ b/lib/pages/first/pages/first_page.dart @@ -1,7 +1,13 @@ +import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; +import 'package:novyronst/common/api/video_request.dart'; import 'package:novyronst/common/help/app_nav.dart'; +import 'package:novyronst/common/model/ny_category_model.dart'; +import 'package:novyronst/common/model/ny_drama_model.dart'; +import 'package:novyronst/common/model/ny_home_model.dart'; import 'package:novyronst/pages/first/pages/search_page.dart'; import 'package:novyronst/pages/first/widgets/home_first_view.dart'; +import 'package:novyronst/pages/first/widgets/home_rank_widget.dart'; import 'package:novyronst/pages/first/widgets/home_remaining_sections.dart'; import 'package:novyronst/pages/first/widgets/search_view.dart'; import 'package:novyronst/root/lib_export.dart'; @@ -18,6 +24,41 @@ class FirstPage extends StatefulWidget { } class _RootPageState extends State { + + List _categories = []; + List _homeDatas = []; + final EasyRefreshController _refreshController = EasyRefreshController( + controlFinishRefresh: true, + ); + + @override + void initState() { + super.initState(); + + _getCategoryData(); + _getAllData(); + } + + void _getAllData() { + VideoRequest.getHomeData().then((value) { + setState(() { + _homeDatas = value; + }); + + for (NyHomeModel element in value) { + print('ele len===: ${element.moduleKey} : ${element.dataList.length}'); + } + }); + } + + void _getCategoryData() { + VideoRequest.getCategoriesList().then((value) { + setState(() { + _categories = value; + }); + }); + } + @override Widget build(BuildContext context) { return AppBgPage( @@ -34,11 +75,17 @@ class _RootPageState extends State { slivers: [ SliverToBoxAdapter(child: HomeFirstView()), SliverPadding( - padding: const EdgeInsets.only(left: 16, right: 10, top: 16), + padding: const EdgeInsets.only(left: 16, right: 10, top: 16, bottom: 8), sliver: SliverToBoxAdapter( child: HelpImage.asset(ConstImage.homeRank), ) ), + SliverPadding( + padding: const EdgeInsetsGeometry.symmetric(horizontal: 16), + sliver: SliverToBoxAdapter( + child: HomeRankWidget(), + ), + ), const SliverToBoxAdapter(child: HomeRemainingSections()), ], ), diff --git a/lib/pages/first/widgets/home_first_view.dart b/lib/pages/first/widgets/home_first_view.dart index f3b3e4d..5149a75 100644 --- a/lib/pages/first/widgets/home_first_view.dart +++ b/lib/pages/first/widgets/home_first_view.dart @@ -84,7 +84,7 @@ class _HomeFirstViewState extends State { ); } - _buildVideoItem() { + Widget _buildVideoItem() { return Padding( padding: const EdgeInsets.all(8), child: Column( diff --git a/lib/pages/first/widgets/home_rank_widget.dart b/lib/pages/first/widgets/home_rank_widget.dart new file mode 100644 index 0000000..b646277 --- /dev/null +++ b/lib/pages/first/widgets/home_rank_widget.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:novyronst/common/const/const_string.dart'; +import 'package:novyronst/tools/widgets/novy_com_widget.dart'; + +import '../../../tools/util/app_screen.dart'; +import '../../../tools/widgets/novy_button_bg.dart'; +import '../../widgets/cut_corner_clipper.dart'; +import '../../widgets/ny_tag_widget.dart'; + +class HomeRankWidget extends StatelessWidget { + + const HomeRankWidget({super.key}); + + @override + Widget build(BuildContext context) { + return CutCornerClipper( + width: AppScreen.screenWidth - 32, + cutCorner: CutCorner.bottomLeft, + cutSize: 40, + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + children: [ + _buildRankList(), + const SizedBox(height: 5), + Row( + children: [ + SizedBox(width: 20.w), + NovyButtonBg(text: 'Keep Watching', width: 308.w,) + ], + ) + ], + ), + ), + ); + } + + Row _buildRankList() { + return Row( + children: [ + _firstVideoView(), + const SizedBox(width: 8), + _otherVideoView(), + ], + ); + } + + Widget _firstVideoView() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 160.w, height: 240.w, + decoration: BoxDecoration( + color: Colors.red, + ) + ), + const SizedBox(height: 10), + NovyText('Star of the ocean', fontSize: 15, + color: Colors.black, + fontFamily: ConstFont.montMedium, + ), + const SizedBox(height: 5), + NyTagWidget(text: 'Safiray'), + const SizedBox(height: 8), + ], + ); + } + + Widget _otherVideoView() { + return Column( + children: List.generate(3, (index) { + return Container( + margin: const EdgeInsets.only(bottom: 8), + width: 160.w, height: 93.w, + decoration: BoxDecoration( + color: Colors.grey, + ) + ); + }) + ); + } +} \ No newline at end of file diff --git a/lib/pages/play/pages/laucher_page.dart b/lib/pages/play/pages/laucher_page.dart new file mode 100644 index 0000000..bef0876 --- /dev/null +++ b/lib/pages/play/pages/laucher_page.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:novyronst/common/api/user_request.dart'; +import 'package:novyronst/common/help/app_nav.dart'; +import 'package:novyronst/common/help/help_image.dart'; +import 'package:novyronst/common/help/help_token.dart'; +import 'package:novyronst/root/root_page.dart'; + +class LauncherPage extends StatefulWidget { + + const LauncherPage({super.key}); + + @override + State createState() { + return _LauncherPageState(); + } +} + +class _LauncherPageState extends State { + + @override + void initState() { + super.initState(); + + _userRegister(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: HelpImage.asset(ConstImage.launcher, fit: BoxFit.cover), + ); + } + + void _userRegister() async { + // 先拿token没有的话去注册 + final tm = HelpToken(); + String token = tm.get(); + if (token.isNotEmpty) { + // 成功后去到主页面 + Future.delayed(const Duration(seconds: 1), () { + AppNav.off(RootPage()); + }); + return; + } + + final res = await UserRequest.register(); + if (res != null) { + tm.save(res.token); + AppNav.off(RootPage()); + } + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 50a9a88..5a0343a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -89,6 +89,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" cupertino_icons: dependency: "direct main" description: @@ -129,6 +137,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + easy_refresh: + dependency: "direct main" + description: + name: easy_refresh + sha256: "513a5dc82c044f8a9c9a3d600b3d5d3256070575bfd8761940533d8e209ba79b" + url: "https://pub.dev" + source: hosted + version: "3.5.1" fake_async: dependency: transitive description: @@ -280,6 +296,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" http: dependency: transitive description: @@ -440,6 +464,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_drawing: + dependency: transitive + description: + name: path_drawing + sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: transitive description: @@ -725,6 +765,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + video_player: + dependency: "direct main" + description: + name: video_player + sha256: "48a7bdaa38a3d50ec10c78627abdbfad863fdf6f0d6e08c7c3c040cfd80ae36f" + url: "https://pub.dev" + source: hosted + version: "2.11.1" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: "877a6c7ba772456077d7bfd71314629b3fe2b73733ce503fc77c3314d43a0ca0" + url: "https://pub.dev" + source: hosted + version: "2.9.5" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: "76097729ef0c976937945afa53f1ca3afa9b50c9a95909ba347bcf93270466fd" + url: "https://pub.dev" + source: hosted + version: "2.10.0" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + sha256: e4ae5bc934b528e5b95c5e47be2812860186260cd3eed3ac62f5ed380fdd1613 + url: "https://pub.dev" + source: hosted + version: "6.8.0" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb" + url: "https://pub.dev" + source: hosted + version: "2.4.0" vm_service: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 95aa29e..c7c3ce9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,6 +31,9 @@ dependencies: android_id: ^0.5.1 logger: ^2.5.0 + video_player: ^2.10.0 + easy_refresh: ^3.4.0 + dev_dependencies: