logo和名称替换
@@ -5,7 +5,7 @@ connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
||||
connection.project.dir=
|
||||
eclipse.preferences.version=1
|
||||
gradle.user.home=
|
||||
java.home=/Library/Java/JavaVirtualMachines/jdk-11.0.15.jdk/Contents/Home
|
||||
java.home=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home
|
||||
jvm.arguments=
|
||||
offline.mode=false
|
||||
override.workspace.settings=true
|
||||
|
||||
@@ -34,7 +34,7 @@ android {
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.hgmj.manju"
|
||||
applicationId "com.wydj.manju"
|
||||
minSdk = 24
|
||||
targetSdk = 36
|
||||
versionCode = 1
|
||||
@@ -84,7 +84,7 @@ android {
|
||||
println "outputFileDir= ${outputFileDir}"
|
||||
def abi = filters.find { it.filterType.toString() == "ABI" }?.identifier
|
||||
def abiSuffix = (variant.outputs.size() > 1 && abi) ? "_${abi}" : ""
|
||||
def path = "hgmj" + '_release' + "_" + variant.versionName + abiSuffix + "_" + createTime + ".apk"
|
||||
def path = "wydj" + '_release' + "_" + variant.versionName + abiSuffix + "_" + createTime + ".apk"
|
||||
println("path= " + path)
|
||||
outputFileName = path
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application
|
||||
android:label="黄果漫剧"
|
||||
android:label="51短剧"
|
||||
android:name=".JPApplication"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:usesCleartextTraffic="true"
|
||||
@@ -39,7 +39,7 @@
|
||||
<activity-alias
|
||||
android:name=".lld"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="黄果漫剧"
|
||||
android:label="51短剧"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:exported="true">
|
||||
|
||||
|
Before Width: | Height: | Size: 376 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 162 KiB |
@@ -14,7 +14,7 @@ fi
|
||||
|
||||
# 参数说明
|
||||
if [ $# -lt 1 ]; then
|
||||
printf -- "Build hgmj release package.\n\n"
|
||||
printf -- "Build wydj release package.\n\n"
|
||||
printf -- "Usage: $0 <target> [mode] [export_method] [export_options_plist] [sign_mode]\n"
|
||||
printf -- " target : a(android) | i(ios) | all\n"
|
||||
printf -- " mode : release(默认) | debug | profile\n"
|
||||
@@ -83,7 +83,7 @@ SAFE_VERSION=${RAW_VERSION//+/_}
|
||||
TIME_TAG=$(date +"%m%d-%H%M")
|
||||
|
||||
# 读取应用内 Config.isDebug(lib/config/config.dart),决定产物命名标识:
|
||||
# isDebug=true → 命名标识固定为 debug(如 hgmj_debug_xxxx),方便区分内测包
|
||||
# isDebug=true → 命名标识固定为 debug(如 wydj_debug_xxxx),方便区分内测包
|
||||
# isDebug=false → 正式环境,命名沿用构建模式(release/profile),保持不变
|
||||
CONFIG_FILE="lib/config/config.dart"
|
||||
CONFIG_DEBUG=$(grep -E 'static[[:space:]]+const[[:space:]]+isDebug[[:space:]]*=' "$CONFIG_FILE" 2>/dev/null | grep -oE 'true|false' | head -1)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/Users/mac/fvm/versions/3.38.3"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/mac/weiming/黄果短剧/hgmj_android"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/mac/weiming/黄果短剧/51dj_android"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_TARGET=lib/main.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=2.0.4"
|
||||
export "FLUTTER_BUILD_NUMBER=2.0.4"
|
||||
export "FLUTTER_BUILD_NAME=2.0.0"
|
||||
export "FLUTTER_BUILD_NUMBER=2.0.0"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NWP977LR25;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "黄果漫剧";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "51短剧";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -681,7 +681,7 @@
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NWP977LR25;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "黄果漫剧";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "51短剧";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -711,7 +711,7 @@
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NWP977LR25;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "黄果漫剧";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "51短剧";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 902 B |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 303 KiB After Width: | Height: | Size: 296 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 838 KiB After Width: | Height: | Size: 790 KiB |
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>黄果漫剧</string>
|
||||
<string>51短剧</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>黄果漫剧</string>
|
||||
<string>51短剧</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
||||
@@ -2,9 +2,9 @@ import 'dart:ui';
|
||||
|
||||
import 'package:easy_rich_text/easy_rich_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
|
||||
import '../hj_utils/screen.dart';
|
||||
import '../tools_base/widget/net_image_widget.dart';
|
||||
@@ -19,7 +19,9 @@ class AwPermissionAlert extends StatelessWidget {
|
||||
color: Colors.black.withValues(alpha: .4),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
|
||||
child: Config.darkWebImg?.isNotEmpty == true ? _imageView() : _normalView(),
|
||||
child: Config.darkWebImg?.isNotEmpty == true
|
||||
? _imageView()
|
||||
: _normalView(),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -60,20 +62,25 @@ class AwPermissionAlert extends StatelessWidget {
|
||||
'乌/中东战争,血腥缅北,呦呦破处,变态\n'
|
||||
'恐怖,暗网交易,等稀缺资源!',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
18.sizeBoxH,
|
||||
//会员卡名标红
|
||||
EasyRichText(
|
||||
'马上开通\n$vipName\n进入世界的黑暗面!',
|
||||
textAlign: TextAlign.center,
|
||||
defaultStyle: const TextStyle(color: Colors.white, fontSize: 14, height: 1.5),
|
||||
defaultStyle: const TextStyle(
|
||||
color: Colors.white, fontSize: 14, height: 1.5),
|
||||
patternList: [
|
||||
if (vipName.isNotEmpty)
|
||||
EasyRichTextPattern(
|
||||
targetString: vipName,
|
||||
matchWordBoundaries: false, // 纯中文无 \b 词边界,关掉才能匹配上
|
||||
hasSpecialCharacters: true, // 卡名是服务端下发的,带 ()+ 等正则符会构造出非法正则崩掉
|
||||
hasSpecialCharacters:
|
||||
true, // 卡名是服务端下发的,带 ()+ 等正则符会构造出非法正则崩掉
|
||||
style: const TextStyle(color: Color(0xffC40F0B)),
|
||||
),
|
||||
],
|
||||
@@ -88,7 +95,8 @@ class AwPermissionAlert extends StatelessWidget {
|
||||
'此板块为黑客破解内容,真实稀缺资源,\n'
|
||||
'可能会引起极度不适,请谨慎进入!\n',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .6), fontSize: 12),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .6), fontSize: 12),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_dialog.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/common_dialog.dart';
|
||||
|
||||
import '../../routers/jump_router.dart';
|
||||
|
||||
@@ -36,7 +36,8 @@ Future<int?> showVipLevelDialog(
|
||||
child: Text(
|
||||
content,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 16, color: Color(0x73FFFFFF), height: 1.5),
|
||||
style: TextStyle(
|
||||
fontSize: 16, color: Color(0x73FFFFFF), height: 1.5),
|
||||
),
|
||||
),
|
||||
if (desc != null && desc.isNotEmpty)
|
||||
@@ -49,7 +50,8 @@ Future<int?> showVipLevelDialog(
|
||||
),
|
||||
),
|
||||
24.sizeBoxH,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
if (vipEvent != null) {
|
||||
vipEvent.call();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
|
||||
import '../../hj_model/splash/ads_model.dart';
|
||||
import '../../hj_utils/screen.dart';
|
||||
@@ -70,7 +70,8 @@ class _AppCenterDialogState extends State<AppCenterDialog> {
|
||||
shrinkWrap: true, //不足 4 行时按内容收,不留空
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemCount: _appList.length,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 16,
|
||||
@@ -93,7 +94,8 @@ class _AppCenterDialogState extends State<AppCenterDialog> {
|
||||
ignoring: !_showClose,
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.back(),
|
||||
child: Image.asset("close_button.png".commonImgPath, width: 32, height: 32),
|
||||
child: Image.asset("close_button.png".commonImgPath,
|
||||
width: 32, height: 32),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -2,11 +2,11 @@ import 'package:easy_rich_text/easy_rich_text.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_dialog.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/widget/common_dialog.dart';
|
||||
|
||||
class LineErrorDialog extends StatelessWidget {
|
||||
static Future show({Function? callback}) {
|
||||
@@ -58,7 +58,10 @@ class LineErrorDialog extends StatelessWidget {
|
||||
alignment: Alignment.centerLeft,
|
||||
child: const Text(
|
||||
"解决方案:",
|
||||
style: TextStyle(color: Color(0xff656565), fontSize: 12, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Color(0xff656565),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
12.sizeBoxH,
|
||||
@@ -67,7 +70,8 @@ class LineErrorDialog extends StatelessWidget {
|
||||
2.前往官网地址 $officialUrl下载最新版。
|
||||
3.前往Telegram${Config.appName}官方交流群
|
||||
''',
|
||||
defaultStyle: TextStyle(fontSize: 12, color: Color(0xff656565), height: 1.8),
|
||||
defaultStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xff656565), height: 1.8),
|
||||
patternList: [
|
||||
EasyRichTextPattern(
|
||||
targetString: officialUrl,
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/splash/ads_model.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/splash/ads_model.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
|
||||
import '../../tools_base/banner/ads_item.dart';
|
||||
|
||||
@@ -31,7 +31,8 @@ class NoticeImageDialog extends StatelessWidget {
|
||||
aspectRatio: 6 / 8,
|
||||
),
|
||||
20.sizeBoxH,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.back(result: false),
|
||||
child: Image.asset("close_button.png".commonImgPath, width: 32),
|
||||
)
|
||||
@@ -76,7 +77,8 @@ class SystemImagesDialog extends StatelessWidget {
|
||||
itemCount: ads?.length ?? 0,
|
||||
),
|
||||
20.sizeBoxH,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.back(result: false),
|
||||
child: Image.asset("close_button.png".commonImgPath, width: 32),
|
||||
)
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import 'package:easy_rich_text/easy_rich_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_dialog.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/common_dialog.dart';
|
||||
|
||||
import '../../hj_model/splash/ads_model.dart';
|
||||
|
||||
@@ -43,7 +43,8 @@ class NoticeTextDialog extends StatelessWidget {
|
||||
child: SingleChildScrollView(
|
||||
child: EasyRichText(
|
||||
content ?? "",
|
||||
defaultStyle: TextStyle(color: Color(0xff656565), fontSize: 12, height: 25 / 12),
|
||||
defaultStyle: TextStyle(
|
||||
color: Color(0xff656565), fontSize: 12, height: 25 / 12),
|
||||
patternList: [
|
||||
EasyRichTextPattern(
|
||||
targetString:
|
||||
@@ -59,15 +60,21 @@ class NoticeTextDialog extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
12.sizeBoxH,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.back(),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(3), color: AppColors.actionRed),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
color: AppColors.actionRed),
|
||||
child: Text(
|
||||
"我知道了",
|
||||
style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -5,11 +5,11 @@ import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_utils/install_util.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_dialog.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/hj_utils/install_util.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/common_dialog.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
@@ -118,7 +118,9 @@ class _UpdateDialog extends State<UpdateDialog> {
|
||||
//Row 不给约束,Text 会按自然宽度排版撑出去,必须 Expanded 收回可用宽度才会换行
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.updateInfo.description?.replaceAll("|", "\n") ?? "",
|
||||
widget.updateInfo.description
|
||||
?.replaceAll("|", "\n") ??
|
||||
"",
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .55),
|
||||
fontSize: 12,
|
||||
@@ -240,8 +242,10 @@ class _UpdateDialog extends State<UpdateDialog> {
|
||||
|
||||
///下载 apk(仅 Android,iOS 走商店)
|
||||
Future<void> _downloadApk(String url) async {
|
||||
final saveDirectory = path.join((await getExternalStorageDirectory())?.path ?? "", "apk");
|
||||
DioSliceRetryDownloader(DioCli(), url, null, saveDirectory, "paofu.apk", onReceiveProgress: (count, total) {
|
||||
final saveDirectory =
|
||||
path.join((await getExternalStorageDirectory())?.path ?? "", "apk");
|
||||
DioSliceRetryDownloader(DioCli(), url, null, saveDirectory, "paofu.apk",
|
||||
onReceiveProgress: (count, total) {
|
||||
progress = (count / total);
|
||||
setState(() {});
|
||||
}, onRetry: (int retryCount) {
|
||||
|
||||
@@ -5,9 +5,9 @@ import 'dart:math' as math;
|
||||
import 'package:carousel_slider/carousel_slider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../hj_model/splash/domain_source_model.dart';
|
||||
@@ -26,10 +26,12 @@ import 'buy_vip_alert_logic.dart';
|
||||
class BuyVipAlert extends StatefulWidget {
|
||||
final String? vipId; //外部指定卡ID(可选),不传走分层卡/升级卡兜底
|
||||
final String? videoId; //在看的那条内容 id,下单时透传给服务端做归因
|
||||
final PayOrderTrackInfo? orderTrack; //整份下单上下文,短剧付费墙要带 mediaId/contentId/checkoutContextId
|
||||
final PayOrderTrackInfo?
|
||||
orderTrack; //整份下单上下文,短剧付费墙要带 mediaId/contentId/checkoutContextId
|
||||
const BuyVipAlert({super.key, this.vipId, this.videoId, this.orderTrack});
|
||||
|
||||
static Future show({String? vipId, String? videoId, PayOrderTrackInfo? orderTrack}) {
|
||||
static Future show(
|
||||
{String? vipId, String? videoId, PayOrderTrackInfo? orderTrack}) {
|
||||
return Get.bottomSheet(
|
||||
BuyVipAlert(vipId: vipId, videoId: videoId, orderTrack: orderTrack),
|
||||
isScrollControlled: true,
|
||||
@@ -42,7 +44,10 @@ class BuyVipAlert extends StatefulWidget {
|
||||
|
||||
// 可叠弹(试看结束/超时长等多处触发),用 per-实例唯一 tag 隔离 controller
|
||||
class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
late final logic = BuyVipAlertLogic(vId: widget.vipId, videoId: widget.videoId, orderTrack: widget.orderTrack);
|
||||
late final logic = BuyVipAlertLogic(
|
||||
vId: widget.vipId,
|
||||
videoId: widget.videoId,
|
||||
orderTrack: widget.orderTrack);
|
||||
|
||||
static const _sheetRadius = 26.0;
|
||||
|
||||
@@ -109,14 +114,18 @@ class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
_selectionBuilder(
|
||||
(_) => Text(
|
||||
_title,
|
||||
style: const TextStyle(color: Color(0xE5FFFFFF), fontSize: 16, fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
color: Color(0xE5FFFFFF),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
_buildCountdown(),
|
||||
],
|
||||
),
|
||||
14.sizeBoxH,
|
||||
_selectionBuilder((_) => _buildPriceInfo()), //原价 / 限时特价 / 优惠
|
||||
_selectionBuilder(
|
||||
(_) => _buildPriceInfo()), //原价 / 限时特价 / 优惠
|
||||
16.sizeBoxH,
|
||||
Expanded(
|
||||
child: _buildContent(),
|
||||
@@ -169,7 +178,8 @@ class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
child: CarouselSlider.builder(
|
||||
carouselController: logic.pageCtr,
|
||||
itemCount: mgr.vipCards.length + 2,
|
||||
itemBuilder: (_, index, __) => _selectionBuilder((l) => l.instanceChildItem(index)),
|
||||
itemBuilder: (_, index, __) => _selectionBuilder(
|
||||
(l) => l.instanceChildItem(index)),
|
||||
options: CarouselOptions(
|
||||
height: logic.cardHeight,
|
||||
viewportFraction: logic.itemRatio,
|
||||
@@ -180,7 +190,8 @@ class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
enlargeCenterPage: false,
|
||||
padEnds: false,
|
||||
clipBehavior: Clip.none,
|
||||
onPageChanged: (index, __) => logic.onPageChanged(index),
|
||||
onPageChanged: (index, __) =>
|
||||
logic.onPageChanged(index),
|
||||
scrollDirection: Axis.horizontal,
|
||||
),
|
||||
),
|
||||
@@ -230,7 +241,8 @@ class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
decoration: TextDecoration.lineThrough,
|
||||
decorationColor: Color(0x8cFFFFFF),
|
||||
);
|
||||
const normal = TextStyle(color: Color(0x8cFFFFFF), fontSize: 14, fontWeight: FontWeight.w500);
|
||||
const normal = TextStyle(
|
||||
color: Color(0x8cFFFFFF), fontSize: 14, fontWeight: FontWeight.w500);
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
@@ -238,16 +250,20 @@ class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
24.sizeBoxW,
|
||||
_priceItem("限时特价", "¥$discounted", normal),
|
||||
24.sizeBoxW,
|
||||
_priceItem("优惠", "¥${(original - discounted).clamp(0, original)}", normal),
|
||||
_priceItem(
|
||||
"优惠", "¥${(original - discounted).clamp(0, original)}", normal),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _priceItem(String title, String value, TextStyle valueStyle, {TextStyle? titleStyle}) {
|
||||
Widget _priceItem(String title, String value, TextStyle valueStyle,
|
||||
{TextStyle? titleStyle}) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(title, style: titleStyle ?? const TextStyle(color: Color(0x99FFFFFF), fontSize: 14)),
|
||||
Text(title,
|
||||
style: titleStyle ??
|
||||
const TextStyle(color: Color(0x99FFFFFF), fontSize: 14)),
|
||||
4.sizeBoxW,
|
||||
Text(value, style: valueStyle),
|
||||
],
|
||||
@@ -260,7 +276,8 @@ class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
valueListenable: MineMsgProvider().tick,
|
||||
builder: (_, __, ___) {
|
||||
final c = MineMsgProvider().payTier?.config;
|
||||
if (c == null || !c.hasDiscountCountdown) return const SizedBox.shrink();
|
||||
if (c == null || !c.hasDiscountCountdown)
|
||||
return const SizedBox.shrink();
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -281,27 +298,35 @@ class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
width: 24,
|
||||
height: 24,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(color: const Color(0xffE1351F), borderRadius: BorderRadius.circular(3)),
|
||||
child: Text(value, style: const TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500)),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xffE1351F),
|
||||
borderRadius: BorderRadius.circular(3)),
|
||||
child: Text(value,
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _colon() => const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
child: Text(":", style: TextStyle(color: Color(0xffDD001B), fontSize: 20)),
|
||||
child:
|
||||
Text(":", style: TextStyle(color: Color(0xffDD001B), fontSize: 20)),
|
||||
);
|
||||
|
||||
/// 权益区:与会员中心同实验分支 —— classic=A/DISABLED,改版=ACTIVE+B
|
||||
Widget _buildPrivilegeSections({required bool classic}) {
|
||||
return _selectionBuilder((l) {
|
||||
final privileges = l.currentProductModel?.newPrivilege ?? [];
|
||||
// final coreList = privileges.where((p) => p.isCore == true).toList();
|
||||
final moreList = privileges; // privileges.where((p) => p.isCore != true).toList();
|
||||
// final coreList = privileges.where((p) => p.isCore == true).toList();
|
||||
final moreList =
|
||||
privileges; // privileges.where((p) => p.isCore != true).toList();
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// classic ? _buildClassicCorePrivileges(coreList) : _buildCorePrivileges(coreList),
|
||||
classic ? _buildClassicMorePrivileges(moreList) : _buildMorePrivileges(moreList),
|
||||
// classic ? _buildClassicCorePrivileges(coreList) : _buildCorePrivileges(coreList),
|
||||
classic
|
||||
? _buildClassicMorePrivileges(moreList)
|
||||
: _buildMorePrivileges(moreList),
|
||||
],
|
||||
);
|
||||
});
|
||||
@@ -358,7 +383,8 @@ class _BuyVipAlertState extends State<BuyVipAlert> with UniqueTagMixin {
|
||||
childAspectRatio: 63 / 100,
|
||||
),
|
||||
itemCount: list.length,
|
||||
itemBuilder: (_, i) => VipProductPrivilegeItem(list[i], classic: true),
|
||||
itemBuilder: (_, i) =>
|
||||
VipProductPrivilegeItem(list[i], classic: true),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -410,6 +436,8 @@ class _BuyVipTopBorderPainter extends CustomPainter {
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant _BuyVipTopBorderPainter oldDelegate) {
|
||||
return oldDelegate.gradient != gradient || oldDelegate.strokeWidth != strokeWidth || oldDelegate.topRadius != topRadius;
|
||||
return oldDelegate.gradient != gradient ||
|
||||
oldDelegate.strokeWidth != strokeWidth ||
|
||||
oldDelegate.topRadius != topRadius;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/extension/extensions.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../assets_tool/app_colors.dart';
|
||||
@@ -75,34 +75,48 @@ class _ComicBuyAlertState extends State<ComicBuyAlert> {
|
||||
18.sizeBoxH,
|
||||
const Text(
|
||||
'购买作品',
|
||||
style: TextStyle(color: Color(0xE5ffffff), fontSize: 20, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Color(0xE5ffffff),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
36.sizeBoxH,
|
||||
//作品解锁价
|
||||
Row(
|
||||
children: [
|
||||
const Text('作品解锁', style: TextStyle(color: Color(0xE5ffffff), fontSize: 14)),
|
||||
const Text('作品解锁',
|
||||
style:
|
||||
TextStyle(color: Color(0xE5ffffff), fontSize: 14)),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => pushToWalletPage(tabPosition: 1),
|
||||
child: Text(
|
||||
'$_price 金币',
|
||||
style: const TextStyle(color: Color(0xffFF9000), fontSize: 14, fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
color: Color(0xffFF9000),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
18.sizeBoxH,
|
||||
Divider(height: 0.5, color: Colors.white.withValues(alpha: .05)),
|
||||
Divider(
|
||||
height: 0.5, color: Colors.white.withValues(alpha: .05)),
|
||||
18.sizeBoxH,
|
||||
//我的金币余额 + 充值入口
|
||||
Row(
|
||||
children: [
|
||||
const Text('我的金币', style: TextStyle(color: Color(0xE5ffffff), fontSize: 14)),
|
||||
const Text('我的金币',
|
||||
style:
|
||||
TextStyle(color: Color(0xE5ffffff), fontSize: 14)),
|
||||
const Spacer(),
|
||||
Text(
|
||||
'${store.wallet?.amount?.toDouble().fixed(2) ?? 0}',
|
||||
style: const TextStyle(color: Color(0xE5ffffff), fontSize: 14, fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
color: Color(0xE5ffffff),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
12.sizeBoxW,
|
||||
InkWell(
|
||||
@@ -125,15 +139,22 @@ class _ComicBuyAlertState extends State<ComicBuyAlert> {
|
||||
//支付按钮:余额不足直接去充值
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => enough ? _buyProduct(true) : pushToWalletPage(tabPosition: 1),
|
||||
onTap: () => enough
|
||||
? _buyProduct(true)
|
||||
: pushToWalletPage(tabPosition: 1),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 47,
|
||||
decoration: BoxDecoration(color: const Color(0xffFFC000), borderRadius: BorderRadius.circular(30)),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xffFFC000),
|
||||
borderRadius: BorderRadius.circular(30)),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
enough ? '$_price金币/立即支付' : '余额不足,前往充值',
|
||||
style: const TextStyle(color: Color(0xff1F2029), fontSize: 16, fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
color: Color(0xff1F2029),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -150,7 +171,9 @@ class _ComicBuyAlertState extends State<ComicBuyAlert> {
|
||||
if (_isBuying) return; //纯防重入,build 不依赖它,改了不用 setState
|
||||
_isBuying = true;
|
||||
final productType = isAll ? ProductType.mediaAll : ProductType.mediaChapter;
|
||||
final productID = isAll ? (widget.mediaInfo?.id ?? widget.curModel?.mediaId) : widget.curModel?.id;
|
||||
final productID = isAll
|
||||
? (widget.mediaInfo?.id ?? widget.curModel?.mediaId)
|
||||
: widget.curModel?.id;
|
||||
await PayManager().buy(
|
||||
productID,
|
||||
productType,
|
||||
|
||||
@@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_model/user/user_info_model.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_dialog.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_model/user/user_info_model.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/common_dialog.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
|
||||
import '../../config/address.dart';
|
||||
@@ -72,7 +72,8 @@ class _ShareMediaDialogState extends State<ShareMediaDialog> {
|
||||
//app 图标 + 名称 + 标语
|
||||
Row(
|
||||
children: [
|
||||
Image.asset('ic_launcher.webp'.commonImgPath, width: 48.w, height: 48.w),
|
||||
Image.asset('ic_launcher.webp'.commonImgPath,
|
||||
width: 48.w, height: 48.w),
|
||||
10.w.sizeBoxW,
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -80,10 +81,16 @@ class _ShareMediaDialogState extends State<ShareMediaDialog> {
|
||||
children: [
|
||||
Text(
|
||||
Config.appName,
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .9), fontWeight: FontWeight.w500, fontSize: 14),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .9),
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14),
|
||||
),
|
||||
4.sizeBoxH,
|
||||
Text("百万大神短剧原创", style: TextStyle(color: Colors.white.withValues(alpha: .55), fontSize: 10)),
|
||||
Text("百万大神短剧原创",
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .55),
|
||||
fontSize: 10)),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -110,7 +117,8 @@ class _ShareMediaDialogState extends State<ShareMediaDialog> {
|
||||
height: 94,
|
||||
padding: const EdgeInsets.all(2),
|
||||
color: Colors.white,
|
||||
child: QrImageView(data: _shareUrl, padding: EdgeInsets.zero),
|
||||
child: QrImageView(
|
||||
data: _shareUrl, padding: EdgeInsets.zero),
|
||||
),
|
||||
16.sizeBoxW,
|
||||
Expanded(
|
||||
@@ -120,13 +128,18 @@ class _ShareMediaDialogState extends State<ShareMediaDialog> {
|
||||
children: [
|
||||
Text(
|
||||
"邀请码${_me?.promotionCode ?? ""}",
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Colors.white.withValues(alpha: .9)),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white.withValues(alpha: .9)),
|
||||
),
|
||||
20.sizeBoxH,
|
||||
Text(
|
||||
'每邀请 1人 送 1天 会员 ${Address.groundUrl}',
|
||||
maxLines: 2,
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .55)),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.white.withValues(alpha: .55)),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -164,7 +177,10 @@ class _ShareMediaDialogState extends State<ShareMediaDialog> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _button(String text, {required Color bgColor, required Color textColor, required VoidCallback onTap}) {
|
||||
Widget _button(String text,
|
||||
{required Color bgColor,
|
||||
required Color textColor,
|
||||
required VoidCallback onTap}) {
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: onTap,
|
||||
@@ -177,7 +193,8 @@ class _ShareMediaDialogState extends State<ShareMediaDialog> {
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(fontSize: 16, color: textColor, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
fontSize: 16, color: textColor, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/extension/extensions.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_page/mine/widgets/gradient_text.dart';
|
||||
import 'package:hgmj/hj_page/mine/mine_vip/widgets/coin_pay_bottom_sheet.dart';
|
||||
import 'package:hgmj/hj_utils/pay/pay_manager.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/mine/widgets/gradient_text.dart';
|
||||
import 'package:wydj/hj_page/mine/mine_vip/widgets/coin_pay_bottom_sheet.dart';
|
||||
import 'package:wydj/hj_utils/pay/pay_manager.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
///金币购买作品面板
|
||||
@@ -33,7 +33,8 @@ class _VideoBuyBottomSheetState extends State<VideoBuyBottomSheet> {
|
||||
bool get _noDiscount => _video.newsType == "PIC" || _isSeedLink;
|
||||
|
||||
//实际售价:无折扣品类按原价,其余按折后价
|
||||
String get _priceText => '${(_noDiscount ? _video.originCoins : _video.coins) ?? 0} 金币';
|
||||
String get _priceText =>
|
||||
'${(_noDiscount ? _video.originCoins : _video.coins) ?? 0} 金币';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -61,19 +62,26 @@ class _VideoBuyBottomSheetState extends State<VideoBuyBottomSheet> {
|
||||
18.sizeBoxH,
|
||||
const Text(
|
||||
'购买作品',
|
||||
style: TextStyle(color: Color(0xE5ffffff), fontSize: 20, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Color(0xE5ffffff),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
18.sizeBoxH,
|
||||
//作品解锁价
|
||||
Row(
|
||||
children: [
|
||||
const Text('作品解锁', style: TextStyle(color: Color(0xE5ffffff), fontSize: 14)),
|
||||
const Text('作品解锁',
|
||||
style: TextStyle(color: Color(0xE5ffffff), fontSize: 14)),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => CoinPayBottomSheet.show(),
|
||||
child: Text(
|
||||
_priceText,
|
||||
style: const TextStyle(color: Color(0xffFF9000), fontSize: 14, fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
color: Color(0xffFF9000),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -86,11 +94,15 @@ class _VideoBuyBottomSheetState extends State<VideoBuyBottomSheet> {
|
||||
//我的金币余额 + 充值入口
|
||||
Row(
|
||||
children: [
|
||||
const Text('我的金币', style: TextStyle(color: Color(0xE5ffffff), fontSize: 14)),
|
||||
const Text('我的金币',
|
||||
style: TextStyle(color: Color(0xE5ffffff), fontSize: 14)),
|
||||
const Spacer(),
|
||||
Text(
|
||||
'${store.wallet?.amount?.toDouble().fixed(2) ?? 0}',
|
||||
style: const TextStyle(color: Color(0xE5ffffff), fontSize: 14, fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
color: Color(0xE5ffffff),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
12.sizeBoxW,
|
||||
InkWell(
|
||||
@@ -164,7 +176,8 @@ class _VideoBuyBottomSheetState extends State<VideoBuyBottomSheet> {
|
||||
return [
|
||||
Row(
|
||||
children: [
|
||||
const Text('作品原价', style: TextStyle(color: Color(0xE5FFFFFF), fontSize: 14)),
|
||||
const Text('作品原价',
|
||||
style: TextStyle(color: Color(0xE5FFFFFF), fontSize: 14)),
|
||||
const Spacer(),
|
||||
Text(
|
||||
'${_video.originCoins ?? 0} 金币',
|
||||
@@ -183,14 +196,16 @@ class _VideoBuyBottomSheetState extends State<VideoBuyBottomSheet> {
|
||||
GradientText(
|
||||
discountText,
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
gradient: const LinearGradient(colors: [Color(0xffAC7E6E), Color(0xffA4634D)]),
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xffAC7E6E), Color(0xffA4634D)]),
|
||||
),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => pushToWalletPage(),
|
||||
child: GradientText(
|
||||
isVip ? '升级会员免费看' : '购买VIP免费看',
|
||||
gradient: const LinearGradient(colors: [Color(0xffAC7E6E), Color(0xffA4634D)]),
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xffAC7E6E), Color(0xffA4634D)]),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
@@ -205,7 +220,10 @@ class _VideoBuyBottomSheetState extends State<VideoBuyBottomSheet> {
|
||||
];
|
||||
}
|
||||
|
||||
Widget _button(String text, {required Color textColor, required BoxDecoration decoration, required VoidCallback onTap}) {
|
||||
Widget _button(String text,
|
||||
{required Color textColor,
|
||||
required BoxDecoration decoration,
|
||||
required VoidCallback onTap}) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: onTap,
|
||||
@@ -215,7 +233,8 @@ class _VideoBuyBottomSheetState extends State<VideoBuyBottomSheet> {
|
||||
decoration: decoration,
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(color: textColor, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: textColor, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -227,7 +246,8 @@ class _VideoBuyBottomSheetState extends State<VideoBuyBottomSheet> {
|
||||
return;
|
||||
}
|
||||
//黄游(SEED_LINK)和普通视频都按单片算,动漫按整部算
|
||||
final type = (!_isSeedLink && _isCartoon) ? ProductType.mediaAll : ProductType.media;
|
||||
final type =
|
||||
(!_isSeedLink && _isCartoon) ? ProductType.mediaAll : ProductType.media;
|
||||
await PayManager().buy(
|
||||
_video.id,
|
||||
type,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
|
||||
import '../../config/address.dart';
|
||||
import '../../hj_model/splash/domain_source_model.dart';
|
||||
@@ -70,7 +70,9 @@ class VideoLineMenuAlert extends StatelessWidget {
|
||||
domain.desc ?? "",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: isSelected ? Color(0xffFFC000) : Colors.white.withValues(alpha: 0.45),
|
||||
color: isSelected
|
||||
? Color(0xffFFC000)
|
||||
: Colors.white.withValues(alpha: 0.45),
|
||||
fontWeight: isSelected ? FontWeight.w500 : FontWeight.w400,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_dialog.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/widget/common_dialog.dart';
|
||||
|
||||
/// 动漫/图集的 VIP 门槛提示弹窗:只有文案和一个开通按钮
|
||||
class VipACGDialog extends StatelessWidget {
|
||||
@@ -16,13 +16,19 @@ class VipACGDialog extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
"温馨提示",
|
||||
style: TextStyle(fontSize: 20, color: Colors.white.withValues(alpha: .9), fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.white.withValues(alpha: .9),
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
24.sizeBoxH,
|
||||
Text(
|
||||
"本内容需要开通VIP会员\n开通会员 即可解锁查看完整版",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 16, color: Colors.white.withValues(alpha: .45), height: 2),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white.withValues(alpha: .45),
|
||||
height: 2),
|
||||
),
|
||||
24.sizeBoxH,
|
||||
//开通按钮。margin 留在 InkWell 外,否则左右各 12 的空白会被算进点击热区
|
||||
@@ -34,10 +40,15 @@ class VipACGDialog extends StatelessWidget {
|
||||
child: Container(
|
||||
height: 44,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(color: AppColors.actionRed, borderRadius: BorderRadius.circular(30)),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.actionRed,
|
||||
borderRadius: BorderRadius.circular(30)),
|
||||
child: const Text(
|
||||
"立即开通",
|
||||
style: TextStyle(fontSize: 16, color: Color(0xff1F2029), fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Color(0xff1F2029),
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
|
||||
import '../../hj_page/mine/mine_vip/pay_order_source.dart';
|
||||
import '../../hj_page/mine/mine_vip/vip_support_model.dart';
|
||||
@@ -66,14 +66,21 @@ class GuideBottomSheet extends StatelessWidget {
|
||||
return show(
|
||||
scene: GuideScene.videoPreviewEnd,
|
||||
title: Text(
|
||||
config?.title?.isNotEmpty == true ? config!.title! : '该视频为VIP内容\n只能观看试看内容哦~',
|
||||
config?.title?.isNotEmpty == true
|
||||
? config!.title!
|
||||
: '该视频为VIP内容\n只能观看试看内容哦~',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 17, fontWeight: FontWeight.w600),
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontSize: 17, fontWeight: FontWeight.w600),
|
||||
),
|
||||
subtitle: GradientText(
|
||||
config?.description?.isNotEmpty == true ? config!.description! : '想要查看完整内容,需要开通会员',
|
||||
gradient: const LinearGradient(colors: [Colors.white, Color(0xffEFD394)]),
|
||||
style: const TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w500),
|
||||
config?.description?.isNotEmpty == true
|
||||
? config!.description!
|
||||
: '想要查看完整内容,需要开通会员',
|
||||
gradient:
|
||||
const LinearGradient(colors: [Colors.white, Color(0xffEFD394)]),
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontSize: 15, fontWeight: FontWeight.w500),
|
||||
),
|
||||
buttonText: buttonText,
|
||||
);
|
||||
@@ -87,8 +94,13 @@ class GuideBottomSheet extends StatelessWidget {
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.fromLTRB(16, 18, 16, 18 + screen.paddingBottom),
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xff0F0F0F), Colors.black]),
|
||||
border: Border(top: BorderSide(color: Color(0x4DE4BB6D))), // rgba(228,187,109,0.3)
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xff0F0F0F), Colors.black]),
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Color(0x4DE4BB6D))), // rgba(228,187,109,0.3)
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
child: Column(
|
||||
@@ -103,7 +115,8 @@ class GuideBottomSheet extends StatelessWidget {
|
||||
SizedBox(
|
||||
width: 270,
|
||||
height: 122,
|
||||
child: NetworkImageLoader(imageUrl: cover, fit: BoxFit.fill, borderRadius: 8),
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: cover, fit: BoxFit.fill, borderRadius: 8),
|
||||
),
|
||||
18.sizeBoxH,
|
||||
subtitle,
|
||||
@@ -116,11 +129,21 @@ class GuideBottomSheet extends StatelessWidget {
|
||||
height: 52,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(colors: [Color(0xffFFB03F), Color(0xffF2680C)]),
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xffFFB03F), Color(0xffF2680C)]),
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
boxShadow: [BoxShadow(color: const Color(0x73F2680C), blurRadius: 18, offset: const Offset(0, 6))], // rgba(242,104,12,0.45)
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x73F2680C),
|
||||
blurRadius: 18,
|
||||
offset: const Offset(0, 6))
|
||||
], // rgba(242,104,12,0.45)
|
||||
),
|
||||
child: Text(buttonText, style: const TextStyle(color: Colors.white, fontSize: 17, fontWeight: FontWeight.w700)),
|
||||
child: Text(buttonText,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w700)),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/splash/domain_source_model.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/hj_model/splash/domain_source_model.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
|
||||
import '../../hj_page/main_page/provider/msg_provider.dart';
|
||||
import '../../hj_page/mine/mine_vip/mine_charge_vip_page.dart';
|
||||
@@ -19,13 +19,18 @@ import 'guide_manager.dart';
|
||||
Future<VipProductModel?> loadGuideCard(GuideScene scene) async {
|
||||
final config = GuideManager().configOf(scene);
|
||||
if (config == null) return null; // 开关关着
|
||||
if (config.productId?.isNotEmpty != true || config.cover?.isNotEmpty != true) {
|
||||
if (config.productId?.isNotEmpty != true ||
|
||||
config.cover?.isNotEmpty != true) {
|
||||
debugLog('paymentGuide', '${scene.value} 缺 productId 或 cover,配置有误不弹');
|
||||
return null;
|
||||
}
|
||||
if (vipProductManager.vipCards.isEmpty) await vipProductManager.loadVipCards();
|
||||
final card = vipProductManager.vipCards.firstWhereOrNull((e) => e.productID == config.productId);
|
||||
if (card == null) debugLog('paymentGuide', '${scene.value} 配置的会员卡不在列表里,不弹: ${config.productId}');
|
||||
if (vipProductManager.vipCards.isEmpty)
|
||||
await vipProductManager.loadVipCards();
|
||||
final card = vipProductManager.vipCards
|
||||
.firstWhereOrNull((e) => e.productID == config.productId);
|
||||
if (card == null)
|
||||
debugLog(
|
||||
'paymentGuide', '${scene.value} 配置的会员卡不在列表里,不弹: ${config.productId}');
|
||||
return card;
|
||||
}
|
||||
|
||||
@@ -38,7 +43,9 @@ bool isUnpayGuideUser() {
|
||||
|
||||
/// 场景 → 下单来源页(透传 /mine/topay 的 sourcePage)
|
||||
PaySourcePage guideSourcePage(GuideScene scene) => switch (scene) {
|
||||
GuideScene.homeNewUser || GuideScene.homeOldUser || GuideScene.homeNewUserFreeTrial =>
|
||||
GuideScene.homeNewUser ||
|
||||
GuideScene.homeOldUser ||
|
||||
GuideScene.homeNewUserFreeTrial =>
|
||||
PaySourcePage.homeUserSegment,
|
||||
GuideScene.vipCenter => PaySourcePage.vipCenter,
|
||||
_ => PaySourcePage.videoBottomSheet, //播放页起播引导 / 返回挽留
|
||||
@@ -47,5 +54,6 @@ PaySourcePage guideSourcePage(GuideScene scene) => switch (scene) {
|
||||
/// 开通 → 关弹窗 + 进会员页并选中该卡(落地页 VIP_CENTER 开着还会再弹一次,不去重)
|
||||
void goVipDetail(VipProductModel card, {required PaySourcePage sourcePage}) {
|
||||
Get.back(result: true); // 带回"去开通了",调用方据此不恢复播放
|
||||
Get.to(() => MineChargeVipPage(vipID: card.productID, sourcePage: sourcePage));
|
||||
Get.to(
|
||||
() => MineChargeVipPage(vipID: card.productID, sourcePage: sourcePage));
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../assets_tool/images.dart';
|
||||
import '../../hj_page/mine/mine_vip/pay_order_source.dart';
|
||||
@@ -34,7 +34,8 @@ class PromoCountdown {
|
||||
/// 长视频返回挽留 / 进会员页时触发
|
||||
class GuideCountdownDialog extends StatelessWidget {
|
||||
final VipProductModel card;
|
||||
final ValueChanged<VipProductModel>? onConfirm; // 默认跳会员页选卡;已在会员页的场景自己处理(关弹窗+就地选中该卡)
|
||||
final ValueChanged<VipProductModel>?
|
||||
onConfirm; // 默认跳会员页选卡;已在会员页的场景自己处理(关弹窗+就地选中该卡)
|
||||
final PaySourcePage sourcePage;
|
||||
final String cover; // 场景下发的主图,相对路径由 ImageCacheManager 拼域名
|
||||
const GuideCountdownDialog({
|
||||
@@ -47,7 +48,9 @@ class GuideCountdownDialog extends StatelessWidget {
|
||||
|
||||
/// [scene] 决定主图/卡/下单来源,调用方须先用开关判过能弹
|
||||
/// 返回 true = 点了「立即开通」(点X/点蒙层/没弹成都是 false),返回挽留场景据此决定要不要放行返回
|
||||
static Future<bool> show({required GuideScene scene, ValueChanged<VipProductModel>? onConfirm}) async {
|
||||
static Future<bool> show(
|
||||
{required GuideScene scene,
|
||||
ValueChanged<VipProductModel>? onConfirm}) async {
|
||||
final card = await loadGuideCard(scene);
|
||||
if (card == null) return false; // 配置有误不弹
|
||||
final confirmed = await Get.dialog<bool>(
|
||||
@@ -92,15 +95,29 @@ class GuideCountdownDialog extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
const Text('现在下单获得', style: TextStyle(color: Colors.white, fontSize: 19, fontWeight: FontWeight.w800)),
|
||||
const Text('现在下单获得',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 19,
|
||||
fontWeight: FontWeight.w800)),
|
||||
2.sizeBoxW,
|
||||
const GradientText(
|
||||
'优惠',
|
||||
gradient: LinearGradient(colors: [Color(0xffFFE3A0), Color(0xffF0A93C)]),
|
||||
style: TextStyle(color: Colors.white, fontSize: 26, fontWeight: FontWeight.w800),
|
||||
gradient: LinearGradient(colors: [
|
||||
Color(0xffFFE3A0),
|
||||
Color(0xffF0A93C)
|
||||
]),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 26,
|
||||
fontWeight: FontWeight.w800),
|
||||
),
|
||||
2.sizeBoxW,
|
||||
const Text('福利', style: TextStyle(color: Colors.white, fontSize: 19, fontWeight: FontWeight.w800)),
|
||||
const Text('福利',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 19,
|
||||
fontWeight: FontWeight.w800)),
|
||||
],
|
||||
),
|
||||
15.sizeBoxH,
|
||||
@@ -119,15 +136,24 @@ class GuideCountdownDialog extends StatelessWidget {
|
||||
height: 52,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(colors: [Color(0xffFFB03F), Color(0xffF2680C)]),
|
||||
gradient: const LinearGradient(colors: [
|
||||
Color(0xffFFB03F),
|
||||
Color(0xffF2680C)
|
||||
]),
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
boxShadow: [
|
||||
BoxShadow(color: const Color(0x73F2680C), blurRadius: 18, offset: const Offset(0, 6))
|
||||
BoxShadow(
|
||||
color: const Color(0x73F2680C),
|
||||
blurRadius: 18,
|
||||
offset: const Offset(0, 6))
|
||||
], // rgba(242,104,12,0.45)
|
||||
),
|
||||
child: Text(
|
||||
'立即开通 · 仅需¥${card.discountedPriceUI}',
|
||||
style: const TextStyle(color: Colors.white, fontSize: 17, fontWeight: FontWeight.w700),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -140,7 +166,8 @@ class GuideCountdownDialog extends StatelessWidget {
|
||||
child: SizedBox(
|
||||
width: 270,
|
||||
height: 122,
|
||||
child: NetworkImageLoader(imageUrl: cover, fit: BoxFit.fill, borderRadius: 8),
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: cover, fit: BoxFit.fill, borderRadius: 8),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -193,7 +220,11 @@ class _CountdownRowState extends State<_CountdownRow> {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('距优惠结束', style: TextStyle(color: Color(0xffB8AE9C), fontSize: 12, fontWeight: FontWeight.w500)),
|
||||
const Text('距优惠结束',
|
||||
style: TextStyle(
|
||||
color: Color(0xffB8AE9C),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500)),
|
||||
8.sizeBoxW,
|
||||
ValueListenableBuilder<Duration>(
|
||||
valueListenable: _remain,
|
||||
@@ -215,15 +246,22 @@ class _CountdownRowState extends State<_CountdownRow> {
|
||||
// 时/分/秒块
|
||||
Widget _timeCell(int v) => Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 4),
|
||||
decoration: BoxDecoration(color: const Color(0xffE23B2E), borderRadius: BorderRadius.circular(6)),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xffE23B2E),
|
||||
borderRadius: BorderRadius.circular(6)),
|
||||
child: Text(
|
||||
v.toString().padLeft(2, '0'),
|
||||
style: const TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w700),
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontSize: 14, fontWeight: FontWeight.w700),
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _colon => const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 3),
|
||||
child: Text(':', style: TextStyle(color: Color(0xffE85B4F), fontSize: 14, fontWeight: FontWeight.w700)),
|
||||
child: Text(':',
|
||||
style: TextStyle(
|
||||
color: Color(0xffE85B4F),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/splash/domain_source_model.dart';
|
||||
import 'package:hgmj/hj_page/home/activity_float/home_activity_float.dart';
|
||||
import 'package:hgmj/hj_page/main_page/provider/msg_provider.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/fly_to_overlay.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/splash/domain_source_model.dart';
|
||||
import 'package:wydj/hj_page/home/activity_float/home_activity_float.dart';
|
||||
import 'package:wydj/hj_page/main_page/provider/msg_provider.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/fly_to_overlay.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
/// 支付分层首页弹窗:展示后端 homePage 图,点击跳会员页并选中 config.vipCard。
|
||||
/// 倒计时读 config.lastDiscountTime,秒级刷新由 MineMsgProvider().tick 驱动,过期自动停
|
||||
@@ -60,7 +60,8 @@ class _GuideHomeDialogState extends State<GuideHomeDialog> {
|
||||
if (box == null || !box.hasSize) return null;
|
||||
final origin = box.localToGlobal(Offset.zero);
|
||||
const w = 60.0, h = 66.0; // 与 _LayeredFloatView 的尺寸一致
|
||||
return Rect.fromLTWH(origin.dx + box.size.width - w, origin.dy + box.size.height - h, w, h);
|
||||
return Rect.fromLTWH(
|
||||
origin.dx + box.size.width - w, origin.dy + box.size.height - h, w, h);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -104,7 +105,8 @@ class _GuideHomeDialogState extends State<GuideHomeDialog> {
|
||||
imageUrl: config.homePage ?? "",
|
||||
fit: BoxFit.fill,
|
||||
borderRadius: 0,
|
||||
placeHolderWidget: Container(color: const Color(0x00000000)),
|
||||
placeHolderWidget:
|
||||
Container(color: const Color(0x00000000)),
|
||||
),
|
||||
// 倒计时胶囊:海报右上角,听 tick 每秒刷新,过期自动收起
|
||||
Positioned(
|
||||
@@ -112,7 +114,10 @@ class _GuideHomeDialogState extends State<GuideHomeDialog> {
|
||||
right: 0,
|
||||
child: ValueListenableBuilder<int>(
|
||||
valueListenable: MineMsgProvider().tick,
|
||||
builder: (_, __, ___) => config.hasDiscountCountdown ? _buildCountdownPill() : const SizedBox.shrink(),
|
||||
builder: (_, __, ___) =>
|
||||
config.hasDiscountCountdown
|
||||
? _buildCountdownPill()
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -123,7 +128,8 @@ class _GuideHomeDialogState extends State<GuideHomeDialog> {
|
||||
20.sizeBoxH,
|
||||
GestureDetector(
|
||||
onTap: _close,
|
||||
child: Image.asset("close_button.png".commonImgPath, width: 32),
|
||||
child: Image.asset("close_button.png".commonImgPath,
|
||||
width: 32),
|
||||
)
|
||||
],
|
||||
),
|
||||
@@ -149,7 +155,10 @@ class _GuideHomeDialogState extends State<GuideHomeDialog> {
|
||||
),
|
||||
child: Text(
|
||||
'${config.discountHour}:${config.discountMin}:${config.discountSec}',
|
||||
style: const TextStyle(color: Color(0xffFFF0D1), fontSize: 20, fontWeight: FontWeight.w600),
|
||||
style: const TextStyle(
|
||||
color: Color(0xffFFF0D1),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/splash/domain_source_model.dart';
|
||||
import 'package:wydj/hj_model/splash/domain_source_model.dart';
|
||||
|
||||
import '../../hj_page/main_page/provider/msg_provider.dart';
|
||||
import 'guide_config.dart';
|
||||
@@ -45,8 +45,12 @@ class GuideManager {
|
||||
/// 请求还没回来,硬判成老用户会让新用户永远错过新人引导,且 _adShown 保证不会再有第二次
|
||||
GuideScene? get homeScene {
|
||||
final tier = MineMsgProvider().payTier?.status;
|
||||
if (tier == null) return [GuideScene.homeNewUser, GuideScene.homeOldUser].firstWhereOrNull(canShow);
|
||||
final scene = tier == PayTier.newUnpay ? GuideScene.homeNewUser : GuideScene.homeOldUser;
|
||||
if (tier == null)
|
||||
return [GuideScene.homeNewUser, GuideScene.homeOldUser]
|
||||
.firstWhereOrNull(canShow);
|
||||
final scene = tier == PayTier.newUnpay
|
||||
? GuideScene.homeNewUser
|
||||
: GuideScene.homeOldUser;
|
||||
return canShow(scene) ? scene : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import '../hj_model/splash/domain_source_model.dart';
|
||||
/// 全局配置:常量 + 启动时由 /ping/domain 下发并缓存的运营配置
|
||||
class Config {
|
||||
// ===== 应用标识 =====
|
||||
static const appName = '黄果漫剧';
|
||||
static const appName = '51短剧';
|
||||
static const appId = 'JHAc-214'; // 埋点app id
|
||||
static const innerVersion = '2.0.0';
|
||||
static const isDebug = false;
|
||||
@@ -21,7 +21,7 @@ class Config {
|
||||
static const signKey = 'kaFtkDJRcchRMTI9';
|
||||
|
||||
// ===== 域名 / 线路 =====
|
||||
static String dns = 'hgmj.mfcg.it.com'; // 运维提供,返回配置域名(TXT 查询,只填域名不带 https://)
|
||||
static String dns = 'wydj.mfcg.it.com'; // 运维提供,返回配置域名(TXT 查询,只填域名不带 https://)
|
||||
|
||||
/// 本地兜底线路(无本地缓存线路时用)
|
||||
static const lineList = isDebug
|
||||
@@ -43,11 +43,12 @@ class Config {
|
||||
// ===== 首页模块数据 =====
|
||||
static HomePlateModel? plateModule; // 亚模块数据
|
||||
static List<JGAreaModel>? jgArea; // 金刚区
|
||||
static List<MarqueeModel>? marquees; // 新版跑马灯数据
|
||||
static List<MarqueeModel>? marquees; // 新版跑马灯数据
|
||||
static List<MarqueeModel>? get marqueesActive {
|
||||
// 新版跑马灯数据 激活的
|
||||
return marquees?.where((e) => e.active == true).toList();
|
||||
}
|
||||
|
||||
static List<BannerJumpEntity> bannerJumps = [];
|
||||
static BannerJump? proxyBanner;
|
||||
|
||||
@@ -66,7 +67,8 @@ class Config {
|
||||
// ===== 短剧 =====
|
||||
static String? shortDramaCardId; // 短剧卡 id,付费墙拉起会员弹窗时默认选中它
|
||||
static bool entryPopupEnabled = true; // 「AI爽剧来袭」引导气泡开关,后台置 false 即永久不出现
|
||||
static bool isDramaEntry = false; // ping 的 defaultEntryPage==drama:启动直接落在短剧 tab
|
||||
static bool isDramaEntry =
|
||||
false; // ping 的 defaultEntryPage==drama:启动直接落在短剧 tab
|
||||
|
||||
// ===== 开关 / 展示配置 =====
|
||||
static bool isStoreOpen = false; // 商店模块开关
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:hgmj/hj_model/actress_info.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_model/actress_info.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
|
||||
import '../cartoon_media_info.dart';
|
||||
import 'package:hgmj/hj_utils/text_util.dart';
|
||||
import 'package:wydj/hj_utils/text_util.dart';
|
||||
|
||||
class AllMediaInfo {
|
||||
List<Content>? contents;
|
||||
@@ -21,11 +21,15 @@ class AllMediaInfo {
|
||||
List<ActressInfo>? allActress;
|
||||
|
||||
String? get coverH {
|
||||
return (horizontalCover?.isNotEmpty == true) ? horizontalCover : verticalCover;
|
||||
return (horizontalCover?.isNotEmpty == true)
|
||||
? horizontalCover
|
||||
: verticalCover;
|
||||
}
|
||||
|
||||
String? get coverV {
|
||||
return (verticalCover?.isNotEmpty == true) ? verticalCover : horizontalCover;
|
||||
return (verticalCover?.isNotEmpty == true)
|
||||
? verticalCover
|
||||
: horizontalCover;
|
||||
}
|
||||
|
||||
String? id;
|
||||
@@ -117,7 +121,9 @@ class AllMediaInfo {
|
||||
}
|
||||
|
||||
AllMediaInfo.fromJson(Map<String, dynamic> json) {
|
||||
contents = json["contents"] == null ? [] : List<Content>.from(json["contents"]!.map((x) => Content.fromJson(x)));
|
||||
contents = json["contents"] == null
|
||||
? []
|
||||
: List<Content>.from(json["contents"]!.map((x) => Content.fromJson(x)));
|
||||
countBrowse = json["countBrowse"];
|
||||
countCollect = json["countCollect"];
|
||||
countComment = json["countComment"];
|
||||
@@ -130,11 +136,16 @@ class AllMediaInfo {
|
||||
freeTime = json["freeTime"];
|
||||
hasFollow = json["hasFollow"];
|
||||
horizontalCover = json["horizontalCover"];
|
||||
allActress = json["actresses"] == null ? [] : List<ActressInfo>.from(json["actresses"]!.map((x) => ActressInfo.fromJson(x)));
|
||||
allActress = json["actresses"] == null
|
||||
? []
|
||||
: List<ActressInfo>.from(
|
||||
json["actresses"]!.map((x) => ActressInfo.fromJson(x)));
|
||||
id = json["id"];
|
||||
kind = json["kind"];
|
||||
mId = json["mId"];
|
||||
mediaStatus = json["mediaStatus"] == null ? null : VidStatus.fromMap(json["mediaStatus"]);
|
||||
mediaStatus = json["mediaStatus"] == null
|
||||
? null
|
||||
: VidStatus.fromMap(json["mediaStatus"]);
|
||||
mediaType = json["mediaType"];
|
||||
moduleName = json["moduleName"];
|
||||
number = json["number"];
|
||||
@@ -148,7 +159,10 @@ class AllMediaInfo {
|
||||
sortCode = json["sortCode"];
|
||||
status = json["status"];
|
||||
summary = json["summary"];
|
||||
tagDetails = json["tagDetails"] == null ? [] : List<TagsBean>.from(json["tagDetails"]!.map((x) => TagsBean.fromMap(x)));
|
||||
tagDetails = json["tagDetails"] == null
|
||||
? []
|
||||
: List<TagsBean>.from(
|
||||
json["tagDetails"]!.map((x) => TagsBean.fromMap(x)));
|
||||
tags = parseStringList(json["tags"]);
|
||||
title = json["title"];
|
||||
totalEpisode = json["totalEpisode"];
|
||||
@@ -230,7 +244,9 @@ class Content {
|
||||
md5 = json["md5"];
|
||||
mediaId = json["mediaId"];
|
||||
mediaSize = json["mediaSize"];
|
||||
mediaStatus = json["mediaStatus"] == null ? null : VidStatus.fromMap(json["mediaStatus"]);
|
||||
mediaStatus = json["mediaStatus"] == null
|
||||
? null
|
||||
: VidStatus.fromMap(json["mediaStatus"]);
|
||||
name = json["name"];
|
||||
playTime = json["playTime"];
|
||||
price = json["price"];
|
||||
@@ -265,7 +281,8 @@ class Content {
|
||||
"ratio": ratio,
|
||||
"text": text,
|
||||
"updateTime": updateTime,
|
||||
"urlSet": urlSet == null ? [] : List<dynamic>.from(urlSet!.map((x) => x)),
|
||||
"urlSet":
|
||||
urlSet == null ? [] : List<dynamic>.from(urlSet!.map((x) => x)),
|
||||
"videoUrl": videoUrl,
|
||||
"weight": weight,
|
||||
};
|
||||
@@ -282,8 +299,12 @@ class MediaSearchListModel {
|
||||
|
||||
MediaSearchListModel.fromJson(dynamic json) {
|
||||
hasNext = json['hasNext'];
|
||||
list = (json['list'] as List?)?.map((v) => CartoonMediaInfo.fromJson(v)).toList();
|
||||
tagMedia = (json['tagMedia'] as List?)?.map((v) => CartoonMediaInfo.fromJson(v)).toList();
|
||||
list = (json['list'] as List?)
|
||||
?.map((v) => CartoonMediaInfo.fromJson(v))
|
||||
.toList();
|
||||
tagMedia = (json['tagMedia'] as List?)
|
||||
?.map((v) => CartoonMediaInfo.fromJson(v))
|
||||
.toList();
|
||||
tagId = json['tagId'];
|
||||
total = json['total'];
|
||||
}
|
||||
@@ -298,4 +319,3 @@ class MediaSearchListModel {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//漫画章节
|
||||
import 'package:hgmj/config/address.dart' as address;
|
||||
import 'package:wydj/config/address.dart' as address;
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import '../media_content.dart';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:hgmj/hj_utils/text_util.dart';
|
||||
|
||||
import 'package:wydj/hj_utils/text_util.dart';
|
||||
|
||||
class ActressInfo {
|
||||
String? age;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hgmj/hj_model/actress_info.dart';
|
||||
import 'package:wydj/hj_model/actress_info.dart';
|
||||
|
||||
class ActressModel {
|
||||
ActressModel({
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_model/drama_media_info.dart';
|
||||
import 'package:hgmj/hj_model/splash/ads_model.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/hj_model/drama_media_info.dart';
|
||||
import 'package:wydj/hj_model/splash/ads_model.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
|
||||
import 'acg/comic_chapters_model.dart';
|
||||
import 'actress_info.dart';
|
||||
@@ -30,7 +30,8 @@ class CartoonMediaInfo {
|
||||
int? totalEpisode; //总集数
|
||||
int? currentEpisode; //当前集数
|
||||
int? freeEpisode; //免费集数
|
||||
bool isCartoonFreeEpisode = false; //当前播放集是否属于免费集(前 freeEpisode 集):运行时按当前集号计算,命中则不拦播、进度可全程拖
|
||||
bool isCartoonFreeEpisode =
|
||||
false; //当前播放集是否属于免费集(前 freeEpisode 集):运行时按当前集号计算,命中则不拦播、进度可全程拖
|
||||
int? updateStatus; //更新状态 0 默认 1、更新中 2、已完结
|
||||
String? updateTime; //文档更新时间
|
||||
String? createdAt; //文档创建时间
|
||||
@@ -86,16 +87,19 @@ class CartoonMediaInfo {
|
||||
bool isSelected = false; // 是否选中
|
||||
String? heroTag; //本地字段,用于传递hero动画tag 随机数
|
||||
|
||||
String? get coverH => horizontalCover?.isNotEmpty == true ? horizontalCover : verticalCover;
|
||||
String? get coverH =>
|
||||
horizontalCover?.isNotEmpty == true ? horizontalCover : verticalCover;
|
||||
|
||||
String? get coverV => verticalCover?.isNotEmpty == true ? verticalCover : horizontalCover;
|
||||
String? get coverV =>
|
||||
verticalCover?.isNotEmpty == true ? verticalCover : horizontalCover;
|
||||
|
||||
String get unit => mediaType == 'image' ? '话' : '章';
|
||||
//更新状态
|
||||
String get updateDesc => updateStatus == 1 ? '连载中' : '已完结';
|
||||
|
||||
String get tagIds => tagDetails?.map((e) => e.id).toList().join(',') ?? '';
|
||||
String get tagNames => tagDetails?.map((e) => e.name).toList().join(',') ?? '';
|
||||
String get tagNames =>
|
||||
tagDetails?.map((e) => e.name).toList().join(',') ?? '';
|
||||
|
||||
//更新状态
|
||||
String get getDetailUpdateString {
|
||||
@@ -237,50 +241,51 @@ class CartoonMediaInfo {
|
||||
globalStore.isSuperUp;
|
||||
}
|
||||
|
||||
CartoonMediaInfo(
|
||||
{this.contents,
|
||||
this.choiceSort,
|
||||
this.countBrowse,
|
||||
this.countCollect,
|
||||
this.countComment,
|
||||
this.countLike,
|
||||
this.countPurchases,
|
||||
this.countPurchasesRate,
|
||||
this.countView,
|
||||
this.createdAt,
|
||||
this.direction,
|
||||
this.freeTime,
|
||||
this.horizontalCover,
|
||||
this.id,
|
||||
this.isDelete,
|
||||
this.kind,
|
||||
this.mId,
|
||||
this.mediaType,
|
||||
this.moduleName,
|
||||
this.permission,
|
||||
this.permissionIconHide,
|
||||
this.price,
|
||||
this.sId,
|
||||
this.discountPrice,
|
||||
this.sectionName,
|
||||
this.sectionSort,
|
||||
this.sortCode,
|
||||
this.status,
|
||||
this.summary,
|
||||
this.tagDetails,
|
||||
this.title,
|
||||
this.totalEpisode,
|
||||
this.currentEpisode,
|
||||
this.updateStatus,
|
||||
this.updateTime,
|
||||
this.updatedAct,
|
||||
this.verticalCover,
|
||||
this.author,
|
||||
this.freeEpisode,
|
||||
this.contentsPrice,
|
||||
this.mediaSubType,
|
||||
this.actress,
|
||||
this.hot,});
|
||||
CartoonMediaInfo({
|
||||
this.contents,
|
||||
this.choiceSort,
|
||||
this.countBrowse,
|
||||
this.countCollect,
|
||||
this.countComment,
|
||||
this.countLike,
|
||||
this.countPurchases,
|
||||
this.countPurchasesRate,
|
||||
this.countView,
|
||||
this.createdAt,
|
||||
this.direction,
|
||||
this.freeTime,
|
||||
this.horizontalCover,
|
||||
this.id,
|
||||
this.isDelete,
|
||||
this.kind,
|
||||
this.mId,
|
||||
this.mediaType,
|
||||
this.moduleName,
|
||||
this.permission,
|
||||
this.permissionIconHide,
|
||||
this.price,
|
||||
this.sId,
|
||||
this.discountPrice,
|
||||
this.sectionName,
|
||||
this.sectionSort,
|
||||
this.sortCode,
|
||||
this.status,
|
||||
this.summary,
|
||||
this.tagDetails,
|
||||
this.title,
|
||||
this.totalEpisode,
|
||||
this.currentEpisode,
|
||||
this.updateStatus,
|
||||
this.updateTime,
|
||||
this.updatedAct,
|
||||
this.verticalCover,
|
||||
this.author,
|
||||
this.freeEpisode,
|
||||
this.contentsPrice,
|
||||
this.mediaSubType,
|
||||
this.actress,
|
||||
this.hot,
|
||||
});
|
||||
|
||||
CartoonMediaInfo.fromJson(dynamic json) {
|
||||
freeEpisode = json['freeEpisode'];
|
||||
@@ -321,11 +326,15 @@ class CartoonMediaInfo {
|
||||
status = json['status'];
|
||||
summary = json['summary'];
|
||||
lsjId = json['lsjId'];
|
||||
actress = json["actress"] == null ? null : ActressInfo.fromJson(json["actress"]);
|
||||
allActress = json["actresses"] == null ? [] : List<ActressInfo>.from(json["actresses"]!.map((x) => ActressInfo.fromJson(x)));
|
||||
actress =
|
||||
json["actress"] == null ? null : ActressInfo.fromJson(json["actress"]);
|
||||
allActress = json["actresses"] == null
|
||||
? []
|
||||
: List<ActressInfo>.from(
|
||||
json["actresses"]!.map((x) => ActressInfo.fromJson(x)));
|
||||
hasFollow = json['hasFollow'];
|
||||
final hot = json['hot'];
|
||||
if(hot is int) {
|
||||
if (hot is int) {
|
||||
this.hot = hot;
|
||||
}
|
||||
if (json['tagDetails'] != null) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hgmj/hj_model/comment/comment_model.dart';
|
||||
import 'package:wydj/hj_model/comment/comment_model.dart';
|
||||
|
||||
///评论列表返回信息
|
||||
class CommentListRes {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hgmj/hj_model/comment/reply_model.dart';
|
||||
import 'package:wydj/hj_model/comment/reply_model.dart';
|
||||
|
||||
class CommentModel {
|
||||
String? id;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:hgmj/hj_model/drama_media_info.dart';
|
||||
import 'package:hgmj/hj_model/media_content.dart';
|
||||
import 'package:wydj/hj_model/drama_media_info.dart';
|
||||
import 'package:wydj/hj_model/media_content.dart';
|
||||
|
||||
/// 一条短剧观看记录:续播位置 + 列表展示用的剧信息快照。本地记录,不走后端,见 [DramaResumeStore]。
|
||||
/// 落库时整条存成 model_data,所以 [mediaId] 必须写进 json——
|
||||
@@ -29,7 +29,9 @@ class DramaResume {
|
||||
: mediaId = json?['mediaId'] ?? '',
|
||||
contentId = json?['contentId'] ?? '',
|
||||
progressSeconds = json?['progressSeconds'] ?? 0,
|
||||
drama = json?['drama'] == null ? null : DramaMediaInfo.fromJson(json['drama']),
|
||||
drama = json?['drama'] == null
|
||||
? null
|
||||
: DramaMediaInfo.fromJson(json['drama']),
|
||||
watchedAt = json?['watchedAt'] ?? 0;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
@@ -62,9 +64,12 @@ class DramaPaywall {
|
||||
|
||||
String get titleUI => title?.isNotEmpty == true ? title! : '更多精彩解锁即享';
|
||||
|
||||
String get coinButtonUI => coinButtonText?.isNotEmpty == true ? coinButtonText! : '${unlockCoin ?? 0}金币解锁';
|
||||
String get coinButtonUI => coinButtonText?.isNotEmpty == true
|
||||
? coinButtonText!
|
||||
: '${unlockCoin ?? 0}金币解锁';
|
||||
|
||||
String get cardButtonUI => cardButtonText?.isNotEmpty == true ? cardButtonText! : '开通短剧卡免费看';
|
||||
String get cardButtonUI =>
|
||||
cardButtonText?.isNotEmpty == true ? cardButtonText! : '开通短剧卡免费看';
|
||||
}
|
||||
|
||||
/// AI短剧 Feed 的一条:某部剧 + 该剧第一集。整页走 ListBaseModel<DramaFeedItem>
|
||||
@@ -76,7 +81,8 @@ class DramaFeedItem {
|
||||
json ??= {};
|
||||
//缺 media 就不造空模型,上层按 null 过滤掉这条,别让信息流多出一个没剧名没地址的空位
|
||||
if (json['media'] != null) media = DramaMediaInfo.fromJson(json['media']);
|
||||
if (json['content'] != null) content = MediaContent.fromJson(json['content']);
|
||||
if (json['content'] != null)
|
||||
content = MediaContent.fromJson(json['content']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +110,12 @@ class DramaTopic {
|
||||
name = json['name']?.toString();
|
||||
topicType = json['topicType']?.toString();
|
||||
systemKey = json['systemKey']?.toString();
|
||||
sort = json['sort'] is int ? json['sort'] as int : int.tryParse('${json['sort'] ?? ''}');
|
||||
workCount =
|
||||
json['workCount'] is int ? json['workCount'] as int : int.tryParse('${json['workCount'] ?? ''}');
|
||||
sort = json['sort'] is int
|
||||
? json['sort'] as int
|
||||
: int.tryParse('${json['sort'] ?? ''}');
|
||||
workCount = json['workCount'] is int
|
||||
? json['workCount'] as int
|
||||
: int.tryParse('${json['workCount'] ?? ''}');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,9 +130,14 @@ class DramaSearchResult {
|
||||
json ??= {};
|
||||
hasNext = json['hasNext'] == true;
|
||||
tagID = json['tagID']?.toString();
|
||||
list = (json['list'] as List?)?.map((e) => DramaMediaInfo.fromJson(e)).toList() ?? [];
|
||||
tagMediaList =
|
||||
(json['tagMediaList'] as List?)?.map((e) => DramaMediaInfo.fromJson(e)).toList() ?? [];
|
||||
list = (json['list'] as List?)
|
||||
?.map((e) => DramaMediaInfo.fromJson(e))
|
||||
.toList() ??
|
||||
[];
|
||||
tagMediaList = (json['tagMediaList'] as List?)
|
||||
?.map((e) => DramaMediaInfo.fromJson(e))
|
||||
.toList() ??
|
||||
[];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_model/media_content.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/hj_model/media_content.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
|
||||
/// 短剧作品信息(接口 DramaInfo:一部剧 + 一堆分集)
|
||||
/// 单集播放数据用 [toVideoModel] 转成 VideoModel 交给短视频播放器
|
||||
@@ -72,9 +72,11 @@ class DramaMediaInfo {
|
||||
bool haxNextEpisode = true; //是否还有下一页
|
||||
bool isSelected = false; //是否选中
|
||||
|
||||
String? get coverH => horizontalCover?.isNotEmpty == true ? horizontalCover : verticalCover;
|
||||
String? get coverH =>
|
||||
horizontalCover?.isNotEmpty == true ? horizontalCover : verticalCover;
|
||||
|
||||
String? get coverV => verticalCover?.isNotEmpty == true ? verticalCover : horizontalCover;
|
||||
String? get coverV =>
|
||||
verticalCover?.isNotEmpty == true ? verticalCover : horizontalCover;
|
||||
|
||||
String get unit => '集';
|
||||
|
||||
@@ -83,9 +85,11 @@ class DramaMediaInfo {
|
||||
|
||||
String get tagIds => tagDetails?.map((e) => e.id).toList().join(',') ?? '';
|
||||
|
||||
String get tagNames => tagDetails?.map((e) => e.name).toList().join(',') ?? '';
|
||||
String get tagNames =>
|
||||
tagDetails?.map((e) => e.name).toList().join(',') ?? '';
|
||||
|
||||
Color get updateDescColor => updateStatus == 1 ? AppColors.actionRed : const Color(0xff989898);
|
||||
Color get updateDescColor =>
|
||||
updateStatus == 1 ? AppColors.actionRed : const Color(0xff989898);
|
||||
|
||||
//集数状态描述
|
||||
String get episodeNumberStatus {
|
||||
@@ -172,13 +176,14 @@ class DramaMediaInfo {
|
||||
countView = json['countView'];
|
||||
hasFollow = json['hasFollow'];
|
||||
final hot = json['hot'];
|
||||
if(hot is int) {
|
||||
if (hot is int) {
|
||||
this.hot = hot;
|
||||
}
|
||||
direction = json['direction'];
|
||||
freeTime = json['freeTime'];
|
||||
mediaStatus = VidStatus.fromMap(json['mediaStatus']);
|
||||
tagDetails = (json['tagDetails'] as List?)?.map((e) => TagsBean.fromMap(e)).toList();
|
||||
tagDetails =
|
||||
(json['tagDetails'] as List?)?.map((e) => TagsBean.fromMap(e)).toList();
|
||||
}
|
||||
|
||||
/// 落本地观看记录用(见 [DramaResume.drama])。只序列化后端字段,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
|
||||
//亚模块模型
|
||||
class ModuleData {
|
||||
@@ -41,6 +41,7 @@ class ModuleData {
|
||||
bool get isACG => type == 4 || type == 5 || type == 6;
|
||||
//短剧
|
||||
bool get isDrama => type == 12;
|
||||
|
||||
/// 展示用的排序项:top=true 的置顶,最多 4 个。
|
||||
/// 标题、sort 值、随机刷新配置一律从这份派生——分头各排一次,遇到同名/同值 remove 会删错元素,两边就对不上了。
|
||||
/// haiJiaoStyle 解析完就不再变,算一次存起来,别每个 getter 各构造一遍
|
||||
@@ -53,10 +54,13 @@ class ModuleData {
|
||||
|
||||
/// 排序 tab(标题 + sort 值),为空返回 null 让调用方退回默认值。
|
||||
/// 标题和 sort 值必须一起产出:拆成两个并行数组时,后端只下发其中一个就会静默错位
|
||||
List<SortTab<int>>? get sortTabs => _sortedRules.isEmpty ? null : _sortedRules.map((e) => SortTab(e.name ?? '', e.val ?? -1)).toList();
|
||||
List<SortTab<int>>? get sortTabs => _sortedRules.isEmpty
|
||||
? null
|
||||
: _sortedRules.map((e) => SortTab(e.name ?? '', e.val ?? -1)).toList();
|
||||
|
||||
/// 按 sort 值取对应的排序规则(用于判断该排序项是否走随机刷新接口)
|
||||
SortRuleModel? sortRuleOf(int? val) => _sortedRules.firstWhereOrNull((e) => e.val == val);
|
||||
SortRuleModel? sortRuleOf(int? val) =>
|
||||
_sortedRules.firstWhereOrNull((e) => e.val == val);
|
||||
}
|
||||
|
||||
class HaiJiaoStyle {
|
||||
@@ -73,7 +77,8 @@ class HaiJiaoStyle {
|
||||
showChosenVideo = json['showChosenVideo'];
|
||||
sortShow = json['sortShow'];
|
||||
final rules = json['sortRules'];
|
||||
if (rules is List) sortRules = rules.map((e) => SortRuleModel.fromJson(e)).toList();
|
||||
if (rules is List)
|
||||
sortRules = rules.map((e) => SortRuleModel.fromJson(e)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,5 +134,8 @@ class HomePlateModel {
|
||||
}
|
||||
|
||||
//字段缺失或类型不对(后端偶发下发非数组)都退化成空列表,别让首页解析整个抛掉
|
||||
static List<ModuleData> _modules(dynamic list) => (list is List ? list : const []).map((e) => ModuleData.fromJson(e)).toList();
|
||||
static List<ModuleData> _modules(dynamic list) =>
|
||||
(list is List ? list : const [])
|
||||
.map((e) => ModuleData.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:hgmj/hj_model/home/module_detail_model.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_model/home/module_detail_model.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
|
||||
//注意⚠️ VideoListResp 只用于兼容不同业务服务端返回的视频列表 key 不一致的情况
|
||||
//注意⚠️ 请勿添加其他类型的数据list,如需添加请单独另外创建新的类
|
||||
@@ -15,14 +15,24 @@ class VideoListResp {
|
||||
json ??= {};
|
||||
hasNext = json['hasNext'];
|
||||
//各业务的视频列表 key 不一样,逐个匹配(后命中的覆盖先命中的)
|
||||
for (final key in ['videos', 'vInfos', 'searchVideo', 'list', 'data', 'searchTag']) {
|
||||
for (final key in [
|
||||
'videos',
|
||||
'vInfos',
|
||||
'searchVideo',
|
||||
'list',
|
||||
'data',
|
||||
'searchTag'
|
||||
]) {
|
||||
if (json[key] is List) {
|
||||
videos = (json[key] as List).map((e) => VideoModel.fromJson(e)).toList();
|
||||
videos =
|
||||
(json[key] as List).map((e) => VideoModel.fromJson(e)).toList();
|
||||
}
|
||||
}
|
||||
tagID = json['tagID'] ?? json['libraryTag']?['id'];
|
||||
if (json['tagVidList'] is List) {
|
||||
tagVidList = (json['tagVidList'] as List).map((e) => VideoModel.fromJson(e)).toList();
|
||||
tagVidList = (json['tagVidList'] as List)
|
||||
.map((e) => VideoModel.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,4 +51,3 @@ class SectionListResp {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import 'package:hgmj/hj_model/acg/comic_chapters_model.dart';
|
||||
import 'package:hgmj/hj_model/actress_model.dart';
|
||||
import 'package:hgmj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:hgmj/hj_model/drama/drama_models.dart';
|
||||
import 'package:hgmj/hj_model/drama_media_info.dart';
|
||||
import 'package:hgmj/hj_model/comment/reply_model.dart';
|
||||
import 'package:hgmj/hj_model/comment/user_comment_res.dart';
|
||||
import 'package:hgmj/hj_model/home/collection_model.dart';
|
||||
import 'package:hgmj/hj_model/media_content.dart';
|
||||
import 'package:hgmj/hj_model/message/message_dynamic_list.dart';
|
||||
import 'package:hgmj/hj_model/mine/exchange/bill_item_model.dart';
|
||||
import 'package:hgmj/hj_model/mine/follow_user_list_model.dart';
|
||||
import 'package:hgmj/hj_model/mine/promotion_record.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_model/acg/comic_chapters_model.dart';
|
||||
import 'package:wydj/hj_model/actress_model.dart';
|
||||
import 'package:wydj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:wydj/hj_model/drama/drama_models.dart';
|
||||
import 'package:wydj/hj_model/drama_media_info.dart';
|
||||
import 'package:wydj/hj_model/comment/reply_model.dart';
|
||||
import 'package:wydj/hj_model/comment/user_comment_res.dart';
|
||||
import 'package:wydj/hj_model/home/collection_model.dart';
|
||||
import 'package:wydj/hj_model/media_content.dart';
|
||||
import 'package:wydj/hj_model/message/message_dynamic_list.dart';
|
||||
import 'package:wydj/hj_model/mine/exchange/bill_item_model.dart';
|
||||
import 'package:wydj/hj_model/mine/follow_user_list_model.dart';
|
||||
import 'package:wydj/hj_model/mine/promotion_record.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
|
||||
import '../hj_page/ai/models/ai_change_face_video_model.dart';
|
||||
import '../hj_page/ai/models/ai_record_model.dart';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:hgmj/config/address.dart' as address;
|
||||
import 'package:hgmj/hj_model/drama/drama_models.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:wydj/config/address.dart' as address;
|
||||
import 'package:wydj/hj_model/drama/drama_models.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
/// 作品的「一集」:漫画一话 / 小说一章 / 有声一集 / 短剧一集 共用这一个模型,
|
||||
@@ -73,7 +73,8 @@ class MediaContent {
|
||||
audioUrl = json['audioUrl'];
|
||||
//用 is List 判而不是 as List:下发 null 或非数组时硬 cast 会抛,整条分集就解析不出来
|
||||
final rawUrlSet = json['urlSet'];
|
||||
urlSet = rawUrlSet is List ? rawUrlSet.map((e) => e.toString()).toList() : [];
|
||||
urlSet =
|
||||
rawUrlSet is List ? rawUrlSet.map((e) => e.toString()).toList() : [];
|
||||
text = json['text'];
|
||||
md5 = json['md5'];
|
||||
playTime = json['playTime'];
|
||||
@@ -82,7 +83,9 @@ class MediaContent {
|
||||
weight = json['weight'];
|
||||
//数字直接转;后端也可能下发字符串("1.5"),那时才走 parse,脏值落 null
|
||||
final rawRatio = json['ratio'];
|
||||
ratio = rawRatio is num ? rawRatio.toDouble() : double.tryParse(rawRatio?.toString() ?? '');
|
||||
ratio = rawRatio is num
|
||||
? rawRatio.toDouble()
|
||||
: double.tryParse(rawRatio?.toString() ?? '');
|
||||
|
||||
listenPermission = json['listenPermission'];
|
||||
price = json['price'];
|
||||
@@ -90,7 +93,8 @@ class MediaContent {
|
||||
isFree = json['isFree'];
|
||||
canPlay = json['canPlay'];
|
||||
accessType = json['accessType'];
|
||||
paywall = json['paywall'] != null ? DramaPaywall.fromJson(json['paywall']) : null;
|
||||
paywall =
|
||||
json['paywall'] != null ? DramaPaywall.fromJson(json['paywall']) : null;
|
||||
isActive = json['isActive'];
|
||||
|
||||
previewEnabled = json['previewEnabled'];
|
||||
@@ -105,7 +109,9 @@ class MediaContent {
|
||||
countDisLike = json['countDisLike'];
|
||||
countLike = json['countLike'];
|
||||
countPurchases = json['countPurchases'];
|
||||
mediaStatus = json['mediaStatus'] != null ? VidStatus.fromMap(json['mediaStatus']) : null;
|
||||
mediaStatus = json['mediaStatus'] != null
|
||||
? VidStatus.fromMap(json['mediaStatus'])
|
||||
: null;
|
||||
|
||||
createdAt = json['createdAt'];
|
||||
updateTime = json['updateTime'];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hgmj/hj_model/mine/exchange/recharge_type_list_model.dart';
|
||||
import 'package:wydj/hj_model/mine/exchange/recharge_type_list_model.dart';
|
||||
|
||||
import 'dc_model.dart';
|
||||
|
||||
@@ -11,6 +11,8 @@ class RechargeListModel {
|
||||
json ??= {};
|
||||
daichong = DCModel.fromJson(json['daichong']);
|
||||
//代充数据挂在上级,逐条塞给档位,档位内部才能拼出代充支付方式
|
||||
list = (json['list'] as List?)?.map((e) => RechargeTypeModel.fromJson(e)..daichong = daichong).toList();
|
||||
list = (json['list'] as List?)
|
||||
?.map((e) => RechargeTypeModel.fromJson(e)..daichong = daichong)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hgmj/hj_model/splash/ads_model.dart';
|
||||
import 'package:wydj/hj_model/splash/ads_model.dart';
|
||||
|
||||
class AdGroup {
|
||||
final List<AdsInfoModel>? items;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
|
||||
import '../../alert/vip_guide/guide_manager.dart';
|
||||
import '../../config/config.dart';
|
||||
@@ -20,7 +20,9 @@ class AdvanceStatus {
|
||||
balancePayment = json['balancePayment'];
|
||||
activityPopUp = json['activityPopUp'];
|
||||
oid = json['oid'];
|
||||
privilegeLimit = json['privilegeLimit'] != null ? PrivilegeLimit.fromJson(json['privilegeLimit']) : null;
|
||||
privilegeLimit = json['privilegeLimit'] != null
|
||||
? PrivilegeLimit.fromJson(json['privilegeLimit'])
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +45,10 @@ class Remain {
|
||||
int? todayCoinVideoCount; //今日剩余金币视频观看次数
|
||||
int? todayDownloadCount; //今日剩余下载次数
|
||||
|
||||
Remain({this.todayAiUndressCount, this.todayCoinVideoCount, this.todayDownloadCount});
|
||||
Remain(
|
||||
{this.todayAiUndressCount,
|
||||
this.todayCoinVideoCount,
|
||||
this.todayDownloadCount});
|
||||
|
||||
Remain.fromJson(Map<String, dynamic> json) {
|
||||
todayAiUndressCount = json['todayAiUndressCount'];
|
||||
@@ -63,7 +68,8 @@ class BannerJump {
|
||||
BannerJump({this.additionalProp});
|
||||
|
||||
BannerJump.fromJson(Map<String, dynamic> json, {String key = '1'}) {
|
||||
additionalProp = json[key] != null ? AdditionalProp.fromJson(json[key]) : null;
|
||||
additionalProp =
|
||||
json[key] != null ? AdditionalProp.fromJson(json[key]) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +83,15 @@ class AdditionalProp {
|
||||
String? endAt; //结束时间
|
||||
int? countdownType;
|
||||
|
||||
AdditionalProp({this.id, this.banner, this.endAt, this.position, this.startAt, this.title, this.url, this.countdownType});
|
||||
AdditionalProp(
|
||||
{this.id,
|
||||
this.banner,
|
||||
this.endAt,
|
||||
this.position,
|
||||
this.startAt,
|
||||
this.title,
|
||||
this.url,
|
||||
this.countdownType});
|
||||
|
||||
AdditionalProp.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
@@ -159,15 +173,23 @@ class DomainSourceModel {
|
||||
Config.darkWebIcon = map['darkWebIcon'];
|
||||
Config.darkWebIconName = map['darkWebIconName'];
|
||||
Config.mineBg = map['personalCenterBackground'];
|
||||
Config.entryPopupEnabled = map['shortDramaEntryPopupEnabled'] ?? true; //短剧引导气泡,字段缺失当开启
|
||||
Config.isDramaEntry = map['defaultEntryPage'] == 'drama'; //默认进哪个 tab,缺字段/其它值都按主页
|
||||
MineMsgProvider().payTier = PayTierModel.fromJson(map); //支付状态分层(各展示位图片/卡ID/倒计时)
|
||||
Config.entryPopupEnabled =
|
||||
map['shortDramaEntryPopupEnabled'] ?? true; //短剧引导气泡,字段缺失当开启
|
||||
Config.isDramaEntry =
|
||||
map['defaultEntryPage'] == 'drama'; //默认进哪个 tab,缺字段/其它值都按主页
|
||||
MineMsgProvider().payTier =
|
||||
PayTierModel.fromJson(map); //支付状态分层(各展示位图片/卡ID/倒计时)
|
||||
GuideManager().update(map['paymentGuide']); //付费引导各场景开关(弹窗一律读缓存,不再临时查接口)
|
||||
if (map['aiSwitchConf'] is List) {
|
||||
Config.aiTypes = (map['aiSwitchConf'] as List).map((e) => AISwitchConf.fromJson(e)).toList();
|
||||
Config.aiTypes = (map['aiSwitchConf'] as List)
|
||||
.map((e) => AISwitchConf.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
if (map.containsKey('bannerJumpList')) {
|
||||
Config.bannerJumps = (map['bannerJumpList'] as List?)?.map((o) => BannerJumpEntity.fromJson(o)).toList() ?? [];
|
||||
Config.bannerJumps = (map['bannerJumpList'] as List?)
|
||||
?.map((o) => BannerJumpEntity.fromJson(o))
|
||||
.toList() ??
|
||||
[];
|
||||
}
|
||||
|
||||
// 域名 / 线路 / 版本
|
||||
@@ -175,10 +197,14 @@ class DomainSourceModel {
|
||||
info.domain = (map['domain'] as List?)?.map((o) => o.toString()).toList();
|
||||
}
|
||||
if (map.containsKey('sourceList')) {
|
||||
info.sourceList = (map['sourceList'] as List?)?.map((o) => Sourcelist.fromJson(o)).toList();
|
||||
info.sourceList = (map['sourceList'] as List?)
|
||||
?.map((o) => Sourcelist.fromJson(o))
|
||||
.toList();
|
||||
}
|
||||
if (map.containsKey('ver')) {
|
||||
info.ver = (map['ver'] as List?)?.map((o) => CheckVersionInfo.fromMap(o)).toList();
|
||||
info.ver = (map['ver'] as List?)
|
||||
?.map((o) => CheckVersionInfo.fromMap(o))
|
||||
.toList();
|
||||
}
|
||||
|
||||
// 广告
|
||||
@@ -199,8 +225,12 @@ class DomainSourceModel {
|
||||
if (map.containsKey('advanceStatus')) {
|
||||
info.advanceStatus = AdvanceStatus.fromJson(map['advanceStatus']);
|
||||
}
|
||||
info.bannerJump = map['bannerJump'] != null ? BannerJump.fromJson(map['bannerJump']) : null;
|
||||
info.proxyBannerJump = map['bannerJump'] != null ? BannerJump.fromJson(map['bannerJump'], key: '2') : null;
|
||||
info.bannerJump = map['bannerJump'] != null
|
||||
? BannerJump.fromJson(map['bannerJump'])
|
||||
: null;
|
||||
info.proxyBannerJump = map['bannerJump'] != null
|
||||
? BannerJump.fromJson(map['bannerJump'], key: '2')
|
||||
: null;
|
||||
info.festivalUi = map['festivalUi'];
|
||||
if (info.festivalUi?.isNotEmpty != true) info.festivalUi = '默认';
|
||||
|
||||
@@ -210,10 +240,12 @@ class DomainSourceModel {
|
||||
|
||||
// 搜索
|
||||
if (map['hotSearchTerms'] is List) {
|
||||
info.hotSearchTerms = (map['hotSearchTerms'] as List).map((e) => e.toString()).toList();
|
||||
info.hotSearchTerms =
|
||||
(map['hotSearchTerms'] as List).map((e) => e.toString()).toList();
|
||||
}
|
||||
if (map['searchHintWord'] is List) {
|
||||
info.searchHintWord = (map['searchHintWord'] as List).map((e) => e.toString()).toList();
|
||||
info.searchHintWord =
|
||||
(map['searchHintWord'] as List).map((e) => e.toString()).toList();
|
||||
}
|
||||
|
||||
// 暗网 VIP
|
||||
@@ -221,7 +253,8 @@ class DomainSourceModel {
|
||||
info.darkWebVipName = map['darkWebVipName'];
|
||||
info.shortDramaCardId = map['shortDramaCardId'];
|
||||
if (map['recommendVipIds'] is List) {
|
||||
info.recommendVipIds = (map['recommendVipIds'] as List).map((e) => e.toString()).toList();
|
||||
info.recommendVipIds =
|
||||
(map['recommendVipIds'] as List).map((e) => e.toString()).toList();
|
||||
}
|
||||
|
||||
// 其他
|
||||
@@ -229,7 +262,9 @@ class DomainSourceModel {
|
||||
info.broadcast = map['broadcast'] ?? false;
|
||||
info.storeIsOpen = map['storeIsOpen'];
|
||||
if (map['jgArea'] is List) {
|
||||
info.jgArea = (map['jgArea'] as List?)?.map((e) => JGAreaModel.fromJson(e)).toList();
|
||||
info.jgArea = (map['jgArea'] as List?)
|
||||
?.map((e) => JGAreaModel.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
return info;
|
||||
}
|
||||
@@ -292,9 +327,15 @@ class AdsBean {
|
||||
static AdsBean fromMap(Map<String, dynamic>? map) {
|
||||
map ??= {};
|
||||
return AdsBean()
|
||||
..announInfo = (map['announInfo'] as List?)?.map((o) => AnnounceInfoBean.fromJson(o)).toList()
|
||||
..announList = (map['announList'] as List?)?.map((o) => AnnounceInfoBean.fromJson(o)).toList()
|
||||
..adsInfoList = (map['adsInfoList'] as List?)?.map((o) => AdsInfoModel.fromMap(o)).toList();
|
||||
..announInfo = (map['announInfo'] as List?)
|
||||
?.map((o) => AnnounceInfoBean.fromJson(o))
|
||||
.toList()
|
||||
..announList = (map['announList'] as List?)
|
||||
?.map((o) => AnnounceInfoBean.fromJson(o))
|
||||
.toList()
|
||||
..adsInfoList = (map['adsInfoList'] as List?)
|
||||
?.map((o) => AdsInfoModel.fromMap(o))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Map toJson() => {
|
||||
@@ -313,7 +354,15 @@ class JGAreaModel {
|
||||
String? linkUrl;
|
||||
String? mid;
|
||||
|
||||
JGAreaModel({this.id, this.name, this.img, this.desc, this.linkType, this.linkUrl, this.type, this.mid});
|
||||
JGAreaModel(
|
||||
{this.id,
|
||||
this.name,
|
||||
this.img,
|
||||
this.desc,
|
||||
this.linkType,
|
||||
this.linkUrl,
|
||||
this.type,
|
||||
this.mid});
|
||||
|
||||
factory JGAreaModel.fromJson(Map<String, dynamic> json) => JGAreaModel(
|
||||
id: json["id"],
|
||||
@@ -348,7 +397,8 @@ class Sourcelist {
|
||||
|
||||
factory Sourcelist.fromJson(Map<String, dynamic> json) => Sourcelist(
|
||||
id: json["id"],
|
||||
domain: List<Domain>.from(json["domain"].map((x) => Domain.fromJson(x))),
|
||||
domain:
|
||||
List<Domain>.from(json["domain"].map((x) => Domain.fromJson(x))),
|
||||
isActive: json["isActive"],
|
||||
type: json["type"],
|
||||
);
|
||||
@@ -436,7 +486,15 @@ class BannerJumpEntity {
|
||||
String? endAt;
|
||||
int? countdownType;
|
||||
|
||||
BannerJumpEntity({this.title, this.id, this.position, this.url, this.startAt, this.banner, this.endAt, this.countdownType});
|
||||
BannerJumpEntity(
|
||||
{this.title,
|
||||
this.id,
|
||||
this.position,
|
||||
this.url,
|
||||
this.startAt,
|
||||
this.banner,
|
||||
this.endAt,
|
||||
this.countdownType});
|
||||
|
||||
BannerJumpEntity.fromJson(dynamic json) {
|
||||
id = json['id'];
|
||||
@@ -455,7 +513,8 @@ enum PayTier {
|
||||
newUnpay('new_unpay'), //新用户:注册≤1天且从未付费 → 推新人200卡(新人价+首购引导+紧迫感)
|
||||
under7DayUnpay('under_7_day_unpay'), //未付费·注册1~7天 → 推300卡(限时优惠+紧迫感)
|
||||
over7DayUnpay('over_7_day_unpay'), //未付费·注册>7天 → 推300卡(永久卡唤醒需求+信任背书)
|
||||
over7DayNeedUpgrade('over_7_day_need_upgrade'), //低级会员需续费:注册>7天且已付费、未达最高等级(<5) → 推500至尊卡
|
||||
over7DayNeedUpgrade(
|
||||
'over_7_day_need_upgrade'), //低级会员需续费:注册>7天且已付费、未达最高等级(<5) → 推500至尊卡
|
||||
normal('normal'), //正常用户:无特殊弹窗
|
||||
unregistered('unregistered'); //未注册(未登录)
|
||||
|
||||
@@ -496,7 +555,13 @@ class PayTierConfig {
|
||||
String? vipCard; //点击跳转的会员卡 ID
|
||||
int? lastDiscountTime; //优惠截止 Unix 时间戳(秒),早于当前则不展示倒计时
|
||||
|
||||
PayTierConfig({this.homePage, this.homePageFlot, this.playPage, this.meTab, this.vipCard, this.lastDiscountTime});
|
||||
PayTierConfig(
|
||||
{this.homePage,
|
||||
this.homePageFlot,
|
||||
this.playPage,
|
||||
this.meTab,
|
||||
this.vipCard,
|
||||
this.lastDiscountTime});
|
||||
|
||||
PayTierConfig.fromJson(Map<String, dynamic>? json) {
|
||||
json ??= {};
|
||||
@@ -508,7 +573,8 @@ class PayTierConfig {
|
||||
lastDiscountTime = _parseEpochSec(json['lastDiscountTime']);
|
||||
}
|
||||
|
||||
static const _minValidEpochSec = 946684800; //2000-01-01,用于挡掉后端零值时间 0001-01-01T00:00:00Z
|
||||
static const _minValidEpochSec =
|
||||
946684800; //2000-01-01,用于挡掉后端零值时间 0001-01-01T00:00:00Z
|
||||
|
||||
//兼容 Unix 秒(int) / 数字字符串 / ISO 字符串(带 Z 或 +08:00 时区);零值哨兵一律归 null,避免负 epoch 流入业务
|
||||
static int? _parseEpochSec(dynamic v) {
|
||||
@@ -519,7 +585,8 @@ class PayTierConfig {
|
||||
} else if (v is String) {
|
||||
final s = v.trim();
|
||||
if (s.isEmpty) return null;
|
||||
sec = int.tryParse(s) ?? (DateTime.tryParse(s)?.millisecondsSinceEpoch ?? 0) ~/ 1000;
|
||||
sec = int.tryParse(s) ??
|
||||
(DateTime.tryParse(s)?.millisecondsSinceEpoch ?? 0) ~/ 1000;
|
||||
}
|
||||
return (sec != null && sec >= _minValidEpochSec) ? sec : null;
|
||||
}
|
||||
@@ -535,9 +602,11 @@ class PayTierConfig {
|
||||
|
||||
bool get hasDiscountCountdown => discountRemainSec > 0;
|
||||
|
||||
String get discountHour => (discountRemainSec ~/ 3600).toString().padLeft(2, '0');
|
||||
String get discountHour =>
|
||||
(discountRemainSec ~/ 3600).toString().padLeft(2, '0');
|
||||
|
||||
String get discountMin => ((discountRemainSec ~/ 60) % 60).toString().padLeft(2, '0');
|
||||
String get discountMin =>
|
||||
((discountRemainSec ~/ 60) % 60).toString().padLeft(2, '0');
|
||||
|
||||
String get discountSec => (discountRemainSec % 60).toString().padLeft(2, '0');
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
|
||||
/// 用户信息
|
||||
class UserInfoModel {
|
||||
@@ -54,7 +54,8 @@ class UserInfoModel {
|
||||
// ============ 计算属性 ============
|
||||
|
||||
/// 观影券总数量
|
||||
int get couponCount => (goldVideoCoupon ?? []).fold(0, (sum, e) => sum + (e.count ?? 0));
|
||||
int get couponCount =>
|
||||
(goldVideoCoupon ?? []).fold(0, (sum, e) => sum + (e.count ?? 0));
|
||||
|
||||
/// 可解锁该金币视频的观影券面额:券面额需 >= 视频金币,都不够就退回第一张
|
||||
int? couponGold(int? originCoins) {
|
||||
@@ -66,7 +67,8 @@ class UserInfoModel {
|
||||
}
|
||||
|
||||
/// 作品总数(视频上传 + 封面上传)
|
||||
int get totalWorkCount => totalWorks ?? 0 ; //(vidUploadCount ?? 0) + (coverUploadCount ?? 0);
|
||||
int get totalWorkCount =>
|
||||
totalWorks ?? 0; //(vidUploadCount ?? 0) + (coverUploadCount ?? 0);
|
||||
|
||||
/// 会员等级对应的角标图片;等级 1~4,0 级(含推广会员)无角标
|
||||
String get vipImageName {
|
||||
@@ -111,7 +113,9 @@ class UserInfoModel {
|
||||
|
||||
allGoldVideoFree = map['allGoldVideoFree'] ?? false;
|
||||
goldVideoFreeExpire = map['goldVideoFreeExpire'];
|
||||
goldVideoCoupon = (map['goldVideoCoupon'] as List?)?.map((o) => MyCoupon.fromJson(o)).toList();
|
||||
goldVideoCoupon = (map['goldVideoCoupon'] as List?)
|
||||
?.map((o) => MyCoupon.fromJson(o))
|
||||
.toList();
|
||||
broadcastExpire = map['broadcastExpire'];
|
||||
dramaExpire = map['dramaExpire'];
|
||||
payVidDiscount = map['payVidDiscount'];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:hgmj/hj_model/splash/ads_model.dart';
|
||||
import 'package:hgmj/hj_utils/date_time_util.dart';
|
||||
import 'package:wydj/hj_model/splash/ads_model.dart';
|
||||
import 'package:wydj/hj_utils/date_time_util.dart';
|
||||
|
||||
import '../config/address.dart';
|
||||
import '../tools_base/global_store/store.dart';
|
||||
@@ -186,10 +186,12 @@ class VideoModel {
|
||||
.toList();
|
||||
title = map['title'];
|
||||
via = map['via'];
|
||||
comment = map.containsKey("comment") ? CommentBean.fromMap(map['comment']) : null;
|
||||
comment =
|
||||
map.containsKey("comment") ? CommentBean.fromMap(map['comment']) : null;
|
||||
vidStatus = VidStatus.fromMap(map['vidStatus']);
|
||||
if (map['seriesCover'] is List) {
|
||||
seriesCover = (map['seriesCover'] as List).map((e) => e.toString()).toList();
|
||||
seriesCover =
|
||||
(map['seriesCover'] as List).map((e) => e.toString()).toList();
|
||||
}
|
||||
newsType = map['newsType'];
|
||||
reason = map['reason'];
|
||||
@@ -302,7 +304,9 @@ class VideoModel {
|
||||
/// 拼 m3u8 完整播放链接:各播放源共用同一套 host / token / cdn 参数。
|
||||
/// 后端偶尔直接下发完整链接(265、短剧下载授权地址),那种别再往前面拼一遍 host
|
||||
String _m3u8(String? path) {
|
||||
if (path != null && (path.startsWith('http://') || path.startsWith('https://'))) return path;
|
||||
if (path != null &&
|
||||
(path.startsWith('http://') || path.startsWith('https://')))
|
||||
return path;
|
||||
return "${Address.baseApiPath}/vid/h5/m3u8/$path?token=${Address.token}&c=${Address.cdnAddress}";
|
||||
}
|
||||
|
||||
@@ -332,8 +336,10 @@ class VideoModel {
|
||||
/// - 普通源:[useH265] 且有 265 地址 → 265(省带宽),否则 264(兜底)
|
||||
/// [useH265] 由调用方算好传入(设备硬解能力 + 本条是否已运行时回退),model 不依赖 CodecSupport
|
||||
String realPlayUrl({required bool canPlayPreview, required bool useH265}) {
|
||||
if (playContentStyle == 2 && chineseLink?.isNotEmpty == true) return realChineseUrl;
|
||||
if (playContentStyle == 3 && codelessLink?.isNotEmpty == true) return realUncodeUrl;
|
||||
if (playContentStyle == 2 && chineseLink?.isNotEmpty == true)
|
||||
return realChineseUrl;
|
||||
if (playContentStyle == 3 && codelessLink?.isNotEmpty == true)
|
||||
return realUncodeUrl;
|
||||
if (canPlayPreview) return realPreviewUrl;
|
||||
if (useH265 && realH265Url.isNotEmpty) return realH265Url;
|
||||
return realVideoUrl;
|
||||
@@ -343,7 +349,8 @@ class VideoModel {
|
||||
|
||||
/// 展示用创建时间:createdAt 为空或后端占位值时退回审核通过时间
|
||||
String? get realCreateAt {
|
||||
if (createdAt?.contains("0001-01-01") == true || createdAt?.isNotEmpty != true) {
|
||||
if (createdAt?.contains("0001-01-01") == true ||
|
||||
createdAt?.isNotEmpty != true) {
|
||||
return reviewAt;
|
||||
}
|
||||
return createdAt;
|
||||
@@ -356,7 +363,8 @@ class VideoModel {
|
||||
return sec >= start && sec < end;
|
||||
}
|
||||
|
||||
bool get isDarkTag => tags?.any((e) => e.name?.contains("暗网") == true) ?? false;
|
||||
bool get isDarkTag =>
|
||||
tags?.any((e) => e.name?.contains("暗网") == true) ?? false;
|
||||
|
||||
String get allTags => tags?.map((e) => e.name).join(' ') ?? '';
|
||||
|
||||
@@ -448,14 +456,19 @@ extension LockType on VideoModel {
|
||||
/// 帖子流相关的判断与封面取值扩展(社区/个人主页等场景使用)
|
||||
extension Post on VideoModel {
|
||||
bool isVideo() {
|
||||
return newsType == 'SP' || newsType == 'MOVIE' || newsType == 'SHORT' || newsType == 'COVER';
|
||||
return newsType == 'SP' ||
|
||||
newsType == 'MOVIE' ||
|
||||
newsType == 'SHORT' ||
|
||||
newsType == 'COVER';
|
||||
}
|
||||
|
||||
//埋点专用
|
||||
String get contentType => newsType == 'SP' ? 'video' : 'short_video';
|
||||
|
||||
bool isSeedPost() {
|
||||
return newsType == 'ADULT_GAME' || (seedLink?.isNotEmpty ?? false) || newsType == 'SEED_LINK';
|
||||
return newsType == 'ADULT_GAME' ||
|
||||
(seedLink?.isNotEmpty ?? false) ||
|
||||
newsType == 'SEED_LINK';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/base_list_controller.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/tools_base/base_list_controller.dart';
|
||||
|
||||
import 'ai_sub_type/ai_function_logic.dart';
|
||||
import 'models/ai_mod_list_model.dart';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import '../../assets_tool/app_colors.dart';
|
||||
import '../../tools_base/indicator/custom_tab_indicator.dart';
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:get/get.dart';
|
||||
import '../../../alert/mine/vip_level_dialog.dart';
|
||||
import '../../../config/config.dart';
|
||||
import '../../../hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import '../../../tools_base/global_store/store.dart';
|
||||
import '../../../tools_base/loading/loading_helper.dart';
|
||||
import '../ai_sub_type/ai_function_logic.dart';
|
||||
@@ -37,7 +37,8 @@ class AiPaintLogic extends AiFunctionBaseLogic {
|
||||
|
||||
@override
|
||||
Future<void> submit() async {
|
||||
if ((globalStore.wallet?.amount ?? 0) < (int.tryParse(Config.aiDrawPrice) ?? 0)) {
|
||||
if ((globalStore.wallet?.amount ?? 0) <
|
||||
(int.tryParse(Config.aiDrawPrice) ?? 0)) {
|
||||
showVipLevelDialog(
|
||||
"当前金币不足",
|
||||
buttonTitle: '我知道了',
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
|
||||
import '../../../tools_base/widget/net_image_widget.dart';
|
||||
import '../models/ai_mod_list_model.dart';
|
||||
@@ -30,7 +30,8 @@ class AiPaintPage extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
keyboardDismissBehavior:
|
||||
ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -86,31 +87,45 @@ class AiPaintPage extends StatelessWidget {
|
||||
logic.aspectRatios.length,
|
||||
(index) => Padding(
|
||||
padding: EdgeInsets.only(right: 12),
|
||||
child: InkWell(enableFeedback: false,
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
logic.selectIndex = index;
|
||||
logic.update();
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 8),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: logic.selectIndex == index
|
||||
? [AppColors.actionRed, AppColors.actionRed]
|
||||
? [
|
||||
AppColors.actionRed,
|
||||
AppColors.actionRed
|
||||
]
|
||||
: [
|
||||
Colors.white.withValues(alpha: .05),
|
||||
Colors.white.withValues(alpha: .05),
|
||||
Colors.white
|
||||
.withValues(alpha: .05),
|
||||
Colors.white
|
||||
.withValues(alpha: .05),
|
||||
]),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: logic.selectIndex == index ? null : Color(0xFF7C7C7C),
|
||||
color: logic.selectIndex == index
|
||||
? null
|
||||
: Color(0xFF7C7C7C),
|
||||
),
|
||||
height: 28,
|
||||
child: Text(
|
||||
logic.aspectRatios[index],
|
||||
style: TextStyle(
|
||||
color: logic.selectIndex == index ? Colors.white : Colors.white.withValues(alpha: .5),
|
||||
fontSize: logic.selectIndex == index ? 14 : 12,
|
||||
color: logic.selectIndex == index
|
||||
? Colors.white
|
||||
: Colors.white
|
||||
.withValues(alpha: .5),
|
||||
fontSize: logic.selectIndex == index
|
||||
? 14
|
||||
: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
@@ -160,7 +175,8 @@ class AiPaintPage extends StatelessWidget {
|
||||
)
|
||||
],
|
||||
),
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.submit(),
|
||||
child: Container(
|
||||
height: 44,
|
||||
@@ -193,19 +209,23 @@ class AiPaintPage extends StatelessWidget {
|
||||
|
||||
Widget _getStyleView(AiPaintLogic logic) {
|
||||
return logic.isFold
|
||||
? InkWell(enableFeedback: false,
|
||||
? InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
logic.isFold = !logic.isFold;
|
||||
logic.update();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildStyleTitle(),
|
||||
Spacer(),
|
||||
NetworkImageLoader(
|
||||
imageUrl: logic.models.length > 1 ? logic.models[logic.chooseItemIndex].cover ?? "" : '',
|
||||
imageUrl: logic.models.length > 1
|
||||
? logic.models[logic.chooseItemIndex].cover ?? ""
|
||||
: '',
|
||||
width: 32,
|
||||
height: 32,
|
||||
),
|
||||
@@ -220,13 +240,15 @@ class AiPaintPage extends StatelessWidget {
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
logic.isFold = !logic.isFold;
|
||||
logic.update();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10.0, vertical: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildStyleTitle(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/base_list_controller.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/tools_base/base_list_controller.dart';
|
||||
|
||||
import 'ai_sub_type/ai_function_logic.dart';
|
||||
import 'models/ai_mod_list_model.dart';
|
||||
@@ -28,7 +28,8 @@ class AIFaceTemplateLogic extends ListBaseLogic<TemplateModel> {
|
||||
|
||||
void loadData() async {
|
||||
dataList ??= [];
|
||||
final resp = await AIService.getModelListV2(type: type, categoryId: mod?.id ?? '');
|
||||
final resp =
|
||||
await AIService.getModelListV2(type: type, categoryId: mod?.id ?? '');
|
||||
if (resp != null) {
|
||||
dataList?.addAll(resp.templateList ?? []);
|
||||
//默认上架时间降序
|
||||
@@ -49,18 +50,21 @@ class AIFaceTemplateLogic extends ListBaseLogic<TemplateModel> {
|
||||
switch (sortIndex) {
|
||||
case 0:
|
||||
dataList?.sort(
|
||||
(obj1, obj2) => ascending ? obj2.timestamp.compareTo(obj1.timestamp) : obj1.timestamp.compareTo(obj2.timestamp),
|
||||
(obj1, obj2) => ascending
|
||||
? obj2.timestamp.compareTo(obj1.timestamp)
|
||||
: obj1.timestamp.compareTo(obj2.timestamp),
|
||||
);
|
||||
case 1:
|
||||
dataList?.sort(
|
||||
(obj1, obj2) => ascending
|
||||
? (obj2.usedCount ?? 0).compareTo(obj1.usedCount ?? 0) :
|
||||
(obj1.usedCount ?? 0).compareTo(obj2.usedCount ?? 0),
|
||||
? (obj2.usedCount ?? 0).compareTo(obj1.usedCount ?? 0)
|
||||
: (obj1.usedCount ?? 0).compareTo(obj2.usedCount ?? 0),
|
||||
);
|
||||
case 2:
|
||||
dataList?.sort(
|
||||
(obj1, obj2) =>
|
||||
ascending ? (obj2.coin ?? 0).compareTo(obj1.coin ?? 0) : (obj1.coin ?? 0).compareTo(obj2.coin ?? 0),
|
||||
(obj1, obj2) => ascending
|
||||
? (obj2.coin ?? 0).compareTo(obj1.coin ?? 0)
|
||||
: (obj1.coin ?? 0).compareTo(obj2.coin ?? 0),
|
||||
);
|
||||
default:
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../assets_tool/app_colors.dart';
|
||||
import 'ai_face_sub_logic.dart';
|
||||
@@ -17,7 +17,8 @@ import 'models/ai_mod_list_model.dart';
|
||||
class AIFaceChangeSubPage extends StatelessWidget {
|
||||
final AICategoryMod? mod;
|
||||
final AiType type; //图片换脸 / 视频换脸
|
||||
const AIFaceChangeSubPage({super.key, this.mod, this.type = AiType.imageChangeFace});
|
||||
const AIFaceChangeSubPage(
|
||||
{super.key, this.mod, this.type = AiType.imageChangeFace});
|
||||
|
||||
// 多分类子页作为 TabBarView 的 keepAlive children 并存,用 type+分类id 隔离各自 logic 实例
|
||||
String get _tag => 'ai_face_sub_${type.name}_${mod?.id}';
|
||||
@@ -51,7 +52,8 @@ class AIFaceChangeSubPage extends StatelessWidget {
|
||||
itemCount: logic.dataList?.length ?? 0,
|
||||
itemBuilder: (context, index) {
|
||||
TemplateModel? model = logic.dataList?[index];
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.to(AIModDetailPage(model!)),
|
||||
child: NetworkImageLoader(imageUrl: model?.cover ?? ''),
|
||||
);
|
||||
@@ -78,9 +80,11 @@ class AIFaceChangeSubPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSortItem(String title, bool ascending, int sortIndex, AIFaceTemplateLogic logic) {
|
||||
Widget _buildSortItem(
|
||||
String title, bool ascending, int sortIndex, AIFaceTemplateLogic logic) {
|
||||
final bool sel = logic.sortIndex == sortIndex;
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.changeSortAction(sortIndex),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 3),
|
||||
@@ -92,7 +96,11 @@ class AIFaceChangeSubPage extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.w500, height: 1.5),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.5),
|
||||
),
|
||||
5.sizeBoxW,
|
||||
Column(
|
||||
@@ -100,7 +108,8 @@ class AIFaceChangeSubPage extends StatelessWidget {
|
||||
children: [
|
||||
_buildArrow(active: sel && ascending),
|
||||
4.sizeBoxH,
|
||||
Transform.rotate(angle: -pi, child: _buildArrow(active: sel && !ascending)),
|
||||
Transform.rotate(
|
||||
angle: -pi, child: _buildArrow(active: sel && !ascending)),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
|
||||
import '../models/ai_girl_resp_model.dart';
|
||||
import '../widgets/ai_girl_sheet.dart';
|
||||
@@ -54,7 +54,8 @@ class AIGrilFriendLogic extends GetxController {
|
||||
//充值操作
|
||||
onRechargeBottomSheet() async {
|
||||
if (currencys != null && currencys?.list?.isNotEmpty == true) {
|
||||
Get.bottomSheet(AIGirlSheet(list: currencys?.list), isScrollControlled: true);
|
||||
Get.bottomSheet(AIGirlSheet(list: currencys?.list),
|
||||
isScrollControlled: true);
|
||||
} else {
|
||||
await onFetchChargeList();
|
||||
if (currencys?.list?.isNotEmpty != true) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
|
||||
import '../../../hj_utils/widget_util.dart';
|
||||
import '../../../tools_base/unique_tag_mixin.dart';
|
||||
@@ -15,7 +15,8 @@ class AIGrilFriendPage extends StatefulWidget {
|
||||
State<AIGrilFriendPage> createState() => _AIGrilFriendPageState();
|
||||
}
|
||||
|
||||
class _AIGrilFriendPageState extends State<AIGrilFriendPage> with UniqueTagMixin {
|
||||
class _AIGrilFriendPageState extends State<AIGrilFriendPage>
|
||||
with UniqueTagMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<AIGrilFriendLogic>(
|
||||
@@ -67,7 +68,8 @@ class _AIGrilFriendPageState extends State<AIGrilFriendPage> with UniqueTagMixin
|
||||
child: Obx(
|
||||
() => Text(
|
||||
logic.tips.value,
|
||||
style: textStyle(17, Colors.white, FontWeight.w500),
|
||||
style:
|
||||
textStyle(17, Colors.white, FontWeight.w500),
|
||||
),
|
||||
)),
|
||||
),
|
||||
@@ -77,7 +79,8 @@ class _AIGrilFriendPageState extends State<AIGrilFriendPage> with UniqueTagMixin
|
||||
child: GestureDetector(
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.back(),
|
||||
child: const Icon(Icons.arrow_back_ios, size: 24, color: Colors.white),
|
||||
child: const Icon(Icons.arrow_back_ios,
|
||||
size: 24, color: Colors.white),
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -101,7 +104,8 @@ class _AIGrilFriendPageState extends State<AIGrilFriendPage> with UniqueTagMixin
|
||||
GestureDetector(
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.back(),
|
||||
child: const Icon(Icons.arrow_back_ios, size: 24, color: Colors.white),
|
||||
child: const Icon(Icons.arrow_back_ios,
|
||||
size: 24, color: Colors.white),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'dart:collection';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
|
||||
import '../../../hj_utils/widget_util.dart';
|
||||
import '../../web_page/h5_webview_settings.dart';
|
||||
@@ -27,7 +27,8 @@ class _YHYSH5ViewState extends State<AiH5Page> {
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
InAppWebView(
|
||||
initialUrlRequest: URLRequest(url: WebUri(widget.webUrl ?? "")), //h5的url
|
||||
initialUrlRequest:
|
||||
URLRequest(url: WebUri(widget.webUrl ?? "")), //h5的url
|
||||
initialSettings: h5WebViewSettings,
|
||||
initialUserScripts: UnmodifiableListView<UserScript>([]),
|
||||
),
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_page/pre_sale/pre_sale_provider.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/hj_page/pre_sale/pre_sale_provider.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import '../../config/config.dart';
|
||||
import '../../hj_model/splash/domain_source_model.dart';
|
||||
@@ -18,7 +18,8 @@ import './ai_sub_type/ai_strip_sub_page.dart';
|
||||
import './models/ai_mod_list_model.dart';
|
||||
import 'ai_square/ai_square_page.dart';
|
||||
|
||||
class AiHomeLogic extends GetxController with GetSingleTickerProviderStateMixin {
|
||||
class AiHomeLogic extends GetxController
|
||||
with GetSingleTickerProviderStateMixin {
|
||||
bool isShowLoading = true;
|
||||
final AiType? aiType;
|
||||
// int tabIndex;
|
||||
@@ -50,7 +51,8 @@ class AiHomeLogic extends GetxController with GetSingleTickerProviderStateMixin
|
||||
//3.获取到默认进来的排序
|
||||
int? initialIndex = aiTypes?.indexWhere((model) => model.aiType == aiType);
|
||||
initialIndex = max(0, initialIndex ?? 0);
|
||||
tabCtr = TabController(initialIndex: initialIndex, length: menus.length, vsync: this)
|
||||
tabCtr = TabController(
|
||||
initialIndex: initialIndex, length: menus.length, vsync: this)
|
||||
..addListener(() {
|
||||
if (!tabCtr.indexIsChanging) {
|
||||
update(['tab']);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import '../../hj_utils/widget_util.dart';
|
||||
import 'ai_home_logic.dart';
|
||||
@@ -36,7 +36,10 @@ class AiHomePage extends StatelessWidget {
|
||||
),
|
||||
child: Text(
|
||||
'记录',
|
||||
style: textStyle(14, Colors.white.withValues(alpha: 0.55), FontWeight.w400),
|
||||
style: textStyle(
|
||||
14,
|
||||
Colors.white.withValues(alpha: 0.55),
|
||||
FontWeight.w400),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -61,7 +64,9 @@ class AiHomePage extends StatelessWidget {
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: logic.tabCtr,
|
||||
children: logic.menus.map<Widget>((e) => logic.subPage(e).keepAlive).toList(),
|
||||
children: logic.menus
|
||||
.map<Widget>((e) => logic.subPage(e).keepAlive)
|
||||
.toList(),
|
||||
),
|
||||
)
|
||||
],
|
||||
@@ -100,8 +105,13 @@ class AiHomePage extends StatelessWidget {
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
color: isSelected ? Color(0xffFFC000) : Colors.white.withValues(alpha: .1),
|
||||
border: isSelected ? null : Border.all(width: 1, color: Colors.white.withValues(alpha: .35)),
|
||||
color: isSelected
|
||||
? Color(0xffFFC000)
|
||||
: Colors.white.withValues(alpha: .1),
|
||||
border: isSelected
|
||||
? null
|
||||
: Border.all(
|
||||
width: 1, color: Colors.white.withValues(alpha: .35)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -114,7 +124,10 @@ class AiHomePage extends StatelessWidget {
|
||||
4.sizeBoxW,
|
||||
Text(
|
||||
menu.aiTypeName ?? '',
|
||||
style: textStyle(12, isSelected ? Colors.black : Colors.white, FontWeight.w400),
|
||||
style: textStyle(
|
||||
12,
|
||||
isSelected ? Colors.black : Colors.white,
|
||||
FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/file_upload/file_upload_tool.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_alert.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/file_upload/file_upload_tool.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/common_alert.dart';
|
||||
|
||||
import '../../../alert/mine/vip_level_dialog.dart';
|
||||
import '../../../hj_model/splash/ads_model.dart';
|
||||
@@ -26,7 +26,8 @@ class AiItvLogic extends GetxController {
|
||||
AiItvLogic({this.model});
|
||||
|
||||
Future<void> submit() async {
|
||||
if ((globalStore.wallet?.amount ?? 0) < (int.tryParse(Config.aiVideoPrice) ?? 0)) {
|
||||
if ((globalStore.wallet?.amount ?? 0) <
|
||||
(int.tryParse(Config.aiVideoPrice) ?? 0)) {
|
||||
showVipLevelDialog(
|
||||
"当前金币不足",
|
||||
buttonTitle: '我知道了',
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/banner/ads_banner.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/banner/ads_banner.dart';
|
||||
|
||||
import '../../../hj_model/splash/ads_model.dart';
|
||||
import '../widgets/pic_picker.dart';
|
||||
@@ -20,7 +20,8 @@ class AiItvPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
model?.title ?? '图生视频',
|
||||
style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600),
|
||||
style: TextStyle(
|
||||
color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600),
|
||||
),
|
||||
centerTitle: false,
|
||||
titleSpacing: -20,
|
||||
@@ -78,7 +79,10 @@ class AiItvPage extends StatelessWidget {
|
||||
18.sizeBoxH,
|
||||
Text(
|
||||
"案列鉴赏",
|
||||
style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.w600),
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
12.sizeBoxH,
|
||||
ClipRRect(
|
||||
@@ -100,7 +104,9 @@ class AiItvPage extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
"处理一张照片的费用是 ",
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .6), fontSize: 14),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .6),
|
||||
fontSize: 14),
|
||||
),
|
||||
Text(
|
||||
"${Config.aiVideoPrice}金币",
|
||||
@@ -112,7 +118,8 @@ class AiItvPage extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
18.sizeBoxH,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.submit(),
|
||||
child: Container(
|
||||
height: 44,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import 'package:easy_rich_text/easy_rich_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_page/pre_sale/pre_sale_provider.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_page/pre_sale/pre_sale_provider.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../hj_model/video_model.dart';
|
||||
@@ -45,7 +45,8 @@ class AIModDetailPage extends StatelessWidget {
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: InkWell(enableFeedback: false,
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.submit(),
|
||||
child: Container(
|
||||
height: 44,
|
||||
@@ -91,9 +92,11 @@ class AIModDetailPage extends StatelessWidget {
|
||||
),
|
||||
//视频换脸
|
||||
if (logic.isChangeVideo)
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
VideoModel videoModel = VideoModel()..sourceURL = logic.mod.m3u8Url;
|
||||
VideoModel videoModel = VideoModel()
|
||||
..sourceURL = logic.mod.m3u8Url;
|
||||
Get.to(
|
||||
SimpleVideoPlayerPage(
|
||||
videoUrl: videoModel.realVideoUrl,
|
||||
@@ -205,7 +208,10 @@ class AIModDetailPage extends StatelessWidget {
|
||||
12.sizeBoxH,
|
||||
EasyRichText(
|
||||
'处理一张照片的费用是 ${logic.price}金币',
|
||||
defaultStyle: TextStyle(color: Color(0xff989898), fontSize: 14, fontWeight: FontWeight.w400),
|
||||
defaultStyle: TextStyle(
|
||||
color: Color(0xff989898),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
patternList: [
|
||||
EasyRichTextPattern(
|
||||
targetString: '${logic.price}金币',
|
||||
@@ -218,7 +224,10 @@ class AIModDetailPage extends StatelessWidget {
|
||||
12.sizeBoxH,
|
||||
EasyRichText(
|
||||
'已抵扣 ${logic.coupon?.goodsValue ?? 0}金币',
|
||||
defaultStyle: TextStyle(color: Colors.white.withValues(alpha: .55), fontSize: 14, fontWeight: FontWeight.w400),
|
||||
defaultStyle: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .55),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
patternList: [
|
||||
EasyRichTextPattern(
|
||||
targetString: '${logic.coupon?.goodsValue ?? 0}金币',
|
||||
@@ -230,7 +239,8 @@ class AIModDetailPage extends StatelessWidget {
|
||||
12.sizeBoxH,
|
||||
Row(
|
||||
children: [
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.showCoupon(),
|
||||
child: GradientText(
|
||||
logic.coupon == null ? '使用抵扣券' : '更换抵扣券',
|
||||
@@ -245,7 +255,8 @@ class AIModDetailPage extends StatelessWidget {
|
||||
),
|
||||
if (logic.coupon != null) ...[
|
||||
12.sizeBoxW,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
//取消优惠券
|
||||
logic.coupon = null;
|
||||
@@ -253,7 +264,8 @@ class AIModDetailPage extends StatelessWidget {
|
||||
},
|
||||
child: Text(
|
||||
'取消',
|
||||
style: textStyle(14, Colors.white.withValues(alpha: .55), FontWeight.w400),
|
||||
style: textStyle(14, Colors.white.withValues(alpha: .55),
|
||||
FontWeight.w400),
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//ai小说
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_helper.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_helper.dart';
|
||||
|
||||
import '../../../../hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import '../ai_sub_type/ai_function_logic.dart';
|
||||
|
||||
class AINovelLogic extends AiFunctionBaseLogic {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
|
||||
import '../widgets/ai_draw_text_field.dart';
|
||||
import 'ai_novel_logic.dart';
|
||||
@@ -22,7 +22,8 @@ class AINovelSubPage extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
keyboardDismissBehavior:
|
||||
ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
padding: EdgeInsets.symmetric(horizontal: 6).copyWith(top: 12),
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -70,7 +71,8 @@ class AINovelSubPage extends StatelessWidget {
|
||||
logic.mods.length,
|
||||
(index) => Padding(
|
||||
padding: EdgeInsets.only(right: 12),
|
||||
child: InkWell(enableFeedback: false,
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
logic.selectIndex = index;
|
||||
logic.update();
|
||||
@@ -81,19 +83,28 @@ class AINovelSubPage extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: logic.selectIndex == index
|
||||
? [AppColors.actionRed, AppColors.actionRed]
|
||||
? [
|
||||
AppColors.actionRed,
|
||||
AppColors.actionRed
|
||||
]
|
||||
: [
|
||||
Colors.white.withValues(alpha: .05),
|
||||
Colors.white.withValues(alpha: .05),
|
||||
Colors.white
|
||||
.withValues(alpha: .05),
|
||||
Colors.white
|
||||
.withValues(alpha: .05),
|
||||
]),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: logic.selectIndex == index ? null : Color(0xFF7C7C7C),
|
||||
color: logic.selectIndex == index
|
||||
? null
|
||||
: Color(0xFF7C7C7C),
|
||||
),
|
||||
height: 28,
|
||||
child: Text(
|
||||
logic.mods[index],
|
||||
style: TextStyle(
|
||||
color: logic.selectIndex == index ? Colors.black : Colors.white.withValues(alpha: .5),
|
||||
color: logic.selectIndex == index
|
||||
? Colors.black
|
||||
: Colors.white.withValues(alpha: .5),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
@@ -125,7 +136,8 @@ class AINovelSubPage extends StatelessWidget {
|
||||
)
|
||||
],
|
||||
),
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.submit(),
|
||||
child: Container(
|
||||
height: 44,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/tools_base/indicator/custom_tab_indicator.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/tools_base/indicator/custom_tab_indicator.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import '../../../hj_model/splash/domain_source_model.dart';
|
||||
import '../ai_sub_type/ai_function_logic.dart';
|
||||
@@ -65,7 +65,8 @@ class AIMainRecordPage extends StatelessWidget {
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
unselectedLabelColor: Colors.white.withValues(alpha: .35),
|
||||
unselectedLabelStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
unselectedLabelStyle:
|
||||
const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
indicator: CustomIndicator(
|
||||
isGradient: true,
|
||||
width: 13,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/list_base_model.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_model/list_base_model.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_alert.dart';
|
||||
import 'package:wydj/tools_base/widget/common_alert.dart';
|
||||
|
||||
import '../ai_sub_type/ai_function_logic.dart';
|
||||
import '../models/ai_record_model.dart';
|
||||
@@ -41,7 +41,9 @@ class AIRecordLogic extends GetxController {
|
||||
refreshCtr?.refreshCompleted();
|
||||
}
|
||||
dataSource.addAll(res?.list ?? []);
|
||||
(res?.hasNext ?? false) ? refreshCtr?.loadComplete() : refreshCtr?.loadNoData();
|
||||
(res?.hasNext ?? false)
|
||||
? refreshCtr?.loadComplete()
|
||||
: refreshCtr?.loadNoData();
|
||||
page += 1;
|
||||
} catch (e) {
|
||||
isLoading = false;
|
||||
@@ -73,13 +75,17 @@ class AIRecordLogic extends GetxController {
|
||||
final model = dataSource[index];
|
||||
switch (aiType) {
|
||||
case AiType.aiNovel:
|
||||
return AINovelRecord(model, onDeleteCallback: () => deleteRecord(index));
|
||||
return AINovelRecord(model,
|
||||
onDeleteCallback: () => deleteRecord(index));
|
||||
case AiType.imageToVideo:
|
||||
return AIVideoRecord(model, status: sort, onDeleteCallback: () => deleteRecord(index));
|
||||
return AIVideoRecord(model,
|
||||
status: sort, onDeleteCallback: () => deleteRecord(index));
|
||||
case AiType.aiPaint:
|
||||
return AIPaintRecord(model, status: sort, onDeleteCallback: () => deleteRecord(index));
|
||||
return AIPaintRecord(model,
|
||||
status: sort, onDeleteCallback: () => deleteRecord(index));
|
||||
default: //脱衣 / 视频换脸 / 图片换脸
|
||||
return AIImageRecord(model, aiType: aiType, onDeleteCallback: () => deleteRecord(index));
|
||||
return AIImageRecord(model,
|
||||
aiType: aiType, onDeleteCallback: () => deleteRecord(index));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import '../ai_sub_type/ai_function_logic.dart';
|
||||
import 'ai_record_logic.dart';
|
||||
@@ -20,8 +20,10 @@ class AiRecordPage extends StatefulWidget {
|
||||
State<AiRecordPage> createState() => _AiRecordPageState();
|
||||
}
|
||||
|
||||
class _AiRecordPageState extends State<AiRecordPage> with SingleTickerProviderStateMixin {
|
||||
late final TabController _tabCtr = TabController(length: _subTypes.length, vsync: this);
|
||||
class _AiRecordPageState extends State<AiRecordPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final TabController _tabCtr =
|
||||
TabController(length: _subTypes.length, vsync: this);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -39,7 +41,9 @@ class _AiRecordPageState extends State<AiRecordPage> with SingleTickerProviderSt
|
||||
controller: _tabCtr,
|
||||
children: List.generate(
|
||||
_subTypes.length,
|
||||
(index) => _AiRecordStatusList(aiType: widget.aiType, status: index + 1).keepAlive,
|
||||
(index) =>
|
||||
_AiRecordStatusList(aiType: widget.aiType, status: index + 1)
|
||||
.keepAlive,
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -58,7 +62,8 @@ class _AiRecordPageState extends State<AiRecordPage> with SingleTickerProviderSt
|
||||
decoration: BoxDecoration(
|
||||
border: index != 2
|
||||
? Border(
|
||||
right: BorderSide(width: .5, color: Colors.white.withValues(alpha: .1)),
|
||||
right: BorderSide(
|
||||
width: .5, color: Colors.white.withValues(alpha: .1)),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@@ -69,8 +74,10 @@ class _AiRecordPageState extends State<AiRecordPage> with SingleTickerProviderSt
|
||||
padding: EdgeInsets.only(top: 10, left: 7),
|
||||
labelPadding: EdgeInsets.zero,
|
||||
tabAlignment: TabAlignment.start,
|
||||
unselectedLabelStyle: TextStyle(color: Colors.white.withValues(alpha: .35), fontSize: 14),
|
||||
labelStyle: TextStyle(color: Colors.white.withValues(alpha: .9), fontSize: 14),
|
||||
unselectedLabelStyle:
|
||||
TextStyle(color: Colors.white.withValues(alpha: .35), fontSize: 14),
|
||||
labelStyle:
|
||||
TextStyle(color: Colors.white.withValues(alpha: .9), fontSize: 14),
|
||||
indicator: const BoxDecoration(),
|
||||
);
|
||||
}
|
||||
@@ -108,7 +115,8 @@ class _AiRecordStatusList extends StatelessWidget {
|
||||
padding: EdgeInsets.only(left: 16, right: 16, top: 18),
|
||||
separatorBuilder: (_, index) => 12.sizeBoxH,
|
||||
itemCount: logic.dataSource.length,
|
||||
itemBuilder: (BuildContext context, int index) => logic.instanceChild(index),
|
||||
itemBuilder: (BuildContext context, int index) =>
|
||||
logic.instanceChild(index),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/base_list_controller.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/tools_base/base_list_controller.dart';
|
||||
|
||||
import '../ai_mod_detail_page.dart';
|
||||
import '../ai_home_logic.dart';
|
||||
@@ -15,7 +15,8 @@ class AiSquareLogic extends ListBaseLogic<AISquareItemModel> {
|
||||
}
|
||||
|
||||
//isRefresh=true 下拉刷新 / false 上拉加载更多
|
||||
void loadData({bool isRefresh = true}) => fetchData(isRefresh: isRefresh, fetch: _fetch);
|
||||
void loadData({bool isRefresh = true}) =>
|
||||
fetchData(isRefresh: isRefresh, fetch: _fetch);
|
||||
|
||||
Future<(List<AISquareItemModel>?, bool)> _fetch(int page) async {
|
||||
final resp = await AIService.getPlazaList(page);
|
||||
@@ -44,7 +45,8 @@ class AiSquareLogic extends ListBaseLogic<AISquareItemModel> {
|
||||
Get.to(() => AIModDetailPage(mod));
|
||||
return;
|
||||
}
|
||||
final isImageFace = AiTypeCode.fromServerCode(model.type) == AiType.imageChangeFace;
|
||||
final isImageFace =
|
||||
AiTypeCode.fromServerCode(model.type) == AiType.imageChangeFace;
|
||||
Get.find<AiHomeLogic>().jumpSubModule(isImageFace ? 5 : 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import '../widgets/ai_square_cell.dart';
|
||||
import 'ai_square_logic.dart';
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_page/pre_sale/pre_sale_provider.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/tools_base/file_upload/file_upload_tool.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_alert.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_page/pre_sale/pre_sale_provider.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/tools_base/file_upload/file_upload_tool.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/common_alert.dart';
|
||||
|
||||
import '../../../alert/mine/vip_level_dialog.dart';
|
||||
import '../../../routers/jump_router.dart';
|
||||
@@ -68,7 +68,8 @@ abstract class AiFunctionBaseLogic extends GetxController {
|
||||
|
||||
//免费次数或金币够不够本次消费
|
||||
bool canPay(int price) {
|
||||
final freeCount = (globalStore.wallet?.todayAiFreeTimes ?? 0) + (presaleProvider.remain?.todayAiUndressCount ?? 0);
|
||||
final freeCount = (globalStore.wallet?.todayAiFreeTimes ?? 0) +
|
||||
(presaleProvider.remain?.todayAiUndressCount ?? 0);
|
||||
if ((globalStore.wallet?.amount ?? 0) < price && freeCount <= 0) {
|
||||
showVipLevelDialog("当前免费次数不足或金币余额不足", buttonTitle: '去充值', vipEvent: () {
|
||||
Get.back();
|
||||
@@ -142,13 +143,19 @@ class AiStripLogic extends AiFunctionBaseLogic {
|
||||
Future<void> submit() async {
|
||||
if (!checkPic()) return;
|
||||
//预售期有免费次数先走免费,否则查金币
|
||||
if (presaleProvider.isOpen && presaleProvider.hasLimit && (presaleProvider.remain?.todayAiUndressCount ?? 0) > 0) {
|
||||
presaleProvider.remain?.todayAiUndressCount = (presaleProvider.remain?.todayAiUndressCount ?? 0) - 1;
|
||||
if (presaleProvider.isOpen &&
|
||||
presaleProvider.hasLimit &&
|
||||
(presaleProvider.remain?.todayAiUndressCount ?? 0) > 0) {
|
||||
presaleProvider.remain?.todayAiUndressCount =
|
||||
(presaleProvider.remain?.todayAiUndressCount ?? 0) - 1;
|
||||
} else {
|
||||
if (!canPay(int.tryParse(Config.aiUndressPrice) ?? 0)) return;
|
||||
}
|
||||
//传副本:提交成功回调里会清空 localPicList
|
||||
await upload([...localPicList], (urls) => AIService.generateUndress(urls, shareToAiSquare, editingCtr.text));
|
||||
await upload(
|
||||
[...localPicList],
|
||||
(urls) =>
|
||||
AIService.generateUndress(urls, shareToAiSquare, editingCtr.text));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,16 +178,22 @@ class AiFaceDetailLogic extends AiFunctionBaseLogic {
|
||||
Future<void> submit() async {
|
||||
if (!checkPic()) return;
|
||||
//预售期图片换脸有免费次数先走免费,否则查金币
|
||||
if (presaleProvider.isOpen && presaleProvider.hasLimit && (presaleProvider.remain?.todayAiUndressCount ?? 0) > 0 && !isChangeVideo) {
|
||||
presaleProvider.remain?.todayAiUndressCount = (presaleProvider.remain?.todayAiUndressCount ?? 0) - 1;
|
||||
if (presaleProvider.isOpen &&
|
||||
presaleProvider.hasLimit &&
|
||||
(presaleProvider.remain?.todayAiUndressCount ?? 0) > 0 &&
|
||||
!isChangeVideo) {
|
||||
presaleProvider.remain?.todayAiUndressCount =
|
||||
(presaleProvider.remain?.todayAiUndressCount ?? 0) - 1;
|
||||
} else {
|
||||
if (!canPay(price)) return;
|
||||
}
|
||||
await upload(
|
||||
localPicList,
|
||||
(urls) => isChangeVideo
|
||||
? AIService.generateChangeFace(urls, mod.id, coupon?.id, shareToAiSquare, editingCtr.text) //视频换脸
|
||||
: AIService.generateImg(urls.firstOrNull ?? '', mod.id ?? '', shareToAiSquare, editingCtr.text), //图片换脸
|
||||
? AIService.generateChangeFace(
|
||||
urls, mod.id, coupon?.id, shareToAiSquare, editingCtr.text) //视频换脸
|
||||
: AIService.generateImg(urls.firstOrNull ?? '', mod.id ?? '',
|
||||
shareToAiSquare, editingCtr.text), //图片换脸
|
||||
onDone: () => coupon = null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_page/pre_sale/pre_sale_provider.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/banner/ads_banner.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_page/pre_sale/pre_sale_provider.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/banner/ads_banner.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../widgets/pic_picker.dart';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hgmj/hj_utils/text_util.dart';
|
||||
import 'package:wydj/hj_utils/text_util.dart';
|
||||
|
||||
import '../../../hj_model/splash/ads_model.dart';
|
||||
import 'ai_change_face_video_model.dart';
|
||||
@@ -18,9 +18,15 @@ class AiModList {
|
||||
|
||||
AiModList.fromJson(dynamic json) {
|
||||
json ??= {};
|
||||
aiUndressMod = (json['aiUndressMod'] as List?)?.map((e) => AdsInfoModel.fromJson(e)).toList();
|
||||
aiImgToVideoMod = (json['aiImgToVideoMod'] as List?)?.map((e) => AdsInfoModel.fromJson(e)).toList();
|
||||
aiTextToImgMod = (json['aiTextToImgMod'] as List?)?.map((e) => AiChangeFaceVideoMod.fromJson(e)).toList();
|
||||
aiUndressMod = (json['aiUndressMod'] as List?)
|
||||
?.map((e) => AdsInfoModel.fromJson(e))
|
||||
.toList();
|
||||
aiImgToVideoMod = (json['aiImgToVideoMod'] as List?)
|
||||
?.map((e) => AdsInfoModel.fromJson(e))
|
||||
.toList();
|
||||
aiTextToImgMod = (json['aiTextToImgMod'] as List?)
|
||||
?.map((e) => AiChangeFaceVideoMod.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +39,12 @@ class AiChangeModList {
|
||||
AiChangeModList.fromJson(dynamic json) {
|
||||
json ??= {};
|
||||
categoryId = json['categoryId'];
|
||||
categoryList = (json['categoryList'] as List?)?.map((e) => AICategoryMod.fromJson(e)).toList();
|
||||
templateList = (json['templateList'] as List?)?.map((e) => TemplateModel.fromJson(e)).toList();
|
||||
categoryList = (json['categoryList'] as List?)
|
||||
?.map((e) => AICategoryMod.fromJson(e))
|
||||
.toList();
|
||||
templateList = (json['templateList'] as List?)
|
||||
?.map((e) => TemplateModel.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +87,8 @@ class TemplateModel {
|
||||
int? vipCoin;
|
||||
|
||||
/// 上架时间戳,模版列表按它排序;时间解析不了按 0 排最前
|
||||
int get timestamp => DateTime.tryParse(createdAt ?? '')?.millisecondsSinceEpoch ?? 0;
|
||||
int get timestamp =>
|
||||
DateTime.tryParse(createdAt ?? '')?.millisecondsSinceEpoch ?? 0;
|
||||
|
||||
TemplateModel.fromJson(dynamic json) {
|
||||
json ??= {};
|
||||
|
||||
@@ -7,7 +7,7 @@ cover换脸后封面大图
|
||||
url换脸后视频地址
|
||||
*/
|
||||
|
||||
import 'package:hgmj/hj_utils/text_util.dart';
|
||||
import 'package:wydj/hj_utils/text_util.dart';
|
||||
|
||||
import '../../../config/address.dart';
|
||||
|
||||
@@ -41,7 +41,8 @@ class AiRecordModel {
|
||||
String? locationScene; //地点场景
|
||||
|
||||
/// 换脸结果视频地址。query 用 cdn= 而不是 VideoModel 的 c=,两边接口不同,别顺手统一
|
||||
String get realVideoUrl => "${Address.baseApiPath}/vid/h5/m3u8/$url?token=${Address.token}&cdn=${Address.cdnAddress}";
|
||||
String get realVideoUrl =>
|
||||
"${Address.baseApiPath}/vid/h5/m3u8/$url?token=${Address.token}&cdn=${Address.cdnAddress}";
|
||||
|
||||
AiRecordModel.fromJson(dynamic json) {
|
||||
json ??= {};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/mine_service.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/api_service/mine_service.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
|
||||
import '../../../hj_utils/widget_util.dart';
|
||||
import '../../mine/mine_vip/coupon_model.dart';
|
||||
@@ -42,7 +42,9 @@ class _AICouponSheetState extends State<AICouponSheet> {
|
||||
dataList ??= []; //首屏失败也要退出 loading,否则永远转圈
|
||||
setState(() {});
|
||||
if (page == 1) refreshCtr?.refreshCompleted();
|
||||
(res?.length ?? 0) < size ? refreshCtr?.loadNoData() : refreshCtr?.loadComplete();
|
||||
(res?.length ?? 0) < size
|
||||
? refreshCtr?.loadNoData()
|
||||
: refreshCtr?.loadComplete();
|
||||
}
|
||||
|
||||
Future<void> loadMore() => loadData(page: curPage + 1);
|
||||
@@ -59,7 +61,9 @@ class _AICouponSheetState extends State<AICouponSheet> {
|
||||
children: [
|
||||
const SheetHandleBar(),
|
||||
18.sizeBoxH,
|
||||
Text('使用抵扣券', style: textStyle(18, Colors.white.withValues(alpha: .9), FontWeight.w600)),
|
||||
Text('使用抵扣券',
|
||||
style: textStyle(
|
||||
18, Colors.white.withValues(alpha: .9), FontWeight.w600)),
|
||||
18.sizeBoxH,
|
||||
Expanded(child: _list()),
|
||||
],
|
||||
@@ -92,12 +96,14 @@ class _AICouponSheetState extends State<AICouponSheet> {
|
||||
alignment: Alignment.center,
|
||||
height: 68,
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(image: AssetImage('ai_coupon_bg.webp'.aiPath), fit: BoxFit.fill),
|
||||
image: DecorationImage(
|
||||
image: AssetImage('ai_coupon_bg.webp'.aiPath), fit: BoxFit.fill),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
18.sizeBoxW,
|
||||
Text('${model.goodsName}', style: textStyle(18, couponText, FontWeight.w600)),
|
||||
Text('${model.goodsName}',
|
||||
style: textStyle(18, couponText, FontWeight.w600)),
|
||||
12.sizeBoxW,
|
||||
Expanded(
|
||||
child: Text(
|
||||
@@ -116,7 +122,8 @@ class _AICouponSheetState extends State<AICouponSheet> {
|
||||
color: const Color(0xffFFDCB3),
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
),
|
||||
child: Text('立即使用', style: textStyle(12, Color(0xFF7F0000), FontWeight.w400)),
|
||||
child: Text('立即使用',
|
||||
style: textStyle(12, Color(0xFF7F0000), FontWeight.w400)),
|
||||
),
|
||||
18.sizeBoxW,
|
||||
],
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/hj_utils/api_service/ai_service.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
|
||||
import '../../../hj_utils/widget_util.dart';
|
||||
import '../models/ai_girl_resp_model.dart';
|
||||
@@ -26,7 +26,8 @@ class _AIGirlSheetState extends State<AIGirlSheet> {
|
||||
List<AIGirlFriendCurrency> get _items => widget.list ?? [];
|
||||
|
||||
//列表可能为空,取不到就没得选
|
||||
AIGirlFriendCurrency? get _selected => selectIndex < _items.length ? _items[selectIndex] : null;
|
||||
AIGirlFriendCurrency? get _selected =>
|
||||
selectIndex < _items.length ? _items[selectIndex] : null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -44,9 +45,12 @@ class _AIGirlSheetState extends State<AIGirlSheet> {
|
||||
const SheetHandleBar(color: Color(0x1AFFFFFF)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 18, bottom: 12),
|
||||
child: Text('AI女友', style: textStyle(20, Colors.white, FontWeight.w600)),
|
||||
child: Text('AI女友',
|
||||
style: textStyle(20, Colors.white, FontWeight.w600)),
|
||||
),
|
||||
Text('充值积分', style: textStyle(14, Colors.white.withValues(alpha: .8), FontWeight.w400)),
|
||||
Text('充值积分',
|
||||
style: textStyle(
|
||||
14, Colors.white.withValues(alpha: .8), FontWeight.w400)),
|
||||
GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 18),
|
||||
shrinkWrap: true,
|
||||
@@ -65,11 +69,13 @@ class _AIGirlSheetState extends State<AIGirlSheet> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('支付小贴士:', style: textStyle(14, Colors.white, FontWeight.w500)),
|
||||
Text('支付小贴士:',
|
||||
style: textStyle(14, Colors.white, FontWeight.w500)),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
'1.因超时支付无法到账,请重新发起。\n2.连续发起且未支付,账号可能被加入黑名单\n3.充值成功后会在1~5分钟内到账,可重新刷新进入当前页面',
|
||||
style: textStyle(12, Colors.white.withValues(alpha: .6), FontWeight.w400),
|
||||
style: textStyle(12, Colors.white.withValues(alpha: .6),
|
||||
FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -83,7 +89,12 @@ class _AIGirlSheetState extends State<AIGirlSheet> {
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xff1E3C72), Color(0xff5F40B6), Color(0xff1E3C72), Color(0xff2A5298)],
|
||||
colors: [
|
||||
Color(0xff1E3C72),
|
||||
Color(0xff5F40B6),
|
||||
Color(0xff1E3C72),
|
||||
Color(0xff2A5298)
|
||||
],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
),
|
||||
@@ -109,10 +120,14 @@ class _AIGirlSheetState extends State<AIGirlSheet> {
|
||||
onTap: () => setState(() => selectIndex = index),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? const Color(0xff4039A1) : Colors.white.withValues(alpha: .05),
|
||||
color: isSelected
|
||||
? const Color(0xff4039A1)
|
||||
: Colors.white.withValues(alpha: .05),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
color: isSelected ? const Color(0xff30509C) : Colors.white.withValues(alpha: .1),
|
||||
color: isSelected
|
||||
? const Color(0xff30509C)
|
||||
: Colors.white.withValues(alpha: .1),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
@@ -120,14 +135,21 @@ class _AIGirlSheetState extends State<AIGirlSheet> {
|
||||
children: [
|
||||
Text(
|
||||
'${item.coins ?? 0}积分',
|
||||
style: textStyle(16, isSelected ? const Color(0xffAFABFF) : const Color(0xff7D95D5), FontWeight.w400),
|
||||
style: textStyle(
|
||||
16,
|
||||
isSelected
|
||||
? const Color(0xffAFABFF)
|
||||
: const Color(0xff7D95D5),
|
||||
FontWeight.w400),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${(item.price ?? 0).truncate()}金币',
|
||||
style: textStyle(
|
||||
12,
|
||||
isSelected ? const Color(0x4DF3F5FF) : Colors.white.withValues(alpha: .3),
|
||||
isSelected
|
||||
? const Color(0x4DF3F5FF)
|
||||
: Colors.white.withValues(alpha: .3),
|
||||
FontWeight.w400,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/video_download/video_cache_store.dart';
|
||||
import 'package:hgmj/tools_base/video_download/video_download_manager.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/video_download/video_cache_store.dart';
|
||||
import 'package:wydj/tools_base/video_download/video_download_manager.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
|
||||
import '../../video/simple_video_player_page.dart';
|
||||
import '../ai_sub_type/ai_function_logic.dart';
|
||||
@@ -39,7 +39,8 @@ class AIImageRecord extends StatelessWidget {
|
||||
final AiType aiType;
|
||||
final VoidCallback? onDeleteCallback;
|
||||
|
||||
const AIImageRecord(this.model, {super.key, this.aiType = AiType.autoStrip, this.onDeleteCallback});
|
||||
const AIImageRecord(this.model,
|
||||
{super.key, this.aiType = AiType.autoStrip, this.onDeleteCallback});
|
||||
|
||||
bool get isVideoFace => aiType.isVideoFace;
|
||||
|
||||
@@ -110,7 +111,8 @@ class AIImageRecord extends StatelessWidget {
|
||||
String get _resultCover {
|
||||
if (_state == AIRecordState.success) {
|
||||
//视频换脸有的成功订单后端不回 cover,退回素材封面,别让结果位空着露占位图
|
||||
if (isVideoFace) return model.cover?.isNotEmpty == true ? model.cover! : _sourceCover;
|
||||
if (isVideoFace)
|
||||
return model.cover?.isNotEmpty == true ? model.cover! : _sourceCover;
|
||||
return model.newPic?.firstOrNull ?? '';
|
||||
}
|
||||
if (isVideoFace) return model.picture?.firstOrNull ?? '';
|
||||
@@ -124,14 +126,17 @@ class AIImageRecord extends StatelessWidget {
|
||||
ImageBrowserPage.open([images.first], showSaveButton: true);
|
||||
return;
|
||||
}
|
||||
final isCached = await VideoCacheStore.instance.isExistLoadVideoByUrl(MediaStyle.Video, model.url ?? '');
|
||||
final isCached = await VideoCacheStore.instance
|
||||
.isExistLoadVideoByUrl(MediaStyle.Video, model.url ?? '');
|
||||
if (isCached) {
|
||||
showToast('你已经添加过缓存了');
|
||||
return;
|
||||
}
|
||||
|
||||
/// VideoDownloadManager下载到了 应用的外部私有目录中,无需动态权限
|
||||
/// if (!await _checkPermission()) return;
|
||||
final result = await VideoDownloadManager.instance.download(url: model.url ?? '');
|
||||
final result =
|
||||
await VideoDownloadManager.instance.download(url: model.url ?? '');
|
||||
if (result != null) return;
|
||||
final viewModel = VideoModel()
|
||||
..sourceURL = model.url
|
||||
@@ -147,7 +152,8 @@ class AIImageRecord extends StatelessWidget {
|
||||
//视频换脸的结果位单独接播放器,链接由 VideoModel 拼(和 AiRecordModel.realVideoUrl 的 query 不一样)
|
||||
void _playResultVideo() {
|
||||
final videoModel = VideoModel()..sourceURL = model.url;
|
||||
Get.to(SimpleVideoPlayerPage(videoUrl: videoModel.realVideoUrl, title: 'AI生成视频'));
|
||||
Get.to(SimpleVideoPlayerPage(
|
||||
videoUrl: videoModel.realVideoUrl, title: 'AI生成视频'));
|
||||
}
|
||||
|
||||
//三张图:模版 + 素材 = 结果
|
||||
@@ -164,7 +170,10 @@ class AIImageRecord extends StatelessWidget {
|
||||
),
|
||||
const AIRecordJoin(gap: 3.5),
|
||||
],
|
||||
AIRecordThumb(imageUrl: _sourceCover, badge: const AISourceBadge(isTemplate: false), width: 90.w),
|
||||
AIRecordThumb(
|
||||
imageUrl: _sourceCover,
|
||||
badge: const AISourceBadge(isTemplate: false),
|
||||
width: 90.w),
|
||||
const AIRecordJoin(isEquals: true, gap: 3.5),
|
||||
AIResultThumb(
|
||||
imageUrl: _resultCover,
|
||||
|
||||