diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 52f0820..3e051f5 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -256,6 +342,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + ED357041BDF6B3C4EED6BE91 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -369,6 +477,7 @@ DEVELOPMENT_TEAM = 2KBA4QW6M2; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 18.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -383,6 +492,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 0695C2418C491EC90FD98053 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -400,6 +510,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B906E66169FF427012694455 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -415,6 +526,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 9785CFD2D21F8A504CAC82C3 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -549,6 +661,7 @@ DEVELOPMENT_TEAM = 2KBA4QW6M2; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 18.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -567,11 +680,13 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + "ASSETCATALOG_COMPILER_APPICON_NAME[sdk=iphoneos*]" = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 2KBA4QW6M2; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 18.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fa..9b6d51f 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +1,122 @@ { "images" : [ { - "size" : "20x20", + "filename" : "app_logo2 14.png", "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "20x20" }, { - "size" : "20x20", + "filename" : "app_logo2 9.png", "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" + "scale" : "3x", + "size" : "20x20" }, { - "size" : "29x29", + "filename" : "app_logo2 16.png", "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" + "scale" : "1x", + "size" : "29x29" }, { - "size" : "29x29", + "filename" : "app_logo2 11.png", "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "29x29" }, { - "size" : "29x29", + "filename" : "app_logo2 5.png", "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" + "scale" : "3x", + "size" : "29x29" }, { - "size" : "40x40", + "filename" : "app_logo2 6.png", "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "40x40" }, { - "size" : "40x40", + "filename" : "app_logo2 3.png", "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" + "scale" : "3x", + "size" : "40x40" }, { - "size" : "60x60", + "filename" : "app_logo2 4.png", "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "60x60" }, { - "size" : "60x60", + "filename" : "app_logo2.png", "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" + "scale" : "3x", + "size" : "60x60" }, { - "size" : "20x20", + "filename" : "app_logo2 17.png", "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" + "scale" : "1x", + "size" : "20x20" }, { - "size" : "20x20", + "filename" : "app_logo2 13.png", "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "20x20" }, { - "size" : "29x29", + "filename" : "app_logo2 15.png", "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" + "scale" : "1x", + "size" : "29x29" }, { - "size" : "29x29", + "filename" : "app_logo2 10.png", "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "29x29" }, { - "size" : "40x40", + "filename" : "app_logo2 12.png", "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" + "scale" : "1x", + "size" : "40x40" }, { - "size" : "40x40", + "filename" : "app_logo2 7.png", "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "40x40" }, { - "size" : "76x76", + "filename" : "app_logo2 8.png", "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" + "scale" : "1x", + "size" : "76x76" }, { - "size" : "76x76", + "filename" : "app_logo2 2.png", "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "76x76" }, { - "size" : "83.5x83.5", + "filename" : "app_logo2 1.png", "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "83.5x83.5" }, { - "size" : "1024x1024", + "filename" : "applogo.png", "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" + "scale" : "1x", + "size" : "1024x1024" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } } diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 7353c41..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 797d452..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 6ed2d93..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cd7b00..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index fe73094..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 321773c..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 797d452..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 502f463..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 0ec3034..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 0ec3034..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index e9f5fea..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 84ac32a..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 8953cba..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 0467bf1..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 1.png new file mode 100644 index 0000000..35c2edc Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 1.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 10.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 10.png new file mode 100644 index 0000000..b1d6298 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 10.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 11.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 11.png new file mode 100644 index 0000000..b1d6298 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 11.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 12.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 12.png new file mode 100644 index 0000000..e0ee1c5 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 12.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 13.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 13.png new file mode 100644 index 0000000..e0ee1c5 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 13.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 14.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 14.png new file mode 100644 index 0000000..e0ee1c5 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 14.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 15.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 15.png new file mode 100644 index 0000000..0899b80 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 15.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 16.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 16.png new file mode 100644 index 0000000..0899b80 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 16.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 17.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 17.png new file mode 100644 index 0000000..3e681e1 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 17.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 2.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 2.png new file mode 100644 index 0000000..2f6f7be Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 2.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 3.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 3.png new file mode 100644 index 0000000..3c39e5b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 3.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 4.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 4.png new file mode 100644 index 0000000..3c39e5b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 4.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 5.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 5.png new file mode 100644 index 0000000..17a8d6e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 5.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 6.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 6.png new file mode 100644 index 0000000..69244d9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 6.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 7.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 7.png new file mode 100644 index 0000000..69244d9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 7.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 8.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 8.png new file mode 100644 index 0000000..7666c13 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 8.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 9.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 9.png new file mode 100644 index 0000000..0388469 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2 9.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2.png new file mode 100644 index 0000000..9e9fa60 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo2.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/applogo.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/applogo.png new file mode 100644 index 0000000..fa0bcee Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/applogo.png differ diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index b1e9470..ce161ba 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -7,7 +7,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Skywood + Glimzo CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -15,7 +15,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - skywood + Glimzo CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/global/client/event_client.dart b/lib/global/client/event_client.dart new file mode 100644 index 0000000..3648ffb --- /dev/null +++ b/lib/global/client/event_client.dart @@ -0,0 +1,68 @@ + +import 'package:skywood/global/request/api_const.dart'; +import 'package:skywood/global/request/app_request.dart'; +import 'package:skywood/global/tool/sky_log.dart'; +import 'package:skywood/utils/tools/token_manage.dart'; + +class EventClient { + 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 AppRequest.post(ApiString.eventCreateHistory, data: params).then((value) { + SkyLog.print(value.data, tag: "eventCreateHis"); + }); + } + + static Future eventEnterApp() { + return AppRequest.post(ApiString.eventUserEnterApp).then((value) {}); + } + + static Future eventOnline({String? oldToken}) { + String token = TokenManager().get(); + if (token == '') return Future.value(false); + final body = {}; + if (oldToken != null) body['token'] = oldToken; + return AppRequest.post(ApiString.eventUserOnline, data: body).then((value) { + return value.isSuccess; + }); + } + + static Future eventOLeaveApp({String? oldToken}) { + String token = TokenManager().get(); + if (token == '') return Future.value(false); + final body = {}; + if (oldToken != null) body['token'] = oldToken; + return AppRequest.post(ApiString.eventUserLeaveApp, data: body).then((value) { + return value.isSuccess; + }); + } + +// 上报播放时长 + static Future eventPlaySeconds({ + required int shortPlayId, + required int videoId, + required int seconds, + }) { + return AppRequest.post(ApiString.eventPlaySeconds, data: { + "short_play_id": shortPlayId, + "video_id": videoId, + "play_seconds": seconds, + }).then((value) {}); + } + + // 上报观看时长 + static Future eventWatchTime({ + required int shortPlayId, + required int seconds, + }) { + return AppRequest.post(ApiString.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/global/request/api_const.dart b/lib/global/request/api_const.dart index ff3ca32..1cb8c02 100644 --- a/lib/global/request/api_const.dart +++ b/lib/global/request/api_const.dart @@ -1,7 +1,7 @@ final class ApiConst { ApiConst._(); - static const appName = 'skywood'; + static const appName = 'Glimzo'; static const int pageSize = 12; static const String apiLink = 'https://api-quickeltv.quickeltv.com/quickeltv'; @@ -75,7 +75,7 @@ class ApiStringPlay { static const String getWaterflowList = "/newShortPlay"; /// getSearchHots GET /search/hots 搜索热门列表 -// getSearch GET /search 关键词搜索,query: search +/// getSearch GET /search 关键词搜索,query: search ///==== collect POST /collect 收藏,body: short_play_id, video_id ///==== cancelCollect POST /cancelCollect 取消收藏,body: short_play_id ///==== getMyCollections GET /myCollections 我的收藏列表,分页 diff --git a/lib/main.dart b/lib/main.dart index 964189b..614bc7c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:skywood/global/client/event_client.dart'; import 'package:skywood/global/request/app_request.dart'; import 'package:skywood/global/tool/sky_routers.dart'; import 'package:skywood/main/main_root.dart'; @@ -28,12 +29,23 @@ Future initServices() async { await Get.putAsync(() async => UserController()); } -class ComApp extends StatelessWidget { +class ComApp extends StatefulWidget { const ComApp({super.key, required this.home, this.locale}); final Widget home; final Locale? locale; + @override + State createState() { + return _ComAppState(); + } +} + +class _ComAppState extends State with WidgetsBindingObserver { + + bool _appInForeground = true; // 跟踪应用是否在前台 + + @override Widget build(BuildContext context) { // Locale locale = await AppLanguage.getLocale(); @@ -42,7 +54,7 @@ class ComApp extends StatelessWidget { child: GetMaterialApp( debugShowCheckedModeBanner: false, translations: AppLanguage(), - locale: locale ?? Get.deviceLocale, + locale: widget.locale ?? Get.deviceLocale, fallbackLocale: const Locale('en'), initialBinding: AppBindings(), initialRoute: SkyPages.initial, @@ -70,6 +82,62 @@ class ComApp extends StatelessWidget { ), ); } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + // _startPeriodicOnlineReport(); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + + switch (state) { + case AppLifecycleState.inactive: + case AppLifecycleState.paused: + // 应用进入后台或不活跃状态 + if (_appInForeground) { + print('💛应用不活跃'); + _appInForeground = false; + _onAppPaused(); + } + break; + case AppLifecycleState.resumed: + // 应用回到前台 + if (!_appInForeground) { + print('💚应用活跃'); + _appInForeground = true; + _onAppResumed(); + } + break; + case AppLifecycleState.detached: + case AppLifecycleState.hidden: + break; + } + } + + // 应用进入后台时的处理 + void _onAppPaused() { + try { + EventClient.eventOLeaveApp(); + } catch (err) { print(err.toString()); } + } + + /// 应用回到前台时的处理 + void _onAppResumed() { + try { + EventClient.eventEnterApp(); + EventClient.eventOnline(); + } catch (err) { print(err.toString()); } + } } class AppBindings extends Bindings { diff --git a/lib/pages/home/players/page/drama_detail_page.dart b/lib/pages/home/players/page/drama_detail_page.dart index 7253e59..c45f76a 100644 --- a/lib/pages/home/players/page/drama_detail_page.dart +++ b/lib/pages/home/players/page/drama_detail_page.dart @@ -1,19 +1,15 @@ import 'package:flutter/material.dart'; import 'package:skywood/global/client/play_client.dart'; import 'package:skywood/main/lib_file.dart'; -import 'package:skywood/pages/home/players/widget/player_bottom_widget.dart'; import 'package:skywood/pages/home/players/widget/sky_player_view.dart'; import 'package:skywood/utils/models/drama/skywood_detail.dart'; import 'package:skywood/utils/models/drama/skywood_drama.dart'; -import 'package:skywood/utils/models/drama/skywood_home.dart'; +import 'package:skywood/utils/models/drama/skywood_episode.dart'; import 'package:skywood/utils/tools/app_toast.dart'; -import 'package:skywood/utils/tools/widgets/sky_app_bar.dart'; import 'package:skywood/utils/tools/widgets/sky_common_widget.dart'; class DramaDetailPage extends StatefulWidget { - const DramaDetailPage({super.key, - required this.dramaBean, - }); + const DramaDetailPage({super.key, required this.dramaBean}); final SkywoodDrama dramaBean; @@ -24,36 +20,49 @@ class DramaDetailPage extends StatefulWidget { } class _DramaDetailPageState extends State { - SkywoodDetail? _detailBean; + SkywoodEpisode? _selectedEpisode; @override void initState() { super.initState(); - _getDetailDrama(); + _getDetailDrama( + shortPlayId: widget.dramaBean.shortPlayId ?? 0, + shortPlayVideoId: widget.dramaBean.shortPlayVideoId ?? 0, + ); } - void _getDetailDrama() { - print('currentEpisode===${widget.dramaBean.currentEpisode}'); + void _getDetailDrama({ + required int shortPlayId, + required int shortPlayVideoId, + }) { AppToast.showLottieLoading(); PlayClient.getVideoDetail( - shortPlayId: widget.dramaBean.shortPlayId ?? 0, - shortPlayVideoId: widget.dramaBean.shortPlayVideoId ?? 0 + shortPlayId: shortPlayId, + shortPlayVideoId: shortPlayVideoId, ).then((value) { AppToast.dismiss(); + if (!mounted) return; setState(() { _detailBean = value; }); }); } + void _onSelectedEpisode(SkywoodEpisode episode) { + setState(() { + _selectedEpisode = episode; + }); + _getDetailDrama( + shortPlayId: episode.shortPlayId, + shortPlayVideoId: episode.shortPlayVideoId, + ); + } + @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.black, - body: _bodyWidget(), - ); + return Scaffold(backgroundColor: Colors.black, body: _bodyWidget()); } Widget _bodyWidget() { @@ -63,17 +72,29 @@ class _DramaDetailPageState extends State { if (_detailBean != null) Positioned( - bottom: 0, left: 0, right: 0, top: 0, + bottom: 0, + left: 0, + right: 0, + top: 0, child: SkyPlayerView( + key: ValueKey( + _selectedEpisode?.shortPlayVideoId ?? + _detailBean?.videoInfo?.shortPlayVideoId ?? + widget.dramaBean.shortPlayVideoId, + ), detailBean: _detailBean, dramaBean: widget.dramaBean, + currentEpisode: _selectedEpisode?.episode, + onSelectedEpisode: _onSelectedEpisode, ), ), Positioned( - top: AppScreen.statusBarHeight + 5, left: 0, right: 0, + top: AppScreen.statusBarHeight + 5, + left: 0, + right: 0, child: _headerWidget(), - ) + ), ], ); } @@ -88,14 +109,18 @@ class _DramaDetailPageState extends State { icon: HelpImg.asset(ConstImg.back, width: 32), onPressed: () => HelpNav.back(), ), - Expanded(child: SkyText(text: widget.dramaBean.name, color: Colors.white, fontSize: 16, - textAlign: TextAlign.center, - fontWeight: FontWeight.bold, - )), - SizedBox(width: 40,) + Expanded( + child: SkyText( + text: widget.dramaBean.name, + color: Colors.white, + fontSize: 16, + textAlign: TextAlign.center, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 40), ], ), ); } - -} \ No newline at end of file +} diff --git a/lib/pages/home/players/page/drama_esp_page.dart b/lib/pages/home/players/page/drama_esp_page.dart index 574dffc..17e39bb 100644 --- a/lib/pages/home/players/page/drama_esp_page.dart +++ b/lib/pages/home/players/page/drama_esp_page.dart @@ -6,7 +6,8 @@ import 'package:skywood/utils/models/drama/skywood_episode.dart'; import 'package:skywood/utils/tools/widgets/sky_common_widget.dart'; class DramaEspPage extends StatefulWidget { - const DramaEspPage({super.key, + const DramaEspPage({ + super.key, required this.detail, this.currentEpisode, this.onSelectedEpisode, @@ -14,7 +15,7 @@ class DramaEspPage extends StatefulWidget { final SkywoodDetail detail; final int? currentEpisode; - final Function(int)? onSelectedEpisode; + final ValueChanged? onSelectedEpisode; @override State createState() { @@ -184,10 +185,11 @@ class _DramaEspPageState extends State { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { + if (_selectedEpisode == episode.episode) return; setState(() { _selectedEpisode = episode.episode; }); - widget.onSelectedEpisode?.call(_selectedEpisode); + widget.onSelectedEpisode?.call(episode); }, child: Container( alignment: Alignment.center, diff --git a/lib/pages/home/players/widget/sky_player_view.dart b/lib/pages/home/players/widget/sky_player_view.dart index 3412ad9..990e088 100644 --- a/lib/pages/home/players/widget/sky_player_view.dart +++ b/lib/pages/home/players/widget/sky_player_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:skywood/global/client/event_client.dart'; import 'package:skywood/global/client/play_client.dart'; import 'package:skywood/main/lib_file.dart'; import 'package:skywood/pages/home/players/page/drama_esp_page.dart'; @@ -15,6 +16,7 @@ class SkyPlayerView extends StatefulWidget { final SkywoodDetail? detailBean; final SkywoodDrama dramaBean; final int? currentEpisode; + final ValueChanged? onSelectedEpisode; const SkyPlayerView({ super.key, @@ -23,6 +25,7 @@ class SkyPlayerView extends StatefulWidget { this.detailBean, required this.dramaBean, this.currentEpisode, + this.onSelectedEpisode, }); @override @@ -40,6 +43,8 @@ class _VideoPlayerWidgetState extends State { Duration _totalDuration = Duration.zero; bool _isLiked = false; SkywoodEpisode? _currentEpisode; + // 是否已经上报his + bool _isReportedHis = false; @override void initState() { @@ -47,14 +52,15 @@ class _VideoPlayerWidgetState extends State { _initializePlayer(); } - // @override - // void didUpdateWidget(SkyPlayerView oldWidget) { - // super.didUpdateWidget(oldWidget); - // if (oldWidget.videoUrl != widget.videoUrl) { - // _disposeController(); - // _initializePlayer(); - // } - // } + @override + void didUpdateWidget(SkyPlayerView oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.detailBean != widget.detailBean || + oldWidget.currentEpisode != widget.currentEpisode) { + _disposeController(); + _initializePlayer(); + } + } Future _initializePlayer() async { setState(() { @@ -66,18 +72,10 @@ class _VideoPlayerWidgetState extends State { _isLiked = widget.dramaBean.isCollect ?? false; }); - int _esp = widget.currentEpisode ?? 0; - String videoUrl = ''; - if (widget.detailBean != null) { - if (widget.detailBean!.episodeList.isNotEmpty) { - videoUrl = widget.detailBean!.episodeList[_esp].videoUrl; - _currentEpisode = widget.detailBean!.episodeList[_esp]; - } - } + _currentEpisode = _resolveCurrentEpisode(); + String videoUrl = _currentEpisode?.videoUrl ?? ''; - final controller = VideoPlayerController.networkUrl( - Uri.parse(videoUrl), - ); + final controller = VideoPlayerController.networkUrl(Uri.parse(videoUrl)); _controller = controller; _controllerCreated = true; controller.addListener(_handlePlayerValueChanged); @@ -104,6 +102,17 @@ class _VideoPlayerWidgetState extends State { void _handlePlayerValueChanged() { if (!mounted || !_controllerCreated) return; _syncPlayerValue(); + + final videoController = _controller; + final position = videoController.value.position; + final duration = videoController.value.duration; + if (_isPlaying && !_isReportedHis && position.inSeconds > 1) { + _isReportedHis = true; + EventClient.eventCreateHis( + shortPlayId: _currentEpisode!.shortPlayId.toString(), + videoId: _currentEpisode!.shortPlayVideoId.toString(), + ); + } } void _syncPlayerValue() { @@ -194,9 +203,7 @@ class _VideoPlayerWidgetState extends State { Widget _buildLoadingView() { return Container( color: Colors.black, - child: Center( - child: HelpImg.asset(ConstImg.loading, width: 110), - ), + child: Center(child: HelpImg.asset(ConstImg.loading, width: 110)), ); } @@ -223,17 +230,39 @@ class _VideoPlayerWidgetState extends State { } } + SkywoodEpisode? _resolveCurrentEpisode() { + final detail = widget.detailBean; + if (detail == null || detail.episodeList.isEmpty) return null; + + final int? episode = + widget.currentEpisode ?? + detail.videoInfo?.episode ?? + detail.videoInfo?.currentEpisode ?? + detail.shortPlayInfo?.episode ?? + detail.shortPlayInfo?.currentEpisode; + + if (episode != null && episode > 0) { + for (final item in detail.episodeList) { + if (item.episode == episode) return item; + } + } + + return detail.episodeList.first; + } + void _collectionDrama() { if (_currentEpisode == null) return; if (_isLiked) { - PlayClient.cancelCollect(shortPlayId: _currentEpisode!.shortPlayId).then((value) { + PlayClient.cancelCollect(shortPlayId: _currentEpisode!.shortPlayId).then(( + value, + ) { setState(() { _isLiked = value; }); }); } else { PlayClient.collect( - shortPlayId: _currentEpisode!.shortPlayId, + shortPlayId: _currentEpisode!.shortPlayId, videoId: _currentEpisode!.shortPlayVideoId, ).then((value) { setState(() { @@ -257,8 +286,9 @@ class _VideoPlayerWidgetState extends State { InkWell( onTap: () => _collectionDrama(), child: HelpImg.asset( - _isLiked ? ConstImg.liked : ConstImg.unlike, - width: 40, height: 40 + _isLiked ? ConstImg.liked : ConstImg.unlike, + width: 40, + height: 40, ), ), const SizedBox(height: 24), @@ -282,7 +312,7 @@ class _VideoPlayerWidgetState extends State { color: Colors.white, ), SkyText( - text: ' / EP.${detail.episodeList.length}', + text: ' / EP.$totalEpisode', fontSize: 13, color: Colors.white.withAlpha(126), ), @@ -293,9 +323,6 @@ class _VideoPlayerWidgetState extends State { ), ).addInkWell( onTap: () { - // HelpNav.showBottom( - // DramaEspPage(detail: detail, currentEpisode: currentEpisode), - // ); showModalBottomSheet( context: context, isScrollControlled: true, @@ -307,12 +334,8 @@ class _VideoPlayerWidgetState extends State { detail: detail, currentEpisode: currentEpisode, onSelectedEpisode: (episode) { - - if (widget.detailBean != null) { - if (widget.detailBean!.episodeList.isNotEmpty) { - _currentEpisode = widget.detailBean!.episodeList[episode]; - } - } + Navigator.pop(context); + widget.onSelectedEpisode?.call(episode); }, ), ); @@ -361,9 +384,7 @@ class _VideoPlayerWidgetState extends State { child: SliderTheme( data: SliderThemeData( trackHeight: 3, // ✅ 进度条高度 3 - thumbShape: _ImageThumbShape( - imagePath: ConstImg.playTag - ), + thumbShape: _ImageThumbShape(imagePath: ConstImg.playTag), overlayShape: const RoundSliderOverlayShape(overlayRadius: 3), activeTrackColor: Colors.white, // ✅ 已播放 = 白色 inactiveTrackColor: Colors.white.withAlpha(126), // ✅ 未播放 = 灰色 @@ -404,6 +425,10 @@ class _VideoPlayerWidgetState extends State { } int _getCurrentEpisode(SkywoodDetail detail) { + if (_currentEpisode?.episode != null && _currentEpisode!.episode > 0) { + return _currentEpisode!.episode; + } + final int? episode = detail.videoInfo?.episode ?? detail.videoInfo?.currentEpisode ?? @@ -419,18 +444,11 @@ class _VideoPlayerWidgetState extends State { } } - - - - class _ImageThumbShape extends SliderComponentShape { final String imagePath; - final double imageSize; + final double imageSize = 16; - const _ImageThumbShape({ - required this.imagePath, - this.imageSize = 16, - }); + const _ImageThumbShape({required this.imagePath}); @override Size getPreferredSize(bool isEnabled, bool isDiscrete) { @@ -439,19 +457,19 @@ class _ImageThumbShape extends SliderComponentShape { @override void paint( - PaintingContext context, - Offset center, { - required Animation activationAnimation, - required Animation enableAnimation, - required bool isDiscrete, - required TextPainter labelPainter, - required RenderBox parentBox, - required SliderThemeData sliderTheme, - required TextDirection textDirection, - required double value, - required double textScaleFactor, - required Size sizeWithOverflow, - }) { + PaintingContext context, + Offset center, { + required Animation activationAnimation, + required Animation enableAnimation, + required bool isDiscrete, + required TextPainter labelPainter, + required RenderBox parentBox, + required SliderThemeData sliderTheme, + required TextDirection textDirection, + required double value, + required double textScaleFactor, + required Size sizeWithOverflow, + }) { // 🔥 使用 Image 直接渲染图片 final imageWidget = Image.asset( imagePath, @@ -464,29 +482,34 @@ class _ImageThumbShape extends SliderComponentShape { final stream = image.resolve(ImageConfiguration()); // 添加监听器,但只在图片加载完成后绘制 - stream.addListener(ImageStreamListener((imageInfo, _) { - final rect = Rect.fromCenter( - center: center, - width: imageSize, - height: imageSize, - ); - context.canvas.drawImageRect( - imageInfo.image, - Rect.fromLTWH( - 0, - 0, - imageInfo.image.width.toDouble(), - imageInfo.image.height.toDouble(), - ), - rect, - Paint(), - ); - }, onError: (error, stackTrace) { - // 🔥 如果图片加载失败,绘制一个默认圆点 - final paint = Paint() - ..color = Colors.white - ..style = PaintingStyle.fill; - context.canvas.drawCircle(center, imageSize / 2, paint); - })); + stream.addListener( + ImageStreamListener( + (imageInfo, _) { + final rect = Rect.fromCenter( + center: center, + width: imageSize, + height: imageSize, + ); + context.canvas.drawImageRect( + imageInfo.image, + Rect.fromLTWH( + 0, + 0, + imageInfo.image.width.toDouble(), + imageInfo.image.height.toDouble(), + ), + rect, + Paint(), + ); + }, + onError: (error, stackTrace) { + // 🔥 如果图片加载失败,绘制一个默认圆点 + final paint = Paint() + ..color = Colors.white + ..style = PaintingStyle.fill; + context.canvas.drawCircle(center, imageSize / 2, paint); + }, + ), + ); } -} \ No newline at end of file +} diff --git a/lib/pages/like/like_page.dart b/lib/pages/like/like_page.dart index 5bffa5f..f5348a2 100644 --- a/lib/pages/like/like_page.dart +++ b/lib/pages/like/like_page.dart @@ -6,6 +6,7 @@ import 'package:skywood/pages/like/widget/like_header.dart'; import 'package:skywood/pages/widgets/common_bg_page.dart'; import 'package:skywood/pages/widgets/pixel_widgets.dart'; import 'package:skywood/utils/extend/app_keep_alive.dart'; +import 'package:skywood/utils/tools/app_sp.dart'; class LikePage extends StatefulWidget { const LikePage({super.key}); @@ -17,17 +18,21 @@ class LikePage extends StatefulWidget { } class _MainRootState extends State { - int _tabIndex = 0; - final _pageController = PageController(initialPage: 0); + PageController _pageController = PageController(initialPage: 0); + int _currentIndex = 0; + static const String _keyIndex = 'LIKE_PAGE_INDEX'; - final List _collectionTitles = const [ - 'Undercover Play', - "Don't Cross Me", - 'Two Worlds Apart', - 'Rekindled Scorn', - 'My Revenge is You', - "Mr. Gu's Sweet Weakness", - ]; + @override + void initState() { + super.initState(); + _loadInitIndex(); + + + } + + _loadInitIndex() async { + + } @override Widget build(BuildContext context) { @@ -35,7 +40,10 @@ class _MainRootState extends State { child: SafeArea( bottom: false, child: Padding( - padding: EdgeInsets.only(left: 15.w, right: 15.w, top: 20.h, bottom: 10.h+50.h), + padding: EdgeInsets.only(left: 15.w, right: 15.w, + top: AppScreen.isIos ? 0 : 20.h, + bottom: (AppScreen.isIos ? 30.h : 10.h)+50.h + ), child: Stack( children: [ HelpImg.asset(ConstImg.likeBg, width: AppScreen.screenWidth - 30.w, height: 700.h, @@ -48,8 +56,10 @@ class _MainRootState extends State { Padding( padding: const EdgeInsets.only(left: 10, top: 10), child: LikeHeader( + initIndex: _currentIndex, onSelectedIndex: (index) { _pageController.jumpToPage(index); + _currentIndex = index; }, ), ), @@ -58,8 +68,10 @@ class _MainRootState extends State { child: PageView( controller: _pageController, children: [ - AppKeepAlive(child: CollectionPage()), - AppKeepAlive(child: PlayLogPage()) + CollectionPage(), + PlayLogPage() + // AppKeepAlive(child: CollectionPage()), + // AppKeepAlive(child: PlayLogPage()) ], ), ) @@ -71,315 +83,5 @@ class _MainRootState extends State { )), ); } - - Widget _buildTabs() { - return Row( - children: [ - Expanded( - child: _LibraryTab( - title: 'My Collection', - selected: _tabIndex == 0, - onTap: () => setState(() => _tabIndex = 0), - ), - ), - SizedBox(width: 8.w), - Expanded( - child: _LibraryTab( - title: 'Play Log', - selected: _tabIndex == 1, - onTap: () => setState(() => _tabIndex = 1), - ), - ), - ], - ); - } - - Widget _buildCollection() { - return GridView.builder( - key: const ValueKey('collection'), - padding: EdgeInsets.only(top: 2.h, bottom: 120.h), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - mainAxisSpacing: 10.h, - crossAxisSpacing: 7.w, - childAspectRatio: 100 / 174, - ), - itemCount: _collectionTitles.length, - itemBuilder: (context, index) { - return _CollectionCard(title: _collectionTitles[index]); - }, - ); - } - - Widget _buildPlayLog() { - return ListView( - key: const ValueKey('play-log'), - padding: EdgeInsets.only(bottom: 120.h), - children: [ - _ContinueCard(), - SizedBox(height: 18.h), - Text( - 'Watch History', - style: TextStyle( - color: const Color(0xFF1C1E1F), - fontSize: 16.sp, - fontWeight: FontWeight.w700, - height: 1, - ), - ), - SizedBox(height: 10.h), - _HistoryItem(title: 'As A Mafia Boss, I Refuse To Be An Extra'), - SizedBox(height: 10.h), - _HistoryItem(title: 'Fatal Vengeance'), - SizedBox(height: 10.h), - _HistoryItem(title: "Don't Cross Me"), - ], - ); - } } -class _LibraryTab extends StatelessWidget { - const _LibraryTab({ - required this.title, - required this.selected, - required this.onTap, - }); - - final String title; - final bool selected; - final VoidCallback onTap; - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - height: 45.h, - alignment: Alignment.center, - decoration: BoxDecoration( - color: selected ? const Color(0xFF16ED1E) : const Color(0xFFF6F6F6), - border: Border.all( - color: selected ? CommonColor.black : const Color(0xFFD6D6D6), - width: 1.5.w, - ), - boxShadow: selected - ? const [ - BoxShadow(color: Color(0xFF1C1E1F), offset: Offset(2, 2)), - ] - : null, - ), - child: Text( - title, - style: TextStyle( - color: selected ? Colors.white : const Color(0xFFB2B2B2), - fontSize: 14.sp, - fontWeight: FontWeight.w900, - height: 1, - shadows: selected - ? const [Shadow(color: Color(0xFF1C1E1F), offset: Offset(1, 1))] - : null, - ), - ), - ), - ); - } -} - -class _CollectionCard extends StatelessWidget { - const _CollectionCard({required this.title}); - - final String title; - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.fromLTRB(4.w, 8.h, 4.w, 6.h), - decoration: BoxDecoration( - color: const Color(0xFFF4FFB6), - border: Border.all(color: const Color(0xFF1C1E1F), width: 1.w), - boxShadow: const [ - BoxShadow(color: Color(0xFF653CFA), offset: Offset(3, 3)), - ], - ), - child: Column( - children: [ - Row( - children: List.generate(4, (index) { - return Container( - width: 11.w, - height: 6.h, - margin: EdgeInsets.only(right: 5.w), - decoration: BoxDecoration( - color: index == 3 - ? const Color(0xFFEAEAEA) - : const Color(0xFF96FE9B), - border: Border.all( - color: const Color(0xFF1C1E1F), - width: 0.8.w, - ), - ), - ); - }), - ), - SizedBox(height: 8.h), - const Expanded(child: PosterImage()), - SizedBox(height: 8.h), - Text( - title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: const Color(0xFF1C1E1F), - fontSize: 13.sp, - fontWeight: FontWeight.w500, - height: 1, - ), - ), - ], - ), - ); - } -} - -class _ContinueCard extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Container( - height: 140.h, - padding: EdgeInsets.all(10.w), - decoration: BoxDecoration( - color: const Color(0xFFEAE6FF), - border: Border.all(color: const Color(0xFF1C1E1F), width: 1.w), - ), - child: Row( - children: [ - const PosterImage(width: 90, height: 120, borderRadius: 2), - SizedBox(width: 10.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Mogul And His Runaway Bride', - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: const Color(0xFF1B1926), - fontSize: 14.sp, - fontWeight: FontWeight.w600, - height: 1.25, - ), - ), - SizedBox(height: 18.h), - Text( - 'Chapter 10 / 28', - style: TextStyle( - color: CommonColor.primacyColor, - fontSize: 11.sp, - height: 1, - ), - ), - SizedBox(height: 6.h), - _ProgressLine(value: 0.46), - const Spacer(), - const PixelButton( - label: 'Continue Watch', - width: 145, - height: 29, - ), - ], - ), - ), - ], - ), - ); - } -} - -class _HistoryItem extends StatelessWidget { - const _HistoryItem({required this.title}); - - final String title; - - @override - Widget build(BuildContext context) { - return Container( - height: 100.h, - padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 6.h), - decoration: BoxDecoration( - color: const Color(0xFFEAE6FF), - border: Border.all(color: const Color(0xFF1C1E1F), width: 1.w), - ), - child: Row( - children: [ - const PosterImage(width: 66, height: 88, borderRadius: 2), - SizedBox(width: 10.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: CommonColor.black, - fontSize: 13.sp, - fontWeight: FontWeight.w600, - height: 1.2, - ), - ), - Text( - 'EP.40/85', - style: TextStyle( - color: CommonColor.primacyColor, - fontSize: 11.sp, - height: 1, - ), - ), - _ProgressLine(value: 0.46), - ], - ), - ), - ], - ), - ); - } -} - -class _ProgressLine extends StatelessWidget { - const _ProgressLine({required this.value}); - - final double value; - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Expanded( - child: Container( - height: 6.h, - decoration: BoxDecoration( - color: Colors.white.withValues(alpha: 0.7), - border: Border.all(color: const Color(0xFF1C1E1F), width: 0.5.w), - borderRadius: BorderRadius.circular(10.r), - ), - alignment: Alignment.centerLeft, - child: FractionallySizedBox( - widthFactor: value, - child: Container( - decoration: BoxDecoration( - color: const Color(0xFF00EE02), - borderRadius: BorderRadius.circular(10.r), - ), - ), - ), - ), - ), - SizedBox(width: 4.w), - Text('46%', style: TextStyle(fontSize: 10.sp, height: 1)), - ], - ); - } -} diff --git a/lib/pages/like/pages/collection_page.dart b/lib/pages/like/pages/collection_page.dart index 829b3ac..d9d83a8 100644 --- a/lib/pages/like/pages/collection_page.dart +++ b/lib/pages/like/pages/collection_page.dart @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; import 'package:skywood/global/client/play_client.dart'; import 'package:skywood/main/lib_file.dart'; import 'package:skywood/pages/home/players/page/drama_detail_page.dart'; +import 'package:skywood/pages/like/widget/no_data_view.dart'; import 'package:skywood/utils/models/drama/skywood_drama.dart'; +import 'package:skywood/utils/tools/app_toast.dart'; import 'package:skywood/utils/tools/widgets/sky_common_widget.dart'; class CollectionPage extends StatefulWidget { @@ -18,6 +20,7 @@ class CollectionPage extends StatefulWidget { class _CollectionPageState extends State { List _collectionList = []; + bool _isLoading = false; @override void initState() { @@ -26,7 +29,12 @@ class _CollectionPageState extends State { } void _getCollection() { + _isLoading = true; + AppToast.showLottieLoading(); PlayClient.getCollections().then((value) { + _isLoading = false; + AppToast.dismiss(); + if (!mounted) return; setState(() { _collectionList = value; }); @@ -35,7 +43,7 @@ class _CollectionPageState extends State { @override Widget build(BuildContext context) { - return GridView.builder( + return !_isLoading&&_collectionList.isEmpty ? NoDataView() : GridView.builder( padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 10.h), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, diff --git a/lib/pages/like/pages/play_log_page.dart b/lib/pages/like/pages/play_log_page.dart index 29d612e..15163d8 100644 --- a/lib/pages/like/pages/play_log_page.dart +++ b/lib/pages/like/pages/play_log_page.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; import 'package:skywood/global/client/play_client.dart'; import 'package:skywood/main/lib_file.dart'; +import 'package:skywood/pages/home/players/page/drama_detail_page.dart'; +import 'package:skywood/utils/models/drama/skywood_drama.dart'; import 'package:skywood/utils/tools/widgets/sky_common_widget.dart'; +import '../../../utils/tools/app_toast.dart'; +import '../widget/no_data_view.dart'; + class PlayLogPage extends StatefulWidget { const PlayLogPage({super.key}); @@ -15,6 +20,9 @@ class PlayLogPage extends StatefulWidget { class _CollectionPageState extends State { + List _historyList = []; + bool _isLoading = false; + @override void initState() { super.initState(); @@ -22,16 +30,25 @@ class _CollectionPageState extends State { } void _getHistory() { - PlayClient.getHistory().then((value) {}); + _isLoading = true; + AppToast.showLottieLoading(); + PlayClient.getHistory().then((value) { + _isLoading = false; + AppToast.dismiss(); + setState(() { + _historyList = value; + }); + }); } @override Widget build(BuildContext context) { - return ListView.separated( + return !_isLoading&&_historyList.isEmpty ? NoDataView() : ListView.separated( padding: const EdgeInsets.only(top: 20, left: 12, right: 12), - itemCount: 5, + itemCount: _historyList.length, itemBuilder: (context, index) { - return index == 0 ? _buildFirstItem() : _buildNormalItem(); + final item = _historyList[index]; + return index == 0 ? _buildFirstItem(item) : _buildNormalItem(item); }, separatorBuilder: (context, index) { return SizedBox(height: 5); @@ -39,25 +56,103 @@ class _CollectionPageState extends State { ); } - Widget _buildNormalItem() { + Widget _buildNormalItem(SkywoodDrama item) { return Stack( children: [ - HelpImg.asset(ConstImg.playlogBg, width: double.infinity, height: 90, fit: BoxFit.fill), - _ProgressLine(value: 0.2) + HelpImg.asset(ConstImg.playlogBg, width: double.infinity, height: 100, fit: BoxFit.fill), + Positioned( + left: 10, top: 5, right: 5, bottom: 5, + child: Row( + children: [ + HelpImg.network(item.imageUrl, width: 66, height: 88, fit: BoxFit.fill), + const SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 6), + Expanded(child: SizedBox( + width: 192.w, + child: SkyText(text: item.name, + fontSize: 14, + fontWeight: FontWeight.bold, + color: CommonColor.black, + maxLines: 2, + ), + )), + SkyText(text: 'EP.${item.currentEpisode} / ${item.episodeTotal}', + fontSize: 11, + color: CommonColor.primacyColor, + ), + const SizedBox(height: 5), + _ProgressLine(value: (item.currentEpisode ?? 1) / item.episodeTotal, width: 150,), + const SizedBox(height: 10), + ], + ) + ], + ), + ) + ], + ).addInkWell(onTap: () { + HelpNav.to(DramaDetailPage(dramaBean: item)); + }); + } + + Widget _buildFirstItem(SkywoodDrama item) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildFirstCard(item), + const SizedBox(height: 20), + if (_historyList.length > 1) + SkyText(text: 'Watch History', + color: CommonColor.black, + fontSize: 16, + fontWeight: FontWeight.bold, + ) ], ); } - Widget _buildFirstItem() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, + Widget _buildFirstCard(SkywoodDrama item) { + return Stack( children: [ - HelpImg.asset(ConstImg.playlogBg, width: double.infinity, height: 140, fit: BoxFit.fill), - const SizedBox(height: 20), - SkyText(text: 'Watch History', - color: CommonColor.black, - fontSize: 16, - fontWeight: FontWeight.bold, + HelpImg.asset(ConstImg.playlogBg, width: 297.w, height: 140, fit: BoxFit.fill), + Positioned( + left: 10, top: 5, right: 5, bottom: 5, + child: Row( + children: [ + HelpImg.network(item.imageUrl, width: 90, height: 120, fit: BoxFit.fill), + const SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 6), + Expanded(child: SizedBox( + width: 170.w, + child: SkyText(text: item.name, + fontSize: 14, + fontWeight: FontWeight.bold, + color: CommonColor.black, + maxLines: 2, + ), + )), + SkyText(text: 'Chapter ${item.currentEpisode} / ${item.episodeTotal}', + fontSize: 11, + color: CommonColor.primacyColor, + ), + const SizedBox(height: 5), + _ProgressLine(value: (item.currentEpisode ?? 1) / item.episodeTotal, width: 150,), + const SizedBox(height: 10), + HelpImg.asset(ConstImg.continueWatch, width: 144, height: 30).addInkWell( + onTap: () { + HelpNav.to(DramaDetailPage(dramaBean: item)); + } + ), + const SizedBox(height: 8), + ], + ) + ], + ), ) ], ); @@ -67,37 +162,44 @@ class _CollectionPageState extends State { class _ProgressLine extends StatelessWidget { - const _ProgressLine({required this.value}); + const _ProgressLine({ + required this.value, + this.width = 140, + }); final double value; + final double width; @override Widget build(BuildContext context) { - return Row( - children: [ - Expanded( - child: Container( - height: 6.h, - decoration: BoxDecoration( - color: Colors.white.withValues(alpha: 0.7), - border: Border.all(color: const Color(0xFF1C1E1F), width: 0.5.w), - borderRadius: BorderRadius.circular(10.r), - ), - alignment: Alignment.centerLeft, - child: FractionallySizedBox( - widthFactor: value, - child: Container( - decoration: BoxDecoration( - color: const Color(0xFF00EE02), - borderRadius: BorderRadius.circular(10.r), + return SizedBox( + width: width, + child: Row( + children: [ + Expanded( + child: Container( + height: 6.h, + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.7), + border: Border.all(color: const Color(0xFF1C1E1F), width: 0.5.w), + borderRadius: BorderRadius.circular(10.r), + ), + alignment: Alignment.centerLeft, + child: FractionallySizedBox( + widthFactor: value, + child: Container( + decoration: BoxDecoration( + color: const Color(0xFF00EE02), + borderRadius: BorderRadius.circular(10.r), + ), ), ), ), ), - ), - SizedBox(width: 4.w), - Text('${(value * 100.0).toInt()}%', style: TextStyle(fontSize: 10.sp, height: 1)), - ], + SizedBox(width: 4.w), + Text('${(value * 100.0).toInt()}%', style: TextStyle(fontSize: 10.sp, height: 1)), + ], + ), ); } } \ No newline at end of file diff --git a/lib/pages/like/widget/like_header.dart b/lib/pages/like/widget/like_header.dart index 43f4bb3..374e6d0 100644 --- a/lib/pages/like/widget/like_header.dart +++ b/lib/pages/like/widget/like_header.dart @@ -6,9 +6,11 @@ class LikeHeader extends StatefulWidget { const LikeHeader({super.key, required this.onSelectedIndex, + required this.initIndex, }); final Function(int) onSelectedIndex; + final int initIndex; @override State createState() { @@ -20,6 +22,18 @@ class _LikeHeaderState extends State { int _selectedIndex = 0; + @override + void initState() { + super.initState(); + + if (widget.initIndex != 0) { + if (!mounted) return; + setState(() { + _selectedIndex = widget.initIndex; + }); + } + } + @override Widget build(BuildContext context) { return SizedBox( diff --git a/lib/pages/like/widget/no_data_view.dart b/lib/pages/like/widget/no_data_view.dart new file mode 100644 index 0000000..b5e4a33 --- /dev/null +++ b/lib/pages/like/widget/no_data_view.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:skywood/main/lib_file.dart'; +import 'package:skywood/utils/tools/widgets/sky_common_widget.dart'; + +class NoDataView extends StatelessWidget { + + const NoDataView({super.key, + this.title = 'No Data', + // 'Nothing here yet.\nCome back later for more fun!', + // Something went wrong.\nPlease try again. + this.subtitle = 'Nothing here yet.\nCome back later for more fun!', + this.btnText = 'RETRY', + this.imgName, + this.onTap, + }); + + final String title; + final String subtitle; + final String btnText; + final String? imgName; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 100), + HelpImg.asset(ConstImg.nodataImg, width: 136), + const SizedBox(height: 14), + _customText(title), + const SizedBox(height: 10), + SkyText(text: subtitle, maxLines: 2, + fontSize: 14, + color: CommonColor.black, + textAlign: TextAlign.center, + ), + const SizedBox(height: 14), + + if (onTap != null) + InkWell( + onTap: onTap, + child: Stack( + children: [ + HelpImg.asset(imgName ?? ConstImg.btnBg, width: 140, height: 46, fit: BoxFit.fill,), + Positioned.fill( + child: Center( + child: SkyText(text: btnText, color: Colors.white), + ), + ) + ], + ) + ) + ], + ), + ); + } + + _customText(String text) { + return Text( + text, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Colors.white, // 内部字体白色 + fontStyle: FontStyle.italic, + fontFamily: 'Inter', + fontWeight: FontWeight.w600, + shadows: [ + Shadow( + color: Colors.black, // 描边颜色 + offset: Offset(1, 1), // 偏移量 + blurRadius: 0, // 不模糊,形成硬边描边 + ), + Shadow( + color: Colors.black, + offset: Offset(-1, -1), + blurRadius: 0, + ), + Shadow( + color: Colors.black, + offset: Offset(1, -1), + blurRadius: 0, + ), + Shadow( + color: Colors.black, + offset: Offset(-1, 1), + blurRadius: 0, + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/pages/mine/mine_page.dart b/lib/pages/mine/mine_page.dart index e43f2c6..3eb3116 100644 --- a/lib/pages/mine/mine_page.dart +++ b/lib/pages/mine/mine_page.dart @@ -4,6 +4,7 @@ import 'package:skywood/global/client/user_client.dart'; import 'package:skywood/global/request/api_const.dart'; import 'package:skywood/main/lib_file.dart'; import 'package:skywood/pages/mine/page/about_us_page.dart'; +import 'package:skywood/pages/mine/page/mine_collection_page.dart'; import 'package:skywood/pages/mine/page/sky_web_page.dart'; import 'package:skywood/pages/mine/widget/mine_section_view.dart'; import 'package:skywood/pages/widgets/pixel_widgets.dart'; @@ -28,6 +29,12 @@ class _MainRootState extends State { List _buildSections() { final menuData = [ + { + 'title': 'Collection', 'img': ConstImg.collection, + 'action': () { + HelpNav.to(MineCollectionPage()); + } + }, { 'title': 'Privacy Policy', 'img': ConstImg.minePp, 'action': () { @@ -168,10 +175,11 @@ class _MainRootState extends State { child: Column( children: [ HelpImg.asset(imgName, width: _w/2.0), - SkyText(text: title, fontSize: 9, color: Colors.white, + const SizedBox(height: 2), + SkyText(text: title, fontSize: 9.w, color: Colors.white, maxLines: 2, textAlign: TextAlign.center, - ), + ) ], ), ) @@ -181,70 +189,3 @@ class _MainRootState extends State { } -class _MenuTile extends StatelessWidget { - const _MenuTile({required this.item}); - - final _MenuItem item; - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.fromLTRB(4.w, 4.h, 4.w, 6.h), - decoration: BoxDecoration( - color: const Color(0xFF8D62F7), - border: Border.all(color: CommonColor.black, width: 1.w), - boxShadow: const [ - BoxShadow(color: Color(0xFF1C1E1F), offset: Offset(2, 2)), - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(item.icon, color: Colors.white, size: 25.w), - SizedBox(height: 5.h), - Text( - item.label, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: Colors.white, - fontSize: 8.sp, - fontWeight: FontWeight.w700, - height: 1, - ), - ), - ], - ), - ); - } -} - -class _DecorIcon extends StatelessWidget { - const _DecorIcon({required this.icon, required this.color}); - - final IconData icon; - final Color color; - - @override - Widget build(BuildContext context) { - return Container( - width: 50.w, - height: 50.w, - decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color: CommonColor.black, width: 1.w), - boxShadow: const [ - BoxShadow(color: Color(0xFF1C1E1F), offset: Offset(2, 2)), - ], - ), - child: Icon(icon, color: color, size: 32.w), - ); - } -} - -class _MenuItem { - const _MenuItem(this.label, this.icon); - - final String label; - final IconData icon; -} diff --git a/lib/pages/mine/page/about_us_page.dart b/lib/pages/mine/page/about_us_page.dart index 37898c9..ee7cfde 100644 --- a/lib/pages/mine/page/about_us_page.dart +++ b/lib/pages/mine/page/about_us_page.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:skywood/global/const/common_color.dart'; import 'package:skywood/global/request/api_const.dart'; +import 'package:skywood/main/lib_file.dart'; +import 'package:skywood/pages/mine/page/sky_web_page.dart'; import 'package:skywood/utils/tools/sky_device_info.dart'; import 'package:skywood/utils/tools/widgets/sky_app_bar.dart'; import 'package:skywood/utils/tools/widgets/sky_common_widget.dart'; @@ -14,14 +17,19 @@ class AboutUsPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: SkyAppBar( - title: 'About Us', + title: 'About', ), body: SizedBox( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - const SizedBox(height: 100), + const SizedBox(height: 50), + SizedBox( + width: 80, height: 80, + child: HelpImg.asset(ConstImg.appLogo), + ), + const SizedBox(height: 10), SkyText(text: ApiConst.appName, fontSize: 16, fontWeight: FontWeight.bold, @@ -33,20 +41,55 @@ class AboutUsPage extends StatelessWidget { color: Colors.grey, ), const SizedBox(height: 20), - Container( - height: 46, - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 4), - child: Row( - children: [ + _buildRowItem('Privacy Policy', () { + HelpNav.to(SkyWebPage(params: WebLinkParams( + title: 'Privacy Policy', + urlString: ApiConst.webPrivacy, + ))); + }), + + _buildRowItem('User Agreement', () { + HelpNav.to(SkyWebPage(params: WebLinkParams( + title: 'User Agreement', + urlString: ApiConst.webAgreement, + ))); + }), + + _buildRowItem('Visit Website', () async { + final encodedUrl = Uri.encodeFull(ApiConst.webIndex); + try { + final bool launched = await launchUrl( + Uri.parse(encodedUrl), + mode: LaunchMode.externalApplication, + ); + if (!launched) { + print('无法打开链接: $encodedUrl'); + } + } catch (e) { + print('打开链接异常: $e'); + } + }), - ], - ), - ) ], ), ), ); } + + _buildRowItem(String title, Function() onTap) { + return Container( + height: 46, + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), + margin: const EdgeInsets.only(bottom: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SkyText(text: title, fontSize: 14, color: Colors.black), + Icon(Icons.arrow_forward, color: CommonColor.black, size: 18,), + ], + ), + ).addInkWell(onTap: onTap); + } Future openUrl(String url) async { final encodedUrl = Uri.encodeFull(url); diff --git a/lib/pages/mine/page/mine_collection_page.dart b/lib/pages/mine/page/mine_collection_page.dart new file mode 100644 index 0000000..f00772b --- /dev/null +++ b/lib/pages/mine/page/mine_collection_page.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; +import 'package:skywood/global/client/play_client.dart'; +import 'package:skywood/main/lib_file.dart'; +import 'package:skywood/pages/home/players/page/drama_detail_page.dart'; +import 'package:skywood/pages/like/widget/no_data_view.dart'; +import 'package:skywood/pages/search/page/result_page.dart'; +import 'package:skywood/utils/models/drama/skywood_drama.dart'; +import 'package:skywood/utils/tools/app_toast.dart'; +import 'package:skywood/utils/tools/widgets/sky_app_bar.dart'; +import 'package:skywood/utils/tools/widgets/sky_common_widget.dart'; + +import '../../../utils/tools/sky_time_tool.dart'; + +class MineCollectionPage extends StatefulWidget { + + const MineCollectionPage({super.key}); + + @override + State createState() { + return _CollectionPageState(); + } +} + +class _CollectionPageState extends State { + + List _collectionList = []; + bool _isLoading = false; + + @override + void initState() { + super.initState(); + _getCollection(); + } + + void _getCollection() { + AppToast.showLottieLoading(); + _isLoading = true; + PlayClient.getCollections().then((value) { + AppToast.dismiss(); + _isLoading = false; + if (!mounted) return; + setState(() { + _collectionList = value; + }); + }); + } + + void _cancelCol(int shortPlayId) { + // AppToast.showLottieLoading(); + // remove + _collectionList.removeWhere((element) => element.shortPlayId == shortPlayId); + PlayClient.cancelCollect(shortPlayId: shortPlayId).then((value) { + // AppToast.dismiss(); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: SkyAppBar( + title: 'Collection', + actions: [], + ), + body: !_isLoading && _collectionList.isEmpty ? NoDataView() : ListView.separated( + itemBuilder: (context, index) { + final item = _collectionList[index]; + return Dismissible( + onDismissed: (direction) { + _cancelCol(item.shortPlayId!); + + }, + key: Key(item.shortPlayId.toString()), + child: MineItemView(drama: _collectionList[index]), + ); + }, + separatorBuilder: (context, index) { + return const SizedBox(height: 5); + }, + itemCount: _collectionList.length + ), + ); + + } + +} + + +class MineItemView extends StatelessWidget { + + const MineItemView({super.key, + required this.drama, + this.onTap + }); + + final SkywoodDrama drama; + final Function()? onTap; + + @override + Widget build(BuildContext context) { + + return Container( + height: 120.h, + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Row( + children: [ + HelpImg.networkRadius(drama.imageUrl, width: 90.w, height: 110.h, + borderRadius: BorderRadius.circular(6), + fit: BoxFit.cover, + ), + const SizedBox(width: 10), + Expanded(child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 8), + SkyText(text: drama.name, + fontSize: 14, + fontWeight: FontWeight.bold, + color: CommonColor.black, + ), + const SizedBox(height: 12), + + SkyText(text: drama.description, + fontSize: 11, + color: CommonColor.withValue('4D4047'), + maxLines: 2, + ), + Spacer(), + _tipView(true, text: 'EP.${drama.episodeTotal}'), + const SizedBox(height: 10), + ], + )) + ], + ), + ).addInkWell(onTap: onTap); + } + + Widget _tipView(bool isStar, {required String text}) { + String imgName = isStar ? ConstImg.star : ConstImg.look; + return Row( + children: [ + HelpImg.asset(imgName, width: 12.w, height: 12.w), + const SizedBox(width: 2), + SkyText(text: text, fontSize: 12, color: Colors.grey) + ], + ); + } +} \ No newline at end of file diff --git a/lib/pages/mine/page/sky_web_page.dart b/lib/pages/mine/page/sky_web_page.dart index f1d6c71..39232bd 100644 --- a/lib/pages/mine/page/sky_web_page.dart +++ b/lib/pages/mine/page/sky_web_page.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:loading_animation_widget/loading_animation_widget.dart'; +import 'package:skywood/global/const/common_color.dart'; import 'package:skywood/utils/tools/widgets/sky_app_bar.dart'; import 'package:webview_flutter/webview_flutter.dart'; +import '../../../utils/tools/help_img.dart'; + /// WebView 页面参数 class WebLinkParams { final String title; @@ -212,7 +215,7 @@ class _WebLinkViewState extends State { titleColor: Colors.white, actions: [ IconButton( - icon: const Icon(Icons.refresh), + icon: const Icon(Icons.refresh, color: Colors.white,), onPressed: _reload, ), ], @@ -221,12 +224,12 @@ class _WebLinkViewState extends State { Widget _buildBody() { return Container( - decoration: const BoxDecoration( + decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ - Color(0xFF1A0B2E), + CommonColor.primacyColor, Color(0xFF2D1B4E), ], ), @@ -255,9 +258,10 @@ class _WebLinkViewState extends State { Widget _buildContent() { if (_isLoading) { return Center( - child: LoadingAnimationWidget.newtonCradle( - color: const Color(0xFFFB98E0), - size: 96.w, + child: SizedBox( + width: 120, + height: 120, + child: Image.asset(ConstImg.loading, fit: BoxFit.fill), ), ); } diff --git a/lib/pages/mine/widget/mine_section_view.dart b/lib/pages/mine/widget/mine_section_view.dart index 4eeedcf..39fbbd6 100644 --- a/lib/pages/mine/widget/mine_section_view.dart +++ b/lib/pages/mine/widget/mine_section_view.dart @@ -49,7 +49,7 @@ class MineSectionView extends StatelessWidget { children: [ HelpImg.asset(ConstImg.sectionTopBg, width: width, height: 20.h), Positioned( - left: 7, right: 7, + left: 7, right: 7, top: 2, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/pages/search/page/result_page.dart b/lib/pages/search/page/result_page.dart index 98a840f..7660c66 100644 --- a/lib/pages/search/page/result_page.dart +++ b/lib/pages/search/page/result_page.dart @@ -4,11 +4,13 @@ import 'package:skywood/main/lib_file.dart'; import 'package:skywood/pages/home/players/page/drama_detail_page.dart'; import 'package:skywood/pages/widgets/pixel_widgets.dart'; import 'package:skywood/utils/models/drama/skywood_drama.dart'; +import 'package:skywood/utils/tools/app_toast.dart'; import 'package:skywood/utils/tools/sky_time_tool.dart'; import 'package:skywood/utils/tools/widgets/sky_app_bar.dart'; import 'package:skywood/utils/tools/widgets/sky_common_widget.dart'; import '../../../utils/tools/widgets/sky_text_field.dart'; +import '../../like/widget/no_data_view.dart'; import '../widget/search_util.dart'; class ResultPage extends StatefulWidget { @@ -30,6 +32,7 @@ class _ResultPageState extends State { final _searchController = TextEditingController(); final _searchFocus = FocusNode(); List _searchResult = []; + bool _isLoading = false; @override void initState() { @@ -45,8 +48,12 @@ class _ResultPageState extends State { _searchFocus.requestFocus(); return; } + _isLoading = true; + AppToast.showLottieLoading(); await SearchUtil.addSearch(keyword); PlayClient.search(keyword: keyword).then((valuer) { + _isLoading = false; + AppToast.dismiss(); setState(() { _searchResult = valuer; }); @@ -74,7 +81,7 @@ class _ResultPageState extends State { }, ), ), - body: ListView.separated( + body: _searchResult.isEmpty && !_isLoading ? NoDataView() : ListView.separated( itemBuilder: (context, index) => ResultItemView( drama: _searchResult[index], onTap: () { @@ -111,6 +118,7 @@ class ResultItemView extends StatelessWidget { children: [ HelpImg.networkRadius(drama.imageUrl, width: 105.w, height: 140.h, borderRadius: BorderRadius.circular(6), + fit: BoxFit.cover, ), const SizedBox(width: 10), Expanded(child: Column( diff --git a/lib/pages/widgets/mystery_box_widget.dart b/lib/pages/widgets/mystery_box_widget.dart index 8b5ac84..9448ce4 100644 --- a/lib/pages/widgets/mystery_box_widget.dart +++ b/lib/pages/widgets/mystery_box_widget.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:skywood/main/lib_file.dart'; -import 'package:skywood/pages/home/players/page/drama_detail_page.dart'; import 'package:skywood/utils/models/drama/skywood_drama.dart'; class MysteryBoxWidget extends StatelessWidget { @@ -16,7 +15,7 @@ class MysteryBoxWidget extends StatelessWidget { @override Widget build(BuildContext context) { return SizedBox( - width: AppScreen.screenWidth, height: 400, + width: AppScreen.screenWidth, height: 450, child: Column( children: [ HelpImg.asset(ConstImg.boxOpened, width: 179, height: 24), @@ -42,7 +41,11 @@ class MysteryBoxWidget extends StatelessWidget { HelpNav.back(); onTap?.call(); } - ) + ), + const SizedBox(height: 12), + IconButton(onPressed: () { + HelpNav.back(); + }, icon: HelpImg.asset(ConstImg.boxClose, width: 30)) ], ), ); diff --git a/lib/utils/tools/app_sp.dart b/lib/utils/tools/app_sp.dart index ae3e9e5..fd00c5e 100644 --- a/lib/utils/tools/app_sp.dart +++ b/lib/utils/tools/app_sp.dart @@ -5,7 +5,7 @@ import 'package:shared_preferences/shared_preferences.dart'; // 用法: AppSp().setString("key", "value"); class AppSp { static SharedPreferences? _instance; - static final String _basePrefix = "omiyo."; + static final String _basePrefix = "app."; static Future? _instanceFuture; static Future getInstance() { diff --git a/lib/utils/tools/help_img.dart b/lib/utils/tools/help_img.dart index ce1e59c..86558ac 100644 --- a/lib/utils/tools/help_img.dart +++ b/lib/utils/tools/help_img.dart @@ -17,6 +17,14 @@ class ConstImg { static const String tabMineUnselect = "assets/common/tab_mine_unselect.png"; // loading static const String loading = "assets/common/loading.gif"; + static const String btnBg = "assets/common/btn_bg.png"; + static const String noData = "assets/common/no_data.png"; + static const String nodataImg = "assets/common/nodata_img.png"; + static const String noworkImg = "assets/common/nowork_img.png"; + // applogo + static const String appLogo = "assets/common/applogo.png"; + + static const String homeBg = "assets/imgs/home_bg.png"; // home_card_bg @@ -91,10 +99,9 @@ class ConstImg { static const String mineAb = "assets/mine/mine_ab.png"; static const String minePp = "assets/mine/mine_pp.png"; static const String mineUa = "assets/mine/mine_ua.png"; + static const String collection = "assets/mine/collection.png"; - // nodata - static const String noData = "assets/images/nodata.png"; static const String loadingJson = "assets/bagua.json"; // static get appLoading => Lottie.asset(loadingJson, width: 60, height: 60); @@ -180,15 +187,18 @@ class HelpImg { fit: fit, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; - return Center( - //CircularProgressIndicator - child: Container( - width: 50, - height: 50, - padding: const EdgeInsets.all(5), - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, + return SizedBox( + width: width, height: height, + child: Center( + //CircularProgressIndicator + child: Container( + width: 30, + height: 30, + padding: const EdgeInsets.all(5), + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 1, + ), ), ), );