logo和名称替换
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../models/ai_change_face_video_model.dart';
|
||||
|
||||
@@ -10,7 +10,8 @@ class AIModCell extends StatelessWidget {
|
||||
final bool isSelected;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const AIModCell({super.key, required this.mod, this.isSelected = false, this.onTap});
|
||||
const AIModCell(
|
||||
{super.key, required this.mod, this.isSelected = false, this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -28,7 +29,9 @@ class AIModCell extends StatelessWidget {
|
||||
right: 8,
|
||||
top: 8,
|
||||
child: Image.asset(
|
||||
isSelected ? 'radio_select.png'.commonImgPath : 'ai_draw_unselected.png'.aiPath,
|
||||
isSelected
|
||||
? 'radio_select.png'.commonImgPath
|
||||
: 'ai_draw_unselected.png'.aiPath,
|
||||
width: 20,
|
||||
),
|
||||
),
|
||||
@@ -38,7 +41,10 @@ class AIModCell extends StatelessWidget {
|
||||
const Spacer(),
|
||||
Text(
|
||||
mod.title ?? '',
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .8), fontSize: 14, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .8),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
|
||||
import '../models/ai_record_model.dart';
|
||||
import 'ai_record_parts.dart';
|
||||
@@ -11,7 +11,8 @@ class AIPaintRecord extends StatelessWidget {
|
||||
final int status; // 1 排队 2 成功 3 失败
|
||||
final VoidCallback? onDeleteCallback;
|
||||
|
||||
const AIPaintRecord(this.model, {super.key, required this.status, this.onDeleteCallback});
|
||||
const AIPaintRecord(this.model,
|
||||
{super.key, required this.status, this.onDeleteCallback});
|
||||
|
||||
AIRecordState get _state => switch (status) {
|
||||
2 => AIRecordState.success,
|
||||
@@ -22,10 +23,13 @@ class AIPaintRecord extends StatelessWidget {
|
||||
/// 排队/失败没有结果图,退回模版封面占位。
|
||||
/// 后端在这个接口里放模版封面的字段不固定(styleUrl 常为空),挨个兜一遍,别露占位图
|
||||
String get _templateCover =>
|
||||
[model.styleUrl, model.cover, model.modCover, model.modPic].firstWhere((e) => e?.isNotEmpty == true, orElse: () => '') ?? '';
|
||||
[model.styleUrl, model.cover, model.modCover, model.modPic]
|
||||
.firstWhere((e) => e?.isNotEmpty == true, orElse: () => '') ??
|
||||
'';
|
||||
|
||||
//只有成功才是真结果图;未知 status 按排队处理,与 _state 的口径保持一致
|
||||
String get _resultCover => status == 2 ? (model.newImgUrl ?? '') : _templateCover;
|
||||
String get _resultCover =>
|
||||
status == 2 ? (model.newImgUrl ?? '') : _templateCover;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -71,7 +75,10 @@ class AIPaintRecord extends StatelessWidget {
|
||||
AIResultThumb(
|
||||
imageUrl: _resultCover,
|
||||
state: _state,
|
||||
onTap: _resultCover.isEmpty ? null : () => ImageBrowserPage.open([_resultCover], showSaveButton: true),
|
||||
onTap: _resultCover.isEmpty
|
||||
? null
|
||||
: () =>
|
||||
ImageBrowserPage.open([_resultCover], showSaveButton: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_utils/date_time_util.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_alert.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/date_time_util.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/common_alert.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../../hj_utils/widget_util.dart';
|
||||
|
||||
@@ -13,7 +13,8 @@ import '../../../hj_utils/widget_util.dart';
|
||||
enum AIRecordState { queuing, success, failed }
|
||||
|
||||
/// 失败原因:接口没给就退回通用文案。底部文案和失败弹窗共用,改一处即可
|
||||
String _failedText(String? remark) => remark?.isNotEmpty == true ? remark! : '生成失败';
|
||||
String _failedText(String? remark) =>
|
||||
remark?.isNotEmpty == true ? remark! : '生成失败';
|
||||
|
||||
/// 记录卡:白 5% 底 + 12 圆角,版式固定为
|
||||
/// 创建时间/删除 → 内容 → 细线 → 状态胶囊/下载或失败原因。
|
||||
@@ -60,7 +61,11 @@ class AIRecordCard extends StatelessWidget {
|
||||
12.sizeBoxH,
|
||||
0.5.line,
|
||||
12.sizeBoxH,
|
||||
AIRecordFooter(state: state, remark: remark, onDownload: onDownload, onStatusTap: onStatusTap),
|
||||
AIRecordFooter(
|
||||
state: state,
|
||||
remark: remark,
|
||||
onDownload: onDownload,
|
||||
onStatusTap: onStatusTap),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -68,7 +73,8 @@ class AIRecordCard extends StatelessWidget {
|
||||
//失败原因底部只放得下两行,点卡片看全文。四类记录都走这里,别再各自实现
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque, //卡片内的空白也要能点
|
||||
onTap: () => CommonAlert.show(title: '失败原因', content: _failedText(remark), showCancel: false),
|
||||
onTap: () => CommonAlert.show(
|
||||
title: '失败原因', content: _failedText(remark), showCancel: false),
|
||||
child: card,
|
||||
);
|
||||
}
|
||||
@@ -108,7 +114,12 @@ class AIRecordFooter extends StatelessWidget {
|
||||
final VoidCallback? onDownload;
|
||||
final VoidCallback? onStatusTap;
|
||||
|
||||
const AIRecordFooter({super.key, required this.state, this.remark, this.onDownload, this.onStatusTap});
|
||||
const AIRecordFooter(
|
||||
{super.key,
|
||||
required this.state,
|
||||
this.remark,
|
||||
this.onDownload,
|
||||
this.onStatusTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -117,7 +128,8 @@ class AIRecordFooter extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
AIStatusPill(state, onTap: state == AIRecordState.success ? onStatusTap : null),
|
||||
AIStatusPill(state,
|
||||
onTap: state == AIRecordState.success ? onStatusTap : null),
|
||||
if (state == AIRecordState.success && onDownload != null)
|
||||
AIDownloadBtn(onTap: onDownload)
|
||||
else if (state == AIRecordState.failed)
|
||||
@@ -154,13 +166,18 @@ class AIStatusPill extends StatelessWidget {
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||
decoration:
|
||||
isFailed ? null : BoxDecoration(color: const Color(0x1AFFDB9E), borderRadius: BorderRadius.circular(3)),
|
||||
decoration: isFailed
|
||||
? null
|
||||
: BoxDecoration(
|
||||
color: const Color(0x1AFFDB9E),
|
||||
borderRadius: BorderRadius.circular(3)),
|
||||
child: Text(
|
||||
text,
|
||||
style: textStyle(
|
||||
13,
|
||||
isFailed ? Colors.white.withValues(alpha: .55) : const Color(0xffFFDB9E),
|
||||
isFailed
|
||||
? Colors.white.withValues(alpha: .55)
|
||||
: const Color(0xffFFDB9E),
|
||||
FontWeight.w400,
|
||||
),
|
||||
),
|
||||
@@ -183,14 +200,16 @@ class AIDownloadBtn extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 0.5, color: Colors.white.withValues(alpha: .15)),
|
||||
border: Border.all(
|
||||
width: 0.5, color: Colors.white.withValues(alpha: .15)),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset('icon_ai_download.png'.aiPath, width: 18),
|
||||
2.5.sizeBoxW,
|
||||
const Text('一键下载', style: TextStyle(color: Colors.white, fontSize: 12)),
|
||||
const Text('一键下载',
|
||||
style: TextStyle(color: Colors.white, fontSize: 12)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -206,7 +225,8 @@ class AIRecordThumb extends StatelessWidget {
|
||||
final VoidCallback? onTap;
|
||||
final double width;
|
||||
|
||||
const AIRecordThumb({super.key, this.imageUrl, this.badge, this.onTap, this.width = 90});
|
||||
const AIRecordThumb(
|
||||
{super.key, this.imageUrl, this.badge, this.onTap, this.width = 90});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -222,7 +242,11 @@ class AIRecordThumb extends StatelessWidget {
|
||||
color: Color(0xff262626),
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
child: NetworkImageLoader(imageUrl: imageUrl, width: width, height: 90, borderRadius: 8),
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: imageUrl,
|
||||
width: width,
|
||||
height: 90,
|
||||
borderRadius: 8),
|
||||
),
|
||||
if (badge != null) badge!,
|
||||
],
|
||||
@@ -239,7 +263,12 @@ class AIResultThumb extends StatelessWidget {
|
||||
final VoidCallback? onTap;
|
||||
final double width;
|
||||
|
||||
const AIResultThumb({super.key, this.imageUrl, required this.state, this.onTap, this.width = 90});
|
||||
const AIResultThumb(
|
||||
{super.key,
|
||||
this.imageUrl,
|
||||
required this.state,
|
||||
this.onTap,
|
||||
this.width = 90});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -260,7 +289,10 @@ class AIResultThumb extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
if (state == AIRecordState.failed)
|
||||
Positioned.fill(child: Center(child: Image.asset('ai_record_failed.webp'.aiPath, width: 20))),
|
||||
Positioned.fill(
|
||||
child: Center(
|
||||
child:
|
||||
Image.asset('ai_record_failed.webp'.aiPath, width: 20))),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_page/video/simple_video_player_page.dart';
|
||||
import 'package:hgmj/hj_utils/date_time_util.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/header_widget.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/video/simple_video_player_page.dart';
|
||||
import 'package:wydj/hj_utils/date_time_util.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/header_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../../hj_utils/widget_util.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
import '../ai_sub_type/ai_function_logic.dart';
|
||||
import '../models/ai_square_model.dart';
|
||||
|
||||
@@ -39,7 +39,9 @@ class AISquareCell extends StatelessWidget {
|
||||
|
||||
Widget _imgView() {
|
||||
return switch (AiTypeCode.fromServerCode(model.type)) {
|
||||
AiType.imageChangeFace || AiType.autoStrip => _twoImgsView(model.originalImage, model.generateImage),
|
||||
AiType.imageChangeFace ||
|
||||
AiType.autoStrip =>
|
||||
_twoImgsView(model.originalImage, model.generateImage),
|
||||
AiType.videoChangeFace => _videoChangeFace(),
|
||||
AiType.imageToVideo => _imgToVideo(),
|
||||
AiType.aiPaint => _aiDraw(),
|
||||
@@ -53,20 +55,24 @@ class AISquareCell extends StatelessWidget {
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => ImageBrowserPage.open([left ?? ''], showSaveButton: true),
|
||||
onTap: () =>
|
||||
ImageBrowserPage.open([left ?? ''], showSaveButton: true),
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: left,
|
||||
imgBorderRadius: const BorderRadius.horizontal(left: Radius.circular(9)),
|
||||
imgBorderRadius:
|
||||
const BorderRadius.horizontal(left: Radius.circular(9)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => ImageBrowserPage.open([right ?? ''], showSaveButton: true),
|
||||
onTap: () =>
|
||||
ImageBrowserPage.open([right ?? ''], showSaveButton: true),
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: right,
|
||||
imgBorderRadius: const BorderRadius.horizontal(right: Radius.circular(9)),
|
||||
imgBorderRadius:
|
||||
const BorderRadius.horizontal(right: Radius.circular(9)),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -80,7 +86,10 @@ class AISquareCell extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
'“${model.originContent ?? ''}”',
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff03FCEB)),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xff03FCEB)),
|
||||
),
|
||||
12.sizeBoxH,
|
||||
Row(
|
||||
@@ -88,7 +97,8 @@ class AISquareCell extends StatelessWidget {
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => ImageBrowserPage.open([model.generateImage ?? ''], showSaveButton: true),
|
||||
onTap: () => ImageBrowserPage.open([model.generateImage ?? ''],
|
||||
showSaveButton: true),
|
||||
child: NetworkImageLoader(imageUrl: model.generateImage),
|
||||
),
|
||||
),
|
||||
@@ -113,7 +123,9 @@ class AISquareCell extends StatelessWidget {
|
||||
Widget _videoChangeFace() {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(child: _videoItem(model.generateVideoCover, model.realGenerateVideoUrl)),
|
||||
Expanded(
|
||||
child: _videoItem(
|
||||
model.generateVideoCover, model.realGenerateVideoUrl)),
|
||||
10.sizeBoxW,
|
||||
const Expanded(child: SizedBox.shrink()),
|
||||
],
|
||||
@@ -141,7 +153,10 @@ class AISquareCell extends StatelessWidget {
|
||||
style: textStyle(10, Colors.white, FontWeight.w500),
|
||||
),
|
||||
)),
|
||||
TextSpan(text: model.title, style: textStyle(14, Colors.white.withValues(alpha: .9), FontWeight.w500))
|
||||
TextSpan(
|
||||
text: model.title,
|
||||
style: textStyle(
|
||||
14, Colors.white.withValues(alpha: .9), FontWeight.w500))
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -175,7 +190,8 @@ class AISquareCell extends StatelessWidget {
|
||||
10.sizeBoxW,
|
||||
Text(
|
||||
DateTimeUtil.utcTurnYear(model.reviewAt),
|
||||
style: textStyle(12, Colors.white.withValues(alpha: 0.55), FontWeight.w400),
|
||||
style: textStyle(12, Colors.white.withValues(alpha: 0.55),
|
||||
FontWeight.w400),
|
||||
)
|
||||
],
|
||||
)
|
||||
@@ -189,7 +205,9 @@ class AISquareCell extends StatelessWidget {
|
||||
width: 70,
|
||||
height: 24,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(3), color: AppColors.actionRed),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
color: AppColors.actionRed),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
@@ -218,7 +236,8 @@ class AISquareCell extends StatelessWidget {
|
||||
Widget _videoItem(String? img, String url) {
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.to(() => SimpleVideoPlayerPage(videoUrl: url, title: model.title ?? '')),
|
||||
onTap: () => Get.to(
|
||||
() => SimpleVideoPlayerPage(videoUrl: url, title: model.title ?? '')),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
|
||||
import '../models/ai_record_model.dart';
|
||||
import 'ai_record_parts.dart';
|
||||
@@ -12,7 +12,8 @@ class AIVideoRecord extends StatelessWidget {
|
||||
final int status; // 1 排队 2 成功 3 失败
|
||||
final VoidCallback? onDeleteCallback;
|
||||
|
||||
const AIVideoRecord(this.model, {super.key, required this.status, this.onDeleteCallback});
|
||||
const AIVideoRecord(this.model,
|
||||
{super.key, required this.status, this.onDeleteCallback});
|
||||
|
||||
AIRecordState get _state => switch (status) {
|
||||
2 => AIRecordState.success,
|
||||
@@ -20,7 +21,8 @@ class AIVideoRecord extends StatelessWidget {
|
||||
_ => AIRecordState.queuing,
|
||||
};
|
||||
|
||||
String get _resultCover => model.status == 3 ? (model.newImgUrl ?? '') : (model.imgUrl ?? '');
|
||||
String get _resultCover =>
|
||||
model.status == 3 ? (model.newImgUrl ?? '') : (model.imgUrl ?? '');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -51,13 +53,17 @@ class AIVideoRecord extends StatelessWidget {
|
||||
children: [
|
||||
AIRecordThumb(
|
||||
imageUrl: model.imgUrl,
|
||||
badge: Image.asset('ai_record_org.png'.aiPath, width: 36, height: 18),
|
||||
badge:
|
||||
Image.asset('ai_record_org.png'.aiPath, width: 36, height: 18),
|
||||
),
|
||||
const AIRecordJoin(isEquals: true),
|
||||
AIResultThumb(
|
||||
imageUrl: _resultCover,
|
||||
state: _state,
|
||||
onTap: _resultCover.isEmpty ? null : () => ImageBrowserPage.open([_resultCover], showSaveButton: true),
|
||||
onTap: _resultCover.isEmpty
|
||||
? null
|
||||
: () =>
|
||||
ImageBrowserPage.open([_resultCover], showSaveButton: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_pickers/image_pickers.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/tools_base/toast.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/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:mobkit_dashed_border/mobkit_dashed_border.dart';
|
||||
|
||||
/// AI 功能的单图选择器:未选时是虚线占位框,选后是缩略图 + 右上角删除
|
||||
@@ -54,7 +54,8 @@ class _PicPickerState extends State<PicPicker> {
|
||||
selectCount: 1,
|
||||
showCamera: true,
|
||||
);
|
||||
final paths = medias.map((e) => e.path ?? "").where((e) => e.isNotEmpty).toList();
|
||||
final paths =
|
||||
medias.map((e) => e.path ?? "").where((e) => e.isNotEmpty).toList();
|
||||
if (paths.length < medias.length) showToast("添加图片失败");
|
||||
return paths;
|
||||
}
|
||||
@@ -92,7 +93,8 @@ class _PicPickerState extends State<PicPicker> {
|
||||
onTap: _delPic,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Image.asset("close_grey.png".commonImgPath, width: 14, height: 14),
|
||||
child: Image.asset("close_grey.png".commonImgPath,
|
||||
width: 14, height: 14),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -120,7 +122,8 @@ class _PicPickerState extends State<PicPicker> {
|
||||
children: [
|
||||
Image.asset('add_grey.png'.communityPath, width: 24),
|
||||
10.sizeBoxH,
|
||||
const Text("添加图片", style: TextStyle(fontSize: 12, color: Color(0xff999999))),
|
||||
const Text("添加图片",
|
||||
style: TextStyle(fontSize: 12, color: Color(0xff999999))),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/routers/jump_router.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/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../config/config.dart';
|
||||
import '../../hj_model/cartoon_media_info.dart';
|
||||
@@ -83,7 +83,10 @@ class AcgItemWidget extends StatelessWidget {
|
||||
child: Text(
|
||||
'${info?.episodeNumberStatus ?? ''} · ${info?.updateDesc}',
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(fontSize: 11, color: _statusColor, fontWeight: FontWeight.w400),
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: _statusColor,
|
||||
fontWeight: FontWeight.w400),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -96,8 +99,12 @@ class AcgItemWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildLevelIcon() {
|
||||
if (info?.permission == 1 && Config.coinMark) return _levelTag('金币', const Color(0xFF1F2029), bgColor: [const Color(0xFFFFE580), const Color(0xFFFACC15)]);
|
||||
if (info?.permission == 0 && Config.vipMark) return _levelTag('VIP', Colors.white, bgColor: [ const Color(0xFFFF8000), const Color(0xFFFF7A01)]);
|
||||
if (info?.permission == 1 && Config.coinMark)
|
||||
return _levelTag('金币', const Color(0xFF1F2029),
|
||||
bgColor: [const Color(0xFFFFE580), const Color(0xFFFACC15)]);
|
||||
if (info?.permission == 0 && Config.vipMark)
|
||||
return _levelTag('VIP', Colors.white,
|
||||
bgColor: [const Color(0xFFFF8000), const Color(0xFFFF7A01)]);
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
@@ -107,7 +114,8 @@ class AcgItemWidget extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(2)),
|
||||
gradient: LinearGradient(colors: bgColor ?? [Color(0xffFFC000), Color(0xffFFC000)]),
|
||||
gradient: LinearGradient(
|
||||
colors: bgColor ?? [Color(0xffFFC000), Color(0xffFFC000)]),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
@@ -117,6 +125,8 @@ class AcgItemWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
Color get _statusColor {
|
||||
return info?.updateStatus == 1 ? const Color(0xffFFC000) : Colors.white.withValues(alpha: .45);
|
||||
return info?.updateStatus == 1
|
||||
? const Color(0xffFFC000)
|
||||
: Colors.white.withValues(alpha: .45);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/acg/comic_chapters_model.dart';
|
||||
import 'package:hgmj/hj_page/live/live_widget.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/acg/comic_chapters_model.dart';
|
||||
import 'package:wydj/hj_page/live/live_widget.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
|
||||
import '../../assets_tool/app_colors.dart';
|
||||
import '../../hj_utils/widget_util.dart';
|
||||
import 'widget/free_badge.dart';
|
||||
import 'package:hgmj/tools_base/widget/stagger_in_item.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/tools_base/widget/stagger_in_item.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
|
||||
//有声小说 选择子集
|
||||
class AudioPlayerBottomSheet extends StatefulWidget {
|
||||
@@ -62,7 +62,8 @@ class _AudioPlayerBottomSheetState extends State<AudioPlayerBottomSheet> {
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => setState(() => sortType = sortType == 1 ? 0 : 1),
|
||||
child: Row(
|
||||
children: [
|
||||
@@ -70,12 +71,14 @@ class _AudioPlayerBottomSheetState extends State<AudioPlayerBottomSheet> {
|
||||
turns: sortType == 1 ? 0 : 0.5,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeOutCubic,
|
||||
child: Image.asset('text_play_sort.png'.acgImgPath, width: 18),
|
||||
child: Image.asset('text_play_sort.png'.acgImgPath,
|
||||
width: 18),
|
||||
),
|
||||
4.sizeBoxW,
|
||||
Text(
|
||||
sortType == 1 ? '正序' : '倒序',
|
||||
style: textStyle(12, Colors.white.withValues(alpha: .45), FontWeight.w400),
|
||||
style: textStyle(12, Colors.white.withValues(alpha: .45),
|
||||
FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -96,52 +99,57 @@ class _AudioPlayerBottomSheetState extends State<AudioPlayerBottomSheet> {
|
||||
final model = widget.allAudiobooks[realIndex];
|
||||
final select = widget.currentPlayIndex == realIndex;
|
||||
return StaggerInItem(
|
||||
index: index,
|
||||
child: InkWell(enableFeedback: false,
|
||||
onTap: () {
|
||||
Get.back(result: realIndex);
|
||||
widget.indexHandler?.call(realIndex);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(bottom: 6),
|
||||
child: Column(
|
||||
children: [
|
||||
16.sizeBoxH,
|
||||
Row(
|
||||
index: index,
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
Get.back(result: realIndex);
|
||||
widget.indexHandler?.call(realIndex);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(bottom: 6),
|
||||
child: Column(
|
||||
children: [
|
||||
if (select) ...[
|
||||
AudioWaveView(),
|
||||
8.sizeBoxW,
|
||||
],
|
||||
Expanded(
|
||||
child: Text(
|
||||
//与详情/抽屉子集 title 格式一致:第X章
|
||||
'第${model.episodeNumber ?? 1}${widget.unit ?? ''}',
|
||||
style: TextStyle(
|
||||
color: select ? AppColors.actionRed : Colors.white.withValues(alpha: .9),
|
||||
fontSize: 14,
|
||||
16.sizeBoxH,
|
||||
Row(
|
||||
children: [
|
||||
if (select) ...[
|
||||
AudioWaveView(),
|
||||
8.sizeBoxW,
|
||||
],
|
||||
Expanded(
|
||||
child: Text(
|
||||
//与详情/抽屉子集 title 格式一致:第X章
|
||||
'第${model.episodeNumber ?? 1}${widget.unit ?? ''}',
|
||||
style: TextStyle(
|
||||
color: select
|
||||
? AppColors.actionRed
|
||||
: Colors.white
|
||||
.withValues(alpha: .9),
|
||||
fontSize: 14,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
//无任何权限时,前 N 集免费展示「免费」角标
|
||||
if (widget.hasPermission == false &&
|
||||
model.inFreeEpisode) ...[
|
||||
8.sizeBoxW,
|
||||
const FreeBadge(),
|
||||
],
|
||||
8.sizeBoxW,
|
||||
const Icon(
|
||||
Icons.navigate_next,
|
||||
size: 18,
|
||||
color: Color(0xffDCDCDC),
|
||||
)
|
||||
],
|
||||
),
|
||||
//无任何权限时,前 N 集免费展示「免费」角标
|
||||
if (widget.hasPermission == false && model.inFreeEpisode) ...[
|
||||
8.sizeBoxW,
|
||||
const FreeBadge(),
|
||||
],
|
||||
8.sizeBoxW,
|
||||
const Icon(
|
||||
Icons.navigate_next,
|
||||
size: 18,
|
||||
color: Color(0xffDCDCDC),
|
||||
)
|
||||
16.sizeBoxH,
|
||||
],
|
||||
),
|
||||
16.sizeBoxH,
|
||||
],
|
||||
)),
|
||||
));
|
||||
)),
|
||||
));
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
@@ -2,11 +2,11 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.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/hj_utils/date_time_util.dart';
|
||||
import 'package:hgmj/hj_utils/screen.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_utils/date_time_util.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import 'audio_player_bottomsheet.dart';
|
||||
import 'widget/acg_source_manager.dart';
|
||||
@@ -16,7 +16,8 @@ class AudioPlayerContent extends StatefulWidget {
|
||||
final int index;
|
||||
final AudioPlayerManager manager;
|
||||
final ACGSourceManager sourceManager;
|
||||
const AudioPlayerContent(this.sourceManager, {super.key, required this.manager, this.index = 0});
|
||||
const AudioPlayerContent(this.sourceManager,
|
||||
{super.key, required this.manager, this.index = 0});
|
||||
|
||||
@override
|
||||
State<AudioPlayerContent> createState() => _AudioPlayerContentState();
|
||||
@@ -33,7 +34,8 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
// - onInit 已 initPlayer
|
||||
// - onClose 已 dispose
|
||||
// 此处不要再调 initPlayer,否则 4 个 stream listener 重复注册导致旧 sub 泄漏
|
||||
manager.play(widget.sourceManager.allEpisodes[widget.index].getRealAudioUrl);
|
||||
manager
|
||||
.play(widget.sourceManager.allEpisodes[widget.index].getRealAudioUrl);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -60,7 +62,10 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
children: [
|
||||
Text(
|
||||
'正在播放:第${(audioValue.onPlayIndex ?? 0) + 1}集',
|
||||
style: TextStyle(color: Colors.white, fontSize: 16.sp, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -76,7 +81,8 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
}
|
||||
|
||||
// 进度条行:左右 ±10s 快进退、中间滑块、两侧时间
|
||||
Widget _progressRow(AudioPlayerValue audioValue, double progress, double max) {
|
||||
Widget _progressRow(
|
||||
AudioPlayerValue audioValue, double progress, double max) {
|
||||
return Row(
|
||||
children: [
|
||||
Column(
|
||||
@@ -96,7 +102,10 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
buildMMSS(audioValue.position?.inSeconds ?? 0),
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .9), fontSize: 12, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .9),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -115,7 +124,8 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => manager.seekTenMinsWithDirection(1),
|
||||
child: Image.asset('noval_time_forword.png'.acgImgPath, width: 24),
|
||||
child:
|
||||
Image.asset('noval_time_forword.png'.acgImgPath, width: 24),
|
||||
),
|
||||
8.sizeBoxH,
|
||||
SizedBox(
|
||||
@@ -158,9 +168,12 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
children: [
|
||||
AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 150),
|
||||
transitionBuilder: (child, anim) => ScaleTransition(scale: anim, child: child),
|
||||
transitionBuilder: (child, anim) =>
|
||||
ScaleTransition(scale: anim, child: child),
|
||||
child: Image.asset(
|
||||
isLoop ? 'single_cycle.png'.acgImgPath : 'list_cycle.png'.acgImgPath,
|
||||
isLoop
|
||||
? 'single_cycle.png'.acgImgPath
|
||||
: 'list_cycle.png'.acgImgPath,
|
||||
// key 必须按状态区分,AnimatedSwitcher 才会把它当成新 child 触发动画
|
||||
key: ValueKey(isLoop ? 'loop' : 'loop_list'),
|
||||
width: 24,
|
||||
@@ -169,7 +182,10 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
2.sizeBoxH,
|
||||
Text(
|
||||
isLoop ? '单曲循环' : '多集循环',
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .9), fontSize: 12, fontWeight: FontWeight.w400),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .9),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -188,7 +204,8 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
onTap: () => isPlaying ? manager.pause() : manager.resume(),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 150),
|
||||
transitionBuilder: (child, anim) => ScaleTransition(scale: anim, child: child),
|
||||
transitionBuilder: (child, anim) =>
|
||||
ScaleTransition(scale: anim, child: child),
|
||||
child: Image.asset(
|
||||
isPlaying ? 'pause.png'.acgImgPath : 'play.png'.acgImgPath,
|
||||
key: ValueKey(isPlaying ? 'pause' : 'play'),
|
||||
@@ -214,7 +231,10 @@ class _AudioPlayerContentState extends State<AudioPlayerContent> {
|
||||
2.sizeBoxH,
|
||||
Text(
|
||||
'播放列表',
|
||||
style: TextStyle(color: Colors.white.withValues(alpha: .9), fontSize: 12, fontWeight: FontWeight.w400),
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .9),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -278,7 +298,8 @@ class GradientTrackShape extends SliderTrackShape {
|
||||
}) {
|
||||
final trackHeight = sliderTheme.trackHeight ?? 2;
|
||||
final trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
|
||||
return Rect.fromLTWH(offset.dx, trackTop, parentBox.size.width, trackHeight);
|
||||
return Rect.fromLTWH(
|
||||
offset.dx, trackTop, parentBox.size.width, trackHeight);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -303,12 +324,14 @@ class GradientTrackShape extends SliderTrackShape {
|
||||
final inactivePaint = Paint()..color = const Color(0xff3D3D3D);
|
||||
// 左侧已播放
|
||||
context.canvas.drawRect(
|
||||
Rect.fromLTRB(trackRect.left, trackRect.top, thumbCenter.dx, trackRect.bottom),
|
||||
Rect.fromLTRB(
|
||||
trackRect.left, trackRect.top, thumbCenter.dx, trackRect.bottom),
|
||||
activePaint,
|
||||
);
|
||||
// 右侧未播放
|
||||
context.canvas.drawRect(
|
||||
Rect.fromLTRB(thumbCenter.dx, trackRect.top, trackRect.right, trackRect.bottom),
|
||||
Rect.fromLTRB(
|
||||
thumbCenter.dx, trackRect.top, trackRect.right, trackRect.bottom),
|
||||
inactivePaint,
|
||||
);
|
||||
}
|
||||
@@ -321,7 +344,8 @@ class GradientThumbShape extends SliderComponentShape {
|
||||
const GradientThumbShape({this.radius = 8});
|
||||
|
||||
@override
|
||||
Size getPreferredSize(bool isEnabled, bool isDiscrete) => Size.fromRadius(radius);
|
||||
Size getPreferredSize(bool isEnabled, bool isDiscrete) =>
|
||||
Size.fromRadius(radius);
|
||||
|
||||
@override
|
||||
void paint(
|
||||
@@ -339,7 +363,8 @@ class GradientThumbShape extends SliderComponentShape {
|
||||
required double value,
|
||||
}) {
|
||||
final canvas = context.canvas;
|
||||
final outerPaint = Paint()..color = AppColors.actionRed.withValues(alpha: 0.7);
|
||||
final outerPaint = Paint()
|
||||
..color = AppColors.actionRed.withValues(alpha: 0.7);
|
||||
final innerPaint = Paint()..color = Colors.white;
|
||||
canvas.drawCircle(center, radius, outerPaint);
|
||||
canvas.drawCircle(center, radius - 3, innerPaint);
|
||||
|
||||
@@ -2,9 +2,9 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/events.dart';
|
||||
import 'package:hgmj/tools_base/widget/scroll_positioned_list/src/scrollable_positioned_list.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/event_bus/events.dart';
|
||||
import 'package:wydj/tools_base/widget/scroll_positioned_list/src/scrollable_positioned_list.dart';
|
||||
|
||||
import '../../../hj_model/acg/comic_chapters_model.dart';
|
||||
import '../../../hj_model/cartoon_media_info.dart';
|
||||
@@ -15,7 +15,8 @@ import 'cartoon_read_page.dart';
|
||||
import 'widget/acg_source_manager.dart';
|
||||
import 'widget/cartoon_subset_alert.dart';
|
||||
|
||||
class CartoonDetailLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
class CartoonDetailLogic extends GetxController
|
||||
with GetTickerProviderStateMixin {
|
||||
String? id;
|
||||
CartoonMediaInfo? mediaInfo;
|
||||
|
||||
@@ -39,7 +40,8 @@ class CartoonDetailLogic extends GetxController with GetTickerProviderStateMixin
|
||||
late ACGSourceManager manager;
|
||||
late StreamSubscription subscription;
|
||||
|
||||
CartoonDetailLogic({this.id}) : manager = ACGSourceManager(id ?? ''); //初始化,加载子集
|
||||
CartoonDetailLogic({this.id})
|
||||
: manager = ACGSourceManager(id ?? ''); //初始化,加载子集
|
||||
|
||||
@override
|
||||
void onReady() async {
|
||||
@@ -88,7 +90,8 @@ class CartoonDetailLogic extends GetxController with GetTickerProviderStateMixin
|
||||
|
||||
play() async {
|
||||
//判断权限
|
||||
ComicChapterInfo? info = await manager.getEpisodeHasPermisson(manager.index);
|
||||
ComicChapterInfo? info =
|
||||
await manager.getEpisodeHasPermisson(manager.index);
|
||||
if (info == null) return;
|
||||
Get.to(() => CartoonReadPage(manager: manager..index = manager.index));
|
||||
}
|
||||
|
||||
@@ -3,15 +3,15 @@ import 'dart:math';
|
||||
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.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/extension/extensions.dart';
|
||||
import 'package:hgmj/tools_base/indicator/custom_tab_indicator.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:hgmj/tools_base/widget/follow_button.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.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/extension/extensions.dart';
|
||||
import 'package:wydj/tools_base/indicator/custom_tab_indicator.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:wydj/tools_base/widget/follow_button.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../../hj_utils/const.dart';
|
||||
@@ -38,7 +38,8 @@ class CartoonDetailPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
// 详情页可经「推荐页 → 再开详情页」成环并存,用 UniqueTagMixin 给每个实例唯一 tag
|
||||
class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMixin {
|
||||
class _CartoonDetailPageState extends State<CartoonDetailPage>
|
||||
with UniqueTagMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -65,7 +66,8 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
}
|
||||
|
||||
// 当前内容对应的推荐类型(小说等无对应 tab 时为 null)
|
||||
MediaStyle? _selfStyle(CartoonDetailLogic logic) => switch (logic.mediaInfo?.mediaType) {
|
||||
MediaStyle? _selfStyle(CartoonDetailLogic logic) =>
|
||||
switch (logic.mediaInfo?.mediaType) {
|
||||
'video' => MediaStyle.Cartoon,
|
||||
'image' => MediaStyle.Comics,
|
||||
_ => null,
|
||||
@@ -111,7 +113,8 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
return [
|
||||
SliverToBoxAdapter(child: _buildImgHeader(logic)), //header
|
||||
SliverToBoxAdapter(child: _buildMenu(logic)), //目录
|
||||
SliverToBoxAdapter(child: _buildTabbar(logic, styles)) //推荐 tabbar
|
||||
SliverToBoxAdapter(
|
||||
child: _buildTabbar(logic, styles)) //推荐 tabbar
|
||||
];
|
||||
},
|
||||
//推荐
|
||||
@@ -137,8 +140,10 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
if (logic.isCartoonType) ...[
|
||||
Consumer<ACGSourceManager>(
|
||||
builder: (context, manager, child) {
|
||||
bool liked = manager.mediaInfo?.mediaStatus?.hasLiked == true;
|
||||
return InkWell(enableFeedback: false,
|
||||
bool liked =
|
||||
manager.mediaInfo?.mediaStatus?.hasLiked == true;
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => manager.onLikeAction(),
|
||||
child: Container(
|
||||
width: 108,
|
||||
@@ -152,13 +157,16 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
liked ? 'acg_like_sel.png'.acgImgPath : 'acg_like_nor.png'.acgImgPath,
|
||||
liked
|
||||
? 'acg_like_sel.png'.acgImgPath
|
||||
: 'acg_like_nor.png'.acgImgPath,
|
||||
width: 16,
|
||||
),
|
||||
10.sizeBoxW,
|
||||
Text(
|
||||
'喜欢',
|
||||
style: textStyle(16, Color(0xff989898), FontWeight.w500),
|
||||
style: textStyle(
|
||||
16, Color(0xff989898), FontWeight.w500),
|
||||
),
|
||||
],
|
||||
)),
|
||||
@@ -168,7 +176,8 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
12.sizeBoxW,
|
||||
],
|
||||
Expanded(
|
||||
child: InkWell(enableFeedback: false,
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.play(),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
@@ -268,12 +277,14 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
if (logic.mediaInfo?.permission == 0) ...[
|
||||
Text(
|
||||
'VIP',
|
||||
style: textStyle(12, Color(0xff989898), FontWeight.w400),
|
||||
style:
|
||||
textStyle(12, Color(0xff989898), FontWeight.w400),
|
||||
),
|
||||
] else if (logic.mediaInfo?.permission == 1) ...[
|
||||
Text(
|
||||
'${logic.mediaInfo?.price ?? 0}金币',
|
||||
style: textStyle(12, Color(0xff989898), FontWeight.w400),
|
||||
style:
|
||||
textStyle(12, Color(0xff989898), FontWeight.w400),
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -300,7 +311,8 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemBuilder: (context, index) {
|
||||
TagsBean? tag = logic.mediaInfo?.tagDetails?[index];
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
Get.to(CartoonTagPage(
|
||||
title: tag?.name ?? '',
|
||||
@@ -310,8 +322,9 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
alignment: Alignment.center,
|
||||
decoration:
|
||||
BoxDecoration(color: Colors.white.withValues(alpha: .05), borderRadius: BorderRadius.circular(3)),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: .05),
|
||||
borderRadius: BorderRadius.circular(3)),
|
||||
height: 26,
|
||||
child: Text(
|
||||
tag?.name ?? '',
|
||||
@@ -375,7 +388,8 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
labelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
labelColor: Colors.white.withValues(alpha: 0.9),
|
||||
unselectedLabelColor: Colors.white.withValues(alpha: .55),
|
||||
unselectedLabelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
unselectedLabelStyle:
|
||||
TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
indicator: CustomIndicator(
|
||||
isGradient: true,
|
||||
width: 13,
|
||||
@@ -397,7 +411,9 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
logic.isCartoonType ? '选集' : '共${logic.mediaInfo?.totalEpisode ?? 0}${logic.mediaInfo?.unit}',
|
||||
logic.isCartoonType
|
||||
? '选集'
|
||||
: '共${logic.mediaInfo?.totalEpisode ?? 0}${logic.mediaInfo?.unit}',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
@@ -407,10 +423,13 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
Spacer(),
|
||||
Row(
|
||||
children: [
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: logic.onMenuAction,
|
||||
child: Text(
|
||||
logic.isCartoonType ? '全${logic.mediaInfo?.totalEpisode ?? 0}${logic.mediaInfo?.unit}' : '目录',
|
||||
logic.isCartoonType
|
||||
? '全${logic.mediaInfo?.totalEpisode ?? 0}${logic.mediaInfo?.unit}'
|
||||
: '目录',
|
||||
style: TextStyle(
|
||||
color: Color(0xFFA7A7A7),
|
||||
fontSize: 14,
|
||||
@@ -437,10 +456,12 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
final epm = provider.allEpisodes[index];
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.changeEpisode(index, false),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: logic.isCartoonType ? 6 : 12),
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: logic.isCartoonType ? 6 : 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
@@ -450,13 +471,18 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: textStyle(
|
||||
16,
|
||||
provider.index == index ? Colors.white.withValues(alpha: .9) : Colors.white.withValues(alpha: .45),
|
||||
provider.index == index ? FontWeight.w500 : FontWeight.w400,
|
||||
provider.index == index
|
||||
? Colors.white.withValues(alpha: .9)
|
||||
: Colors.white.withValues(alpha: .45),
|
||||
provider.index == index
|
||||
? FontWeight.w500
|
||||
: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
//无任何权限时,前 N 集免费展示「免费」角标
|
||||
if (provider.mediaInfo?.hasPermission == false && epm.inFreeEpisode) ...[
|
||||
if (provider.mediaInfo?.hasPermission == false &&
|
||||
epm.inFreeEpisode) ...[
|
||||
8.sizeBoxW,
|
||||
const FreeBadge(),
|
||||
],
|
||||
@@ -478,7 +504,8 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
}
|
||||
|
||||
Widget _buildBackView() {
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
child: Image.asset(
|
||||
'back_circle_grey.png'.commonImgPath,
|
||||
width: 24,
|
||||
@@ -488,7 +515,8 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
}
|
||||
|
||||
Widget _buildShareView(CartoonDetailLogic logic) {
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
Get.dialog(
|
||||
ShareMediaDialog(
|
||||
@@ -510,20 +538,25 @@ class _CartoonDetailPageState extends State<CartoonDetailPage> with UniqueTagMix
|
||||
return Offstage(
|
||||
offstage: logic.showHeader,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 16, right: 16, top: screen.paddingTop),
|
||||
padding:
|
||||
EdgeInsets.only(left: 16, right: 16, top: screen.paddingTop),
|
||||
height: 44 + screen.paddingTop,
|
||||
color: Color(0xff05000E),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => Get.back(),
|
||||
child: Icon(Icons.arrow_back_ios, size: 24, color: Colors.white),
|
||||
child:
|
||||
Icon(Icons.arrow_back_ios, size: 24, color: Colors.white),
|
||||
),
|
||||
8.sizeBoxW,
|
||||
Expanded(
|
||||
child: Text(
|
||||
logic.mediaInfo?.title ?? '',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white),
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/media_content.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/scroll_positioned_list/src/item_positions_listener.dart';
|
||||
import 'package:hgmj/tools_base/widget/scroll_positioned_list/src/scrollable_positioned_list.dart';
|
||||
import 'package:wydj/hj_model/media_content.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/scroll_positioned_list/src/item_positions_listener.dart';
|
||||
import 'package:wydj/tools_base/widget/scroll_positioned_list/src/scrollable_positioned_list.dart';
|
||||
|
||||
import 'widget/acg_source_manager.dart';
|
||||
|
||||
@@ -156,9 +156,11 @@ class CartoonReadLogic extends GetxController {
|
||||
/// [isFirstLoad] 失败时才进错误页
|
||||
Future<void> _openEpisode(int index, {bool isFirstLoad = false}) async {
|
||||
// 首次进入页面已有全屏 loading,不再叠遮罩
|
||||
final model = await manager.getComicsMediaContent(index: index, showLoading: !isFirstLoad);
|
||||
final model = await manager.getComicsMediaContent(
|
||||
index: index, showLoading: !isFirstLoad);
|
||||
if (model == null) {
|
||||
if (isFirstLoad) detailInfo = MediaContent(); // 空 model → id 为 null → 页面走错误态
|
||||
if (isFirstLoad)
|
||||
detailInfo = MediaContent(); // 空 model → id 为 null → 页面走错误态
|
||||
update();
|
||||
return;
|
||||
}
|
||||
@@ -196,7 +198,8 @@ class CartoonReadLogic extends GetxController {
|
||||
void _startTimer() {
|
||||
_timer?.cancel(); // 防重入:先停旧的再建新的,避免重复开启时旧定时器泄漏
|
||||
_timer = Timer.periodic(const Duration(milliseconds: 500), (_) {
|
||||
scrollOffsetCtr.animateScroll(offset: 50, duration: const Duration(milliseconds: 500));
|
||||
scrollOffsetCtr.animateScroll(
|
||||
offset: 50, duration: const Duration(milliseconds: 500));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,23 +3,23 @@ import 'dart:math';
|
||||
import 'package:flutter/material.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/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_page/comment/comment_alert.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/tools_base/widget/follow_button.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/scroll_positioned_list/src/scrollable_positioned_list.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/comment/comment_alert.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/widget/follow_button.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/scroll_positioned_list/src/scrollable_positioned_list.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../alert/video/share_media_dialog.dart';
|
||||
import '../../hj_utils/widget_util.dart';
|
||||
import 'cartoon_read_logic.dart';
|
||||
import 'widget/acg_source_manager.dart';
|
||||
import 'package:hgmj/tools_base/widget/stagger_in_item.dart';
|
||||
import 'package:wydj/tools_base/widget/stagger_in_item.dart';
|
||||
|
||||
// 漫画阅读页面
|
||||
class CartoonReadPage extends StatelessWidget {
|
||||
@@ -42,11 +42,13 @@ class CartoonReadPage extends StatelessWidget {
|
||||
|
||||
Widget _buildBody(BuildContext context, CartoonReadLogic logic) {
|
||||
if (logic.detailInfo == null) return const LoadingCenterWidget();
|
||||
if (logic.detailInfo?.id == null) return CErrorWidget(retryOnTap: logic.loadData);
|
||||
if (logic.detailInfo?.id == null)
|
||||
return CErrorWidget(retryOnTap: logic.loadData);
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: logic.changeShowMenu,
|
||||
child: ScrollablePositionedList.builder(
|
||||
scrollAction: logic.onScrollAction,
|
||||
@@ -85,21 +87,27 @@ class CartoonReadPage extends StatelessWidget {
|
||||
padding: EdgeInsets.fromLTRB(10, screen.paddingTop + 8, 10, 8),
|
||||
child: Row(
|
||||
children: [
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.back(),
|
||||
child: const Icon(Icons.arrow_back_ios_new, size: 24, color: Colors.white),
|
||||
child: const Icon(Icons.arrow_back_ios_new,
|
||||
size: 24, color: Colors.white),
|
||||
),
|
||||
10.sizeBoxW,
|
||||
Expanded(
|
||||
child: Text(
|
||||
logic.detailInfo?.name ?? '',
|
||||
style: TextStyle(fontSize: 18.sp, color: Colors.white, fontWeight: FontWeight.w600),
|
||||
style: TextStyle(
|
||||
fontSize: 18.sp,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
21.sizeBoxW,
|
||||
Consumer<ACGSourceManager>(
|
||||
builder: (ctx, manager, _) {
|
||||
final col = manager.mediaInfo?.mediaStatus?.hasCollected ?? false;
|
||||
final col =
|
||||
manager.mediaInfo?.mediaStatus?.hasCollected ?? false;
|
||||
return FollowButton(
|
||||
mediaId: manager.mediaInfo?.id ?? '',
|
||||
isFollow: col,
|
||||
@@ -112,7 +120,8 @@ class CartoonReadPage extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
12.sizeBoxW,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.dialog(
|
||||
ShareMediaDialog(
|
||||
videoModel: VideoModel()
|
||||
@@ -196,8 +205,10 @@ class CartoonReadPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionItem({String? title, String? icon, VoidCallback? action, Color? color}) {
|
||||
return InkWell(enableFeedback: false,
|
||||
Widget _buildActionItem(
|
||||
{String? title, String? icon, VoidCallback? action, Color? color}) {
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: action,
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -223,13 +234,15 @@ class CartoonReadPage extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.loadOtherEpisode(false),
|
||||
child: Column(
|
||||
children: [
|
||||
Image.asset('common_back_new.png'.commonImgPath, width: 24),
|
||||
4.sizeBoxH,
|
||||
Text('上一篇', style: textStyle(12, Colors.white, FontWeight.w400)),
|
||||
Text('上一篇',
|
||||
style: textStyle(12, Colors.white, FontWeight.w400)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -238,9 +251,12 @@ class CartoonReadPage extends StatelessWidget {
|
||||
child: SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
trackHeight: 4,
|
||||
thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 8.0),
|
||||
overlayShape: const RoundSliderOverlayShape(overlayRadius: 12.0),
|
||||
tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 10.0),
|
||||
thumbShape:
|
||||
const RoundSliderThumbShape(enabledThumbRadius: 8.0),
|
||||
overlayShape:
|
||||
const RoundSliderOverlayShape(overlayRadius: 12.0),
|
||||
tickMarkShape:
|
||||
const RoundSliderTickMarkShape(tickMarkRadius: 10.0),
|
||||
trackShape: const RoundedRectSliderTrackShape(),
|
||||
overlayColor: Colors.white.withValues(alpha: .3),
|
||||
activeTrackColor: const Color(0xffFFD460),
|
||||
@@ -261,16 +277,19 @@ class CartoonReadPage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
13.sizeBoxW,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.loadOtherEpisode(true),
|
||||
child: Column(
|
||||
children: [
|
||||
Transform.rotate(
|
||||
angle: pi,
|
||||
child: Image.asset('common_back_new.png'.commonImgPath, width: 24),
|
||||
child: Image.asset('common_back_new.png'.commonImgPath,
|
||||
width: 24),
|
||||
),
|
||||
4.sizeBoxH,
|
||||
Text('下一篇', style: textStyle(12, Colors.white, FontWeight.w400)),
|
||||
Text('下一篇',
|
||||
style: textStyle(12, Colors.white, FontWeight.w400)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -290,10 +309,12 @@ class CartoonReadPage extends StatelessWidget {
|
||||
child: Consumer<ACGSourceManager>(
|
||||
builder: (_, manager, __) {
|
||||
final liked = manager.mediaInfo?.mediaStatus?.hasLiked == true;
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: manager.onLikeAction,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: .5),
|
||||
borderRadius: const BorderRadius.only(
|
||||
@@ -306,12 +327,15 @@ class CartoonReadPage extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
liked ? 'acg_like_sel.png'.acgImgPath : 'acg_like_nor.png'.acgImgPath,
|
||||
liked
|
||||
? 'acg_like_sel.png'.acgImgPath
|
||||
: 'acg_like_nor.png'.acgImgPath,
|
||||
width: 24,
|
||||
color: liked ? null : Colors.white,
|
||||
),
|
||||
5.sizeBoxW,
|
||||
Text('喜欢', style: textStyle(12, Colors.white, FontWeight.w400)),
|
||||
Text('喜欢',
|
||||
style: textStyle(12, Colors.white, FontWeight.w400)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -344,7 +368,8 @@ class CartoonReadPage extends StatelessWidget {
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Center(
|
||||
child: Image.asset('cartoon_auto_play.gif'.acgImgPath, width: 24),
|
||||
child: Image.asset('cartoon_auto_play.gif'.acgImgPath,
|
||||
width: 24),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -390,9 +415,13 @@ class CartoonReadPage extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
'共${logic.manager.mediaInfo?.totalEpisode}话 ${logic.manager.mediaInfo?.getDetailUpdateString ?? ''}',
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xff141414), fontWeight: FontWeight.w400),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xff141414),
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: logic.toggleSort,
|
||||
child: Row(
|
||||
children: [
|
||||
@@ -400,12 +429,18 @@ class CartoonReadPage extends StatelessWidget {
|
||||
turns: logic.sortType ? 0 : 0.5,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeOutCubic,
|
||||
child: Image.asset('text_play_sort.png'.acgImgPath, color: const Color(0xff141414), width: 16, height: 16),
|
||||
child: Image.asset('text_play_sort.png'.acgImgPath,
|
||||
color: const Color(0xff141414),
|
||||
width: 16,
|
||||
height: 16),
|
||||
),
|
||||
4.sizeBoxW,
|
||||
Text(
|
||||
logic.sortType ? '正序' : '倒序',
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xff141414), fontWeight: FontWeight.w400),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xff141414),
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -422,13 +457,15 @@ class CartoonReadPage extends StatelessWidget {
|
||||
// 不使用 list.reverse(items 不够会从底部排),采用数据倒序方法
|
||||
final info = logic.sortType
|
||||
? logic.manager.allEpisodes[index]
|
||||
: logic.manager.allEpisodes[logic.manager.allEpisodes.length - index - 1];
|
||||
: logic.manager.allEpisodes[
|
||||
logic.manager.allEpisodes.length - index - 1];
|
||||
return StaggerInItem(
|
||||
index: index,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
if (logic.detailInfo?.id == info.id) return; //点的就是当前章,不重复加载
|
||||
if (logic.detailInfo?.id == info.id)
|
||||
return; //点的就是当前章,不重复加载
|
||||
logic.loadDataWithIndex(info.id ?? '');
|
||||
},
|
||||
child: Container(
|
||||
@@ -461,7 +498,9 @@ class CartoonReadPage extends StatelessWidget {
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.sp,
|
||||
color: select ? AppColors.actionRed : Colors.white.withValues(alpha: 0.55),
|
||||
color: select
|
||||
? AppColors.actionRed
|
||||
: Colors.white.withValues(alpha: 0.55),
|
||||
fontWeight: select ? FontWeight.w500 : FontWeight.w400,
|
||||
),
|
||||
maxLines: 1,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//小说/视频推荐
|
||||
import 'package:hgmj/hj_utils/api_service/acg_service.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/base_list_controller.dart';
|
||||
import 'package:wydj/hj_utils/api_service/acg_service.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/base_list_controller.dart';
|
||||
|
||||
import '../../hj_utils/api_service/common_service.dart';
|
||||
|
||||
@@ -10,7 +10,8 @@ class CartoonRecommendLogic extends ListBaseLogic<dynamic> {
|
||||
final MediaStyle mediaStyle; //推荐类型:Video(真人视频) / Cartoon(动漫) / Comics(漫画)
|
||||
final String? videoTagId; //视频(SP)推荐的 tagId,按当前视频 tag 拉同类
|
||||
|
||||
CartoonRecommendLogic({this.mediaId, this.mediaStyle = MediaStyle.Comics, this.videoTagId});
|
||||
CartoonRecommendLogic(
|
||||
{this.mediaId, this.mediaStyle = MediaStyle.Comics, this.videoTagId});
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
@@ -30,10 +31,15 @@ class CartoonRecommendLogic extends ListBaseLogic<dynamic> {
|
||||
//按类型分流:视频走 getRecommendList,漫画/动漫走 comicsRecommendList
|
||||
Future<(List<dynamic>?, bool)> _fetch(int page) async {
|
||||
if (mediaStyle == MediaStyle.Video) {
|
||||
final resp = await CommonService.getRecommendList(pageNumber: page, pageSize: 12, tagId: videoTagId, newsType: mediaStyle.rankParam);
|
||||
final resp = await CommonService.getRecommendList(
|
||||
pageNumber: page,
|
||||
pageSize: 12,
|
||||
tagId: videoTagId,
|
||||
newsType: mediaStyle.rankParam);
|
||||
return (resp?.videos, resp?.hasNext == true);
|
||||
}
|
||||
final model = await ACGService.comicsRecommendList(page, 12, tagId: mediaId, mediaType: mediaStyle.rankParam);
|
||||
final model = await ACGService.comicsRecommendList(page, 12,
|
||||
tagId: mediaId, mediaType: mediaStyle.rankParam);
|
||||
return (model?.list, model?.hasNext == true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/routers/jump_router.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/unique_tag_mixin.dart';
|
||||
import 'package:wydj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/routers/jump_router.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/unique_tag_mixin.dart';
|
||||
|
||||
import '../../hj_model/video_model.dart';
|
||||
import '../home/home_cell_style/video_simple_cell.dart';
|
||||
@@ -40,7 +40,8 @@ class CartoonRecommendPage extends StatefulWidget {
|
||||
State<CartoonRecommendPage> createState() => _CartoonRecommendPageState();
|
||||
}
|
||||
|
||||
class _CartoonRecommendPageState extends State<CartoonRecommendPage> with UniqueTagMixin {
|
||||
class _CartoonRecommendPageState extends State<CartoonRecommendPage>
|
||||
with UniqueTagMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<CartoonRecommendLogic>(
|
||||
@@ -52,7 +53,8 @@ class _CartoonRecommendPageState extends State<CartoonRecommendPage> with Unique
|
||||
),
|
||||
builder: (logic) {
|
||||
if (logic.isLoading) return LoadingCenterWidget();
|
||||
if (logic.isEmptyData) return CErrorWidget(retryOnTap: () => logic.loadData());
|
||||
if (logic.isEmptyData)
|
||||
return CErrorWidget(retryOnTap: () => logic.loadData());
|
||||
final list = logic.dataList!;
|
||||
return pullYsRefresh(
|
||||
onInit: (ctr) => logic.refreshCtr = ctr,
|
||||
@@ -68,7 +70,9 @@ class _CartoonRecommendPageState extends State<CartoonRecommendPage> with Unique
|
||||
childAspectRatio: widget.childAspectRatio,
|
||||
),
|
||||
itemCount: list.length,
|
||||
itemBuilder: (_, index) => widget.mediaStyle == MediaStyle.Video ? _videoCell(list[index]) : _acgCell(list[index]),
|
||||
itemBuilder: (_, index) => widget.mediaStyle == MediaStyle.Video
|
||||
? _videoCell(list[index])
|
||||
: _acgCell(list[index]),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import 'cartoon_sectionlist_sub_page.dart';
|
||||
|
||||
@@ -26,8 +26,10 @@ class CartoonSectionListPage extends StatefulWidget {
|
||||
State<CartoonSectionListPage> createState() => _CartoonSectionListPageState();
|
||||
}
|
||||
|
||||
class _CartoonSectionListPageState extends State<CartoonSectionListPage> with SingleTickerProviderStateMixin {
|
||||
late final TabController tabCtr = TabController(length: _sortTabs.length, vsync: this);
|
||||
class _CartoonSectionListPageState extends State<CartoonSectionListPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final TabController tabCtr =
|
||||
TabController(length: _sortTabs.length, vsync: this);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -73,7 +75,8 @@ class _CartoonSectionListPageState extends State<CartoonSectionListPage> with Si
|
||||
decoration: BoxDecoration(
|
||||
border: index != _sortTabs.length - 1
|
||||
? Border(
|
||||
right: BorderSide(width: .5, color: Colors.white.withValues(alpha: .1)),
|
||||
right: BorderSide(
|
||||
width: .5, color: Colors.white.withValues(alpha: .1)),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@@ -84,7 +87,8 @@ class _CartoonSectionListPageState extends State<CartoonSectionListPage> with Si
|
||||
labelPadding: EdgeInsets.zero,
|
||||
labelStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
unselectedLabelColor: Colors.white.withValues(alpha: 0.5),
|
||||
unselectedLabelStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
unselectedLabelStyle:
|
||||
const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
indicator: const BoxDecoration(),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:hgmj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/acg_service.dart';
|
||||
import 'package:hgmj/tools_base/base_list_controller.dart';
|
||||
import 'package:wydj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:wydj/hj_utils/api_service/acg_service.dart';
|
||||
import 'package:wydj/tools_base/base_list_controller.dart';
|
||||
|
||||
class CartoonSectionSubLogic extends ListBaseLogic<CartoonMediaInfo> {
|
||||
final int? sortType;
|
||||
@@ -8,13 +8,13 @@ class CartoonSectionSubLogic extends ListBaseLogic<CartoonMediaInfo> {
|
||||
|
||||
CartoonSectionSubLogic({this.sortType, this.sectionID});
|
||||
|
||||
|
||||
bool get isCartoon {
|
||||
if(dataList?.isNotEmpty == true){
|
||||
if (dataList?.isNotEmpty == true) {
|
||||
return dataList!.first.mediaType == "video";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
@@ -25,7 +25,6 @@ class CartoonSectionSubLogic extends ListBaseLogic<CartoonMediaInfo> {
|
||||
|
||||
void loadMoreData() => fetchData(isRefresh: false, fetch: _fetch);
|
||||
|
||||
|
||||
Future<(List<CartoonMediaInfo>?, bool)> _fetch(int page) async {
|
||||
final resp = await ACGService.getPreferences(
|
||||
page,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import 'acg_widget_item.dart';
|
||||
import 'cartoon_sectionlist_sub_logic.dart';
|
||||
@@ -35,14 +35,15 @@ class CartoonSectionSubPage extends StatelessWidget {
|
||||
Widget _buildGrid(CartoonSectionSubLogic logic) {
|
||||
return GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: logic.isCartoon ? 2 : 3,
|
||||
mainAxisSpacing: 12,
|
||||
crossAxisSpacing: 5,
|
||||
childAspectRatio: logic.isCartoon ? 174 /138 : 111 / 190,
|
||||
childAspectRatio: logic.isCartoon ? 174 / 138 : 111 / 190,
|
||||
),
|
||||
itemCount: logic.dataList?.length ?? 0,
|
||||
itemBuilder: (context, index) => AcgItemWidget(info: logic.dataList?[index]),
|
||||
itemBuilder: (context, index) =>
|
||||
AcgItemWidget(info: logic.dataList?[index]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/hj_model/home/plate_model.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/hj_model/home/plate_model.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import 'cartoon_sub_grid_page.dart';
|
||||
|
||||
@@ -21,6 +21,7 @@ class CartoonSubDetailPage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CartoonSubGridPage(tagData: tagData, type: type, scrollCtr: scroll).keepAlive;
|
||||
return CartoonSubGridPage(tagData: tagData, type: type, scrollCtr: scroll)
|
||||
.keepAlive;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/hj_model/home/plate_model.dart';
|
||||
import 'package:hgmj/hj_model/home/module_detail_model.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/vid_service.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/base_list_controller.dart';
|
||||
import 'package:wydj/hj_model/home/plate_model.dart';
|
||||
import 'package:wydj/hj_model/home/module_detail_model.dart';
|
||||
import 'package:wydj/hj_utils/api_service/vid_service.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/base_list_controller.dart';
|
||||
|
||||
class CartoonSubGridLogic extends ListBaseLogic {
|
||||
final MediaStyle type; //-1:动漫和漫画 0:图集 1:黄游 2:小说
|
||||
@@ -30,11 +30,13 @@ class CartoonSubGridLogic extends ListBaseLogic {
|
||||
|
||||
String get newsType {
|
||||
if (tagData?.moduleName == '热门推荐' && tagData?.type == -100) return 'PIC';
|
||||
if (tagData?.moduleName == '热门推荐' && tagData?.type == -101) return 'SEED_LINK';
|
||||
if (tagData?.moduleName == '热门推荐' && tagData?.type == -101)
|
||||
return 'SEED_LINK';
|
||||
return '';
|
||||
}
|
||||
|
||||
bool get isAcg => type == MediaStyle.Novel || type == MediaStyle.Cartoon; //是否是acg模块
|
||||
bool get isAcg =>
|
||||
type == MediaStyle.Novel || type == MediaStyle.Cartoon; //是否是acg模块
|
||||
|
||||
CartoonSubGridLogic({this.tagData, this.type = MediaStyle.Pic});
|
||||
|
||||
@@ -57,7 +59,11 @@ class CartoonSubGridLogic extends ListBaseLogic {
|
||||
SortTab('最多收藏', 7),
|
||||
];
|
||||
} else if (type == MediaStyle.Pic || type == MediaStyle.Novel) {
|
||||
sortTabs = const [SortTab('最多观看', 3), SortTab('最新发布', 1), SortTab('最多收藏', 7)];
|
||||
sortTabs = const [
|
||||
SortTab('最多观看', 3),
|
||||
SortTab('最新发布', 1),
|
||||
SortTab('最多收藏', 7)
|
||||
];
|
||||
} else {
|
||||
sortTabs = const [SortTab('最新', 1), SortTab('最热', 2), SortTab('畅销', 8)];
|
||||
}
|
||||
@@ -74,7 +80,8 @@ class CartoonSubGridLogic extends ListBaseLogic {
|
||||
loadData({int pageNum = 1}) async {
|
||||
dataList ??= [];
|
||||
ModuleDetailModel? retModel;
|
||||
if (tagData?.moduleName == '热门推荐' && (tagData?.type == -100 || tagData?.type == -101)) {
|
||||
if (tagData?.moduleName == '热门推荐' &&
|
||||
(tagData?.type == -100 || tagData?.type == -101)) {
|
||||
//图集
|
||||
retModel = await VidService.communityRecommend(
|
||||
pageNum,
|
||||
@@ -111,7 +118,9 @@ class CartoonSubGridLogic extends ListBaseLogic {
|
||||
}
|
||||
update();
|
||||
refreshCtr?.refreshCompleted();
|
||||
retModel?.hasNext == true ? refreshCtr?.loadComplete() : refreshCtr?.loadNoData();
|
||||
retModel?.hasNext == true
|
||||
? refreshCtr?.loadComplete()
|
||||
: refreshCtr?.loadNoData();
|
||||
}
|
||||
|
||||
loadMoreData() => loadData(pageNum: currentPage + 1);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_model/home/plate_model.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/hj_utils/sliver_delegate.dart';
|
||||
import 'package:hgmj/tools_base/banner/ads_grid_view.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/hj_model/home/plate_model.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/hj_utils/sliver_delegate.dart';
|
||||
import 'package:wydj/tools_base/banner/ads_grid_view.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import '../home/home_cell_style/quick_entry_row.dart';
|
||||
import '../home/home_cell_style/video_simple_cell.dart';
|
||||
@@ -89,7 +89,8 @@ class CartoonSubGridPage extends StatelessWidget {
|
||||
controller: logic.tabCtr,
|
||||
isScrollable: true,
|
||||
//选中/未选中只差颜色,unselectedLabelStyle 不传会 fallback 到 labelStyle
|
||||
labelStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
labelStyle:
|
||||
const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
labelColor: Colors.white.withValues(alpha: .9),
|
||||
unselectedLabelColor: Colors.white.withValues(alpha: .55),
|
||||
indicator: const BoxDecoration(), //去掉默认下划线
|
||||
@@ -110,11 +111,13 @@ class CartoonSubGridPage extends StatelessWidget {
|
||||
final list = logic.dataList;
|
||||
//null 是还没拉过,空 list 才是真没数据
|
||||
if (list == null) {
|
||||
return const SliverToBoxAdapter(child: SizedBox(height: 400, child: LoadingCenterWidget()));
|
||||
return const SliverToBoxAdapter(
|
||||
child: SizedBox(height: 400, child: LoadingCenterWidget()));
|
||||
}
|
||||
if (list.isEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: SizedBox(height: 400, child: CErrorWidget(retryOnTap: logic.loadData)),
|
||||
child: SizedBox(
|
||||
height: 400, child: CErrorWidget(retryOnTap: logic.loadData)),
|
||||
);
|
||||
}
|
||||
return SliverPadding(
|
||||
@@ -129,8 +132,11 @@ class CartoonSubGridPage extends StatelessWidget {
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
//-1动漫/漫画 0-图集 1-黄游 2-小说
|
||||
(_, index) => switch (type) {
|
||||
MediaStyle.Cartoon || MediaStyle.Novel => AcgItemWidget(info: list[index], coverV: true),
|
||||
MediaStyle.Pic => PhotoGalleryItem(videoModel: list[index], textline: 1),
|
||||
MediaStyle.Cartoon ||
|
||||
MediaStyle.Novel =>
|
||||
AcgItemWidget(info: list[index], coverV: true),
|
||||
MediaStyle.Pic =>
|
||||
PhotoGalleryItem(videoModel: list[index], textline: 1),
|
||||
MediaStyle.Game => VideoSimpleCell(
|
||||
videoModel: list[index],
|
||||
isFromHY: true,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:hgmj/hj_model/home/plate_model.dart';
|
||||
import 'package:hgmj/hj_page/main_page/provider/bottom_bar_provider.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import 'package:wydj/hj_model/home/plate_model.dart';
|
||||
import 'package:wydj/hj_page/main_page/provider/bottom_bar_provider.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
|
||||
class CartoonSubModuleLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
class CartoonSubModuleLogic extends GetxController
|
||||
with GetTickerProviderStateMixin {
|
||||
final int tabIndex; // 未初始化时,内链跳转需要
|
||||
final MediaStyle type; //-1:动漫和漫画 0:图集 1:黄游 2:小说
|
||||
List<ModuleData> tabs = []; //漫画
|
||||
@@ -39,7 +40,8 @@ class CartoonSubModuleLogic extends GetxController with GetTickerProviderStateMi
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
tabController.dispose(); // 自建 TabController,随 logic 释放(含内部 AnimationController + 匿名监听)
|
||||
tabController
|
||||
.dispose(); // 自建 TabController,随 logic 释放(含内部 AnimationController + 匿名监听)
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_page/main_page/provider/bottom_bar_provider.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/indicator/custom_tab_indicator.dart';
|
||||
import 'package:wydj/hj_page/main_page/provider/bottom_bar_provider.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/indicator/custom_tab_indicator.dart';
|
||||
|
||||
import 'cartoon_sub_detail_page.dart';
|
||||
import 'cartoon_sub_module_logic.dart';
|
||||
@@ -12,7 +12,8 @@ class CartoonSubModulePage extends StatelessWidget {
|
||||
final MediaStyle type; //-1:动漫和漫画 0:图集 1:黄游 2:小说
|
||||
final int tabIndex;
|
||||
|
||||
const CartoonSubModulePage({super.key, this.type = MediaStyle.Pic, this.tabIndex = 0});
|
||||
const CartoonSubModulePage(
|
||||
{super.key, this.type = MediaStyle.Pic, this.tabIndex = 0});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -31,8 +32,11 @@ class CartoonSubModulePage extends StatelessWidget {
|
||||
tagData: logic.tabs[index],
|
||||
type: type,
|
||||
index: index,
|
||||
scroll: CommunityBottomProvider()
|
||||
.scrollCtr(type == MediaStyle.Pic ? MediaStyle.Pic : MediaStyle.Novel, index),
|
||||
scroll: CommunityBottomProvider().scrollCtr(
|
||||
type == MediaStyle.Pic
|
||||
? MediaStyle.Pic
|
||||
: MediaStyle.Novel,
|
||||
index),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -59,8 +63,10 @@ class CartoonSubModulePage extends StatelessWidget {
|
||||
labelColor: Colors.white.withValues(alpha: .9),
|
||||
labelStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
||||
unselectedLabelColor: Colors.white.withValues(alpha: .55),
|
||||
unselectedLabelStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
indicator: CustomIndicator(width: 16, height: 2, offsetY: 6, color: Color(0xFFFFC000)),
|
||||
unselectedLabelStyle:
|
||||
const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
indicator: CustomIndicator(
|
||||
width: 16, height: 2, offsetY: 6, color: Color(0xFFFFC000)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
import '../../hj_model/cartoon_media_info.dart';
|
||||
import '../../hj_utils/api_service/acg_service.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import '../../hj_utils/history_util.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import '../../routers/jump_router.dart';
|
||||
import 'audio_player_bottomsheet.dart';
|
||||
import 'text_novel_read_page.dart';
|
||||
@@ -71,12 +71,15 @@ class NovelDetailLogic extends GetxController {
|
||||
|
||||
// 获取相关推荐
|
||||
Future fetchRecommendData() async {
|
||||
final result = await ACGService.comicsRecommendList(page, 12, tagId: model?.tagDetails?.firstOrNull?.id ?? '', mediaType: 'text');
|
||||
final result = await ACGService.comicsRecommendList(page, 12,
|
||||
tagId: model?.tagDetails?.firstOrNull?.id ?? '', mediaType: 'text');
|
||||
if (result != null) {
|
||||
page += 1;
|
||||
recommends.addAll(result.list ?? []);
|
||||
}
|
||||
result?.hasNext ?? false ? refreshCtr?.loadComplete() : refreshCtr?.loadNoData();
|
||||
result?.hasNext ?? false
|
||||
? refreshCtr?.loadComplete()
|
||||
: refreshCtr?.loadNoData();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -96,11 +99,13 @@ class NovelDetailLogic extends GetxController {
|
||||
|
||||
gotoPlay({int index = 0}) async {
|
||||
final mediaSubType = model?.mediaSubType ?? -1;
|
||||
final opm = await manager.getEpisodeHasPermisson(index); //通过时内部已切集,不必再 changeEpisodesIndex
|
||||
final opm = await manager
|
||||
.getEpisodeHasPermisson(index); //通过时内部已切集,不必再 changeEpisodesIndex
|
||||
if (opm != null) {
|
||||
//0-默认文本小说 1-有声小说
|
||||
if (mediaSubType == 0) {
|
||||
Get.to(() => TextNovelReadPage(manager: manager), preventDuplicates: false);
|
||||
Get.to(() => TextNovelReadPage(manager: manager),
|
||||
preventDuplicates: false);
|
||||
} else if (mediaSubType == 1) {
|
||||
Get.to(
|
||||
() => VoiceNovelReadPage(
|
||||
@@ -123,5 +128,4 @@ class NovelDetailLogic extends GetxController {
|
||||
}
|
||||
pushToCartoonPage(info);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ 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/tools_base/toast.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:hgmj/tools_base/widget/follow_button.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:wydj/tools_base/widget/follow_button.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../hj_utils/widget_util.dart';
|
||||
@@ -87,7 +87,8 @@ class _NovelDetailPageState extends State<NovelDetailPage> with UniqueTagMixin {
|
||||
padding: EdgeInsets.only(bottom: 80),
|
||||
sliver: SliverGrid.builder(
|
||||
itemCount: _.recommends.length,
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3,
|
||||
mainAxisSpacing: 12,
|
||||
crossAxisSpacing: 6,
|
||||
@@ -112,7 +113,8 @@ class _NovelDetailPageState extends State<NovelDetailPage> with UniqueTagMixin {
|
||||
),
|
||||
),
|
||||
),
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
height: 44,
|
||||
@@ -124,7 +126,10 @@ class _NovelDetailPageState extends State<NovelDetailPage> with UniqueTagMixin {
|
||||
child: Consumer<ACGSourceManager>(
|
||||
builder: (context, value, child) => Text(
|
||||
_.manager.actionTitle(),
|
||||
style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
)),
|
||||
onTap: () => _.gotoPlay(index: _.manager.index),
|
||||
@@ -152,7 +157,8 @@ class _NovelDetailPageState extends State<NovelDetailPage> with UniqueTagMixin {
|
||||
color: !_.showHeader ? Color(0xff0E141E) : Colors.transparent,
|
||||
child: Row(
|
||||
children: [
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
child: Image.asset('acg_noval_back.png'.acgImgPath, width: 24),
|
||||
onTap: () => Get.back(),
|
||||
),
|
||||
@@ -165,7 +171,8 @@ class _NovelDetailPageState extends State<NovelDetailPage> with UniqueTagMixin {
|
||||
Spacer(),
|
||||
Consumer<ACGSourceManager>(
|
||||
builder: (context, manager, child) {
|
||||
bool col = manager.mediaInfo?.mediaStatus?.hasCollected ?? false;
|
||||
bool col =
|
||||
manager.mediaInfo?.mediaStatus?.hasCollected ?? false;
|
||||
return FollowButton(
|
||||
mediaId: manager.mediaInfo?.id ?? '',
|
||||
isFollow: col,
|
||||
@@ -207,7 +214,8 @@ class _NovelDetailPageState extends State<NovelDetailPage> with UniqueTagMixin {
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => _.episodesBottomSheet(),
|
||||
child: Row(
|
||||
children: [
|
||||
@@ -241,7 +249,8 @@ class _NovelDetailPageState extends State<NovelDetailPage> with UniqueTagMixin {
|
||||
),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final epm = manager.allEpisodes[index];
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => _.gotoPlay(index: index),
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -251,18 +260,22 @@ class _NovelDetailPageState extends State<NovelDetailPage> with UniqueTagMixin {
|
||||
Text(
|
||||
'第${epm.episodeNumber ?? 1}${_.model?.unit}',
|
||||
style: TextStyle(
|
||||
color: manager.index == index ? AppColors.actionRed : Color(0xff989898),
|
||||
color: manager.index == index
|
||||
? AppColors.actionRed
|
||||
: Color(0xff989898),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
//无任何权限时,前 N 集免费展示「免费」角标
|
||||
if (manager.mediaInfo?.hasPermission == false && epm.inFreeEpisode) ...[
|
||||
if (manager.mediaInfo?.hasPermission == false &&
|
||||
epm.inFreeEpisode) ...[
|
||||
6.sizeBoxW,
|
||||
const FreeBadge(),
|
||||
],
|
||||
Spacer(),
|
||||
Icon(Icons.navigate_next_sharp, size: 20, color: Colors.white)
|
||||
Icon(Icons.navigate_next_sharp,
|
||||
size: 20, color: Colors.white)
|
||||
],
|
||||
),
|
||||
12.sizeBoxH,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../hj_model/cartoon_media_info.dart';
|
||||
import '../../hj_model/video_model.dart';
|
||||
@@ -87,17 +87,20 @@ class NovelHeader extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
'共${info?.totalEpisode ?? 0}${info?.unit}',
|
||||
style: textStyle(12, const Color(0xff999999), FontWeight.w400),
|
||||
style:
|
||||
textStyle(12, const Color(0xff999999), FontWeight.w400),
|
||||
),
|
||||
8.sizeBoxW,
|
||||
Text(
|
||||
'/',
|
||||
style: textStyle(12, const Color(0xff999999), FontWeight.w400),
|
||||
style:
|
||||
textStyle(12, const Color(0xff999999), FontWeight.w400),
|
||||
),
|
||||
8.sizeBoxW,
|
||||
Text(
|
||||
info?.updateDesc ?? '',
|
||||
style: textStyle(12, info!.getDetailUpdateColor, FontWeight.w400),
|
||||
style: textStyle(
|
||||
12, info!.getDetailUpdateColor, FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -118,10 +121,13 @@ class NovelHeader extends StatelessWidget {
|
||||
runSpacing: 10,
|
||||
maxLines: 1,
|
||||
children: tags
|
||||
.map((tag) => InkWell(enableFeedback: false,
|
||||
onTap: () => Get.to(CartoonTagPage(title: tag.name ?? '', sId: tag.id ?? '')),
|
||||
.map((tag) => InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.to(
|
||||
CartoonTagPage(title: tag.name ?? '', sId: tag.id ?? '')),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xff22252D),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
@@ -129,7 +135,8 @@ class NovelHeader extends StatelessWidget {
|
||||
child: Text(
|
||||
'#${tag.name ?? ''}',
|
||||
maxLines: 1,
|
||||
style: const TextStyle(color: Color(0xFF999999), fontSize: 12),
|
||||
style:
|
||||
const TextStyle(color: Color(0xFF999999), fontSize: 12),
|
||||
),
|
||||
),
|
||||
))
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_page/find/pic_collect/pics_detail_page.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:hgmj/extension/extensions.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/find/pic_collect/pics_detail_page.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
|
||||
//图集item
|
||||
class PhotoGalleryItem extends StatelessWidget {
|
||||
@@ -13,7 +13,8 @@ class PhotoGalleryItem extends StatelessWidget {
|
||||
final Function? callback;
|
||||
final int textline;
|
||||
|
||||
const PhotoGalleryItem({super.key,
|
||||
const PhotoGalleryItem({
|
||||
super.key,
|
||||
this.videoModel,
|
||||
this.callback,
|
||||
this.textline = 1,
|
||||
@@ -21,7 +22,8 @@ class PhotoGalleryItem extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
if (callback != null) {
|
||||
callback?.call();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/media_content.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/acg_service.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_model/media_content.dart';
|
||||
import 'package:wydj/hj_utils/api_service/acg_service.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
|
||||
import '../../hj_model/acg/comic_chapters_model.dart';
|
||||
import '../../hj_model/cartoon_media_info.dart';
|
||||
@@ -49,7 +49,8 @@ class TextNovelReadLogic extends GetxController {
|
||||
|
||||
// ========== 公开方法 ==========
|
||||
// 获取文字小说。返回 Future 不是可有可无:CErrorWidget 靠它做重试 loading 和防连点
|
||||
Future<void> loadData({bool showLoading = false, bool needToTop = false}) async {
|
||||
Future<void> loadData(
|
||||
{bool showLoading = false, bool needToTop = false}) async {
|
||||
if (showLoading) LoadingHelper.showLoading();
|
||||
final model = await manager.getComicsMediaContent(index: currentEpisode);
|
||||
if (showLoading) LoadingHelper.dismissLoading();
|
||||
@@ -89,7 +90,8 @@ class TextNovelReadLogic extends GetxController {
|
||||
final epm = await manager.getEpisodeHasPermisson(realIndex);
|
||||
if (epm == null) return;
|
||||
LoadingHelper.showLoading();
|
||||
final model = await ACGService.getMediaDetail(mediaId: manager.mediaInfo?.id, id: id);
|
||||
final model =
|
||||
await ACGService.getMediaDetail(mediaId: manager.mediaInfo?.id, id: id);
|
||||
LoadingHelper.dismissLoading();
|
||||
if (model != null) {
|
||||
currentEpisode = realIndex;
|
||||
|
||||
@@ -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/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/stagger_in_item.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/stagger_in_item.dart';
|
||||
|
||||
import '../../tools_base/loading/loading_center_widget.dart';
|
||||
import 'text_novel_read_logic.dart';
|
||||
@@ -65,7 +65,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
controller: logic.scrollCtr,
|
||||
padding: const EdgeInsets.only(bottom: 60), //给底部菜单栏留位,别被挡住最后几行
|
||||
padding:
|
||||
const EdgeInsets.only(bottom: 60), //给底部菜单栏留位,别被挡住最后几行
|
||||
child: Align(
|
||||
//正文不足一行时居中(长文自然撑满,看不出差别),与旧版 Column 默认的 center 保持一致
|
||||
alignment: Alignment.topCenter,
|
||||
@@ -73,7 +74,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
logic.detailInfo?.text ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: (logic.isDark ? Colors.white : Colors.black).withValues(alpha: .9),
|
||||
color: (logic.isDark ? Colors.white : Colors.black)
|
||||
.withValues(alpha: .9),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -98,7 +100,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
child: Container(
|
||||
height: height,
|
||||
color: logic.isDark ? Colors.black : Colors.white,
|
||||
padding: EdgeInsets.only(top: screen.paddingTop + 5, left: 16, right: 16),
|
||||
padding:
|
||||
EdgeInsets.only(top: screen.paddingTop + 5, left: 16, right: 16),
|
||||
alignment: Alignment.topCenter, //按钮贴状态栏下沿,余量留在底部
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -111,7 +114,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(
|
||||
logic.detailInfo?.name ?? '',
|
||||
style: TextStyle(fontSize: 18, color: fg, fontWeight: FontWeight.w600),
|
||||
style: TextStyle(
|
||||
fontSize: 18, color: fg, fontWeight: FontWeight.w600),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -124,9 +128,12 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 7),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
transitionBuilder: (child, anim) => ScaleTransition(scale: anim, child: child),
|
||||
transitionBuilder: (child, anim) =>
|
||||
ScaleTransition(scale: anim, child: child),
|
||||
child: Image.asset(
|
||||
logic.isDark ? 'text_sun.png'.acgImgPath : 'text_moon.png'.acgImgPath,
|
||||
logic.isDark
|
||||
? 'text_sun.png'.acgImgPath
|
||||
: 'text_moon.png'.acgImgPath,
|
||||
// key 按状态区分,AnimatedSwitcher 才会把它当成新 child 触发动画
|
||||
key: ValueKey(logic.isDark),
|
||||
width: 24,
|
||||
@@ -140,7 +147,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
onTap: () => Scaffold.of(ctx).openEndDrawer(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 7),
|
||||
child: Image.asset('text_play_menu.png'.acgImgPath, width: 24, color: fg),
|
||||
child: Image.asset('text_play_menu.png'.acgImgPath,
|
||||
width: 24, color: fg),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -151,7 +159,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
|
||||
// 底部翻章栏,收起时整条移出屏幕下方
|
||||
Widget _buildFooter(TextNovelReadLogic logic) {
|
||||
final style = TextStyle(fontSize: 14, color: logic.isDark ? Colors.white : Colors.black);
|
||||
final style = TextStyle(
|
||||
fontSize: 14, color: logic.isDark ? Colors.white : Colors.black);
|
||||
return AnimatedPositioned(
|
||||
duration: Duration(milliseconds: logic.durationTime),
|
||||
bottom: logic.showMenu ? 0 : -60,
|
||||
@@ -170,7 +179,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
onTap: () => logic.loadOtherEpisode(false, showLoading: true),
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset('text_last.png'.acgImgPath, color: AppColors.actionRed, width: 20, height: 20),
|
||||
Image.asset('text_last.png'.acgImgPath,
|
||||
color: AppColors.actionRed, width: 20, height: 20),
|
||||
12.sizeBoxW,
|
||||
Text('上一章', style: style),
|
||||
],
|
||||
@@ -183,7 +193,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
children: [
|
||||
Text('下一章', style: style),
|
||||
12.sizeBoxW,
|
||||
Image.asset('text_next.png'.acgImgPath, color: AppColors.actionRed, width: 20, height: 20),
|
||||
Image.asset('text_next.png'.acgImgPath,
|
||||
color: AppColors.actionRed, width: 20, height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -207,7 +218,10 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
logic.mediaInfo?.title ?? '',
|
||||
style: TextStyle(fontSize: 16, color: fg.withValues(alpha: .9), fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: fg.withValues(alpha: .9),
|
||||
fontWeight: FontWeight.w500),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
@@ -221,7 +235,10 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
'共${logic.mediaInfo?.totalEpisode ?? 0}话 ${logic.mediaInfo?.updateDesc ?? ''}',
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF1F2029), fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF1F2029),
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
@@ -234,12 +251,19 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
turns: logic.isAscend ? 0 : 0.5,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeOutCubic,
|
||||
child: Image.asset('text_play_sort.png'.acgImgPath, width: 20, color: Color(0xFF1F2029),),
|
||||
child: Image.asset(
|
||||
'text_play_sort.png'.acgImgPath,
|
||||
width: 20,
|
||||
color: Color(0xFF1F2029),
|
||||
),
|
||||
),
|
||||
4.sizeBoxW,
|
||||
Text(
|
||||
logic.isAscend ? '正序' : '倒序',
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF1F2029), fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF1F2029),
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -252,7 +276,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
child: GetBuilder<TextNovelReadLogic>(
|
||||
id: 'list',
|
||||
builder: (_) => ListView.builder(
|
||||
key: ValueKey(logic.isAscend), // 切换正/倒序时 key 变化→列表重建→item 重新错峰入场
|
||||
key:
|
||||
ValueKey(logic.isAscend), // 切换正/倒序时 key 变化→列表重建→item 重新错峰入场
|
||||
itemCount: logic.allEpisodes.length,
|
||||
padding: const EdgeInsets.only(top: 6),
|
||||
itemBuilder: (_, index) {
|
||||
@@ -261,7 +286,8 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
return StaggerInItem(
|
||||
index: index,
|
||||
child: InkWell(
|
||||
enableFeedback: false, //换掉裸 GestureDetector:整行可点,不再只有文字那一小块
|
||||
enableFeedback:
|
||||
false, //换掉裸 GestureDetector:整行可点,不再只有文字那一小块
|
||||
onTap: () {
|
||||
Get.back();
|
||||
logic.loadDataWithIndex(info.id ?? '');
|
||||
@@ -275,8 +301,11 @@ class TextNovelReadPage extends StatelessWidget {
|
||||
'第${info.episodeNumber ?? 1}${logic.mediaInfo?.unit ?? ''}',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: select ? AppColors.actionRed : fg.withValues(alpha: .55),
|
||||
fontWeight: select ? FontWeight.w500 : FontWeight.w400,
|
||||
color: select
|
||||
? AppColors.actionRed
|
||||
: fg.withValues(alpha: .55),
|
||||
fontWeight:
|
||||
select ? FontWeight.w500 : FontWeight.w400,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/event_bus_util.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/events.dart';
|
||||
import 'package:wydj/tools_base/event_bus/event_bus_util.dart';
|
||||
import 'package:wydj/tools_base/event_bus/events.dart';
|
||||
|
||||
import 'widget/acg_source_manager.dart';
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/hj_utils/widget_util.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/hj_utils/widget_util.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'audio_player_content.dart';
|
||||
@@ -34,7 +34,8 @@ class VoiceNovelReadPage extends StatefulWidget {
|
||||
|
||||
// 可重复 push(preventDuplicates: false)+ 间接环 NovelDetail→VoiceNovelRead 可能多实例并存,
|
||||
// 用 UniqueTagMixin 给每个实例分独立 tag 隔离
|
||||
class _VoiceNovelReadPageState extends State<VoiceNovelReadPage> with UniqueTagMixin {
|
||||
class _VoiceNovelReadPageState extends State<VoiceNovelReadPage>
|
||||
with UniqueTagMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<VoiceNovelReadLogic>(
|
||||
@@ -49,9 +50,11 @@ class _VoiceNovelReadPageState extends State<VoiceNovelReadPage> with UniqueTagM
|
||||
value: logic.sourceManager,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: InkWell(enableFeedback: false,
|
||||
leading: InkWell(
|
||||
enableFeedback: false,
|
||||
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),
|
||||
),
|
||||
centerTitle: false,
|
||||
titleSpacing: -10,
|
||||
@@ -91,17 +94,18 @@ class _VoiceNovelReadPageState extends State<VoiceNovelReadPage> with UniqueTagM
|
||||
padding: const EdgeInsets.fromLTRB(16, 18, 16, 12),
|
||||
child: Text(
|
||||
'相关推荐',
|
||||
style: textStyle(18, Colors.white.withValues(alpha: .9), FontWeight.w600),
|
||||
style: textStyle(
|
||||
18, Colors.white.withValues(alpha: .9), FontWeight.w600),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
body: CartoonRecommendPage(
|
||||
mediaId: logic.sourceManager.mediaInfo?.tagDetails?.firstOrNull?.id ?? '',
|
||||
mediaId:
|
||||
logic.sourceManager.mediaInfo?.tagDetails?.firstOrNull?.id ?? '',
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
tapAction: () => logic.audioManager.pause(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//查看更多
|
||||
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:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
|
||||
import '../../../hj_utils/widget_util.dart';
|
||||
|
||||
@@ -33,7 +33,9 @@ class _AcgShowMoreTextWidgetState extends State<AcgShowMoreTextWidget> {
|
||||
Widget build(BuildContext context) {
|
||||
//用 LayoutBuilder 拿真实约束宽度测量,避免传入的 maxWidth 与实际渲染宽度不符导致"该展开却没按钮"
|
||||
return LayoutBuilder(builder: (context, cons) {
|
||||
final maxWidth = cons.maxWidth.isFinite ? cons.maxWidth : (widget.maxWidth ?? Get.width);
|
||||
final maxWidth = cons.maxWidth.isFinite
|
||||
? cons.maxWidth
|
||||
: (widget.maxWidth ?? Get.width);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -41,7 +43,9 @@ class _AcgShowMoreTextWidgetState extends State<AcgShowMoreTextWidget> {
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
widget.summary?.isNotEmpty == true ? widget.summary ?? '' : '暂无简介',
|
||||
widget.summary?.isNotEmpty == true
|
||||
? widget.summary ?? ''
|
||||
: '暂无简介',
|
||||
textAlign: TextAlign.left,
|
||||
style: textStyle(12, widget.txColor, FontWeight.w400),
|
||||
maxLines: _isFold ? widget.maxLine : null,
|
||||
@@ -59,7 +63,8 @@ class _AcgShowMoreTextWidgetState extends State<AcgShowMoreTextWidget> {
|
||||
children: [
|
||||
Text(
|
||||
_isFold ? '更多简介' : '收起简介',
|
||||
style: textStyle(12, const Color(0xffEFEFEF), FontWeight.w400),
|
||||
style: textStyle(
|
||||
12, const Color(0xffEFEFEF), FontWeight.w400),
|
||||
),
|
||||
2.sizeBoxW,
|
||||
AnimatedRotation(
|
||||
@@ -93,7 +98,8 @@ class _AcgShowMoreTextWidgetState extends State<AcgShowMoreTextWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
bool _textExceedMaxLines(String text, TextStyle style, int maxLine, double maxWidth) {
|
||||
bool _textExceedMaxLines(
|
||||
String text, TextStyle style, int maxLine, double maxWidth) {
|
||||
//与 Text 组件保持一致:合并 DefaultTextStyle(letterSpacing/字体等差异会导致测量行数偏少)
|
||||
final effectiveStyle = DefaultTextStyle.of(context).style.merge(style);
|
||||
final painter = TextPainter(
|
||||
|
||||
@@ -3,13 +3,13 @@ import 'dart:async';
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:hgmj/hj_model/media_content.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/common_service.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/event_bus_util.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/events.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_helper.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:wydj/hj_model/media_content.dart';
|
||||
import 'package:wydj/hj_utils/api_service/common_service.dart';
|
||||
import 'package:wydj/tools_base/event_bus/event_bus_util.dart';
|
||||
import 'package:wydj/tools_base/event_bus/events.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_helper.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
|
||||
import '../../../alert/video/comic_buy_alert.dart';
|
||||
import '../../../alert/video/vip_acg_dialog.dart';
|
||||
@@ -44,7 +44,9 @@ class ACGSourceManager extends ChangeNotifier {
|
||||
final liked = mediaInfo?.mediaStatus?.hasLiked ?? false;
|
||||
final mid = mediaInfo?.id ?? '';
|
||||
final type = mediaInfo?.mediaType ?? '';
|
||||
final suc = liked ? await CommonService.cancelLike(mid, type) : await CommonService.sendLike(mid, type);
|
||||
final suc = liked
|
||||
? await CommonService.cancelLike(mid, type)
|
||||
: await CommonService.sendLike(mid, type);
|
||||
LoadingHelper.dismissLoading();
|
||||
if (suc) {
|
||||
mediaInfo?.mediaStatus?.hasLiked = !liked;
|
||||
@@ -94,7 +96,8 @@ class ACGSourceManager extends ChangeNotifier {
|
||||
final list = result.list ?? [];
|
||||
// 每页拉到就按集号标免费集(与播放放行/角标同一口径),避免全部拉完才标导致角标迟到
|
||||
for (final e in list) {
|
||||
e.inFreeEpisode = mediaInfo?.isFreeEpisodeNumber(e.episodeNumber) ?? false;
|
||||
e.inFreeEpisode =
|
||||
mediaInfo?.isFreeEpisodeNumber(e.episodeNumber) ?? false;
|
||||
}
|
||||
allEpisodes.addAll(list);
|
||||
notifyListeners();
|
||||
@@ -146,7 +149,8 @@ class ACGSourceManager extends ChangeNotifier {
|
||||
}
|
||||
|
||||
/// 拉漫画章节详情(带缓存 + 权限校验)
|
||||
Future<MediaContent?> getComicsMediaContent({int index = 0, bool showLoading = false}) async {
|
||||
Future<MediaContent?> getComicsMediaContent(
|
||||
{int index = 0, bool showLoading = false}) async {
|
||||
final cached = mediaContentCache[index];
|
||||
if (cached != null) {
|
||||
changeEpisodesIndex(index); // 命中缓存也要同步当前章,否则退回详情页「续看」还停在旧章
|
||||
@@ -244,9 +248,11 @@ class AudioPlayerManager {
|
||||
double playSpeed = 1;
|
||||
|
||||
void initPlayer() {
|
||||
if (_audioPlayer != null) return; // 防重入:已初始化则跳过,避免 5 个 stream 监听重复注册、旧 sub 泄漏
|
||||
if (_audioPlayer != null)
|
||||
return; // 防重入:已初始化则跳过,避免 5 个 stream 监听重复注册、旧 sub 泄漏
|
||||
_audioPlayer = AudioPlayer();
|
||||
_audioPlayer?.setReleaseMode(playMod == AudioPlayMod.loop ? ReleaseMode.loop : ReleaseMode.stop);
|
||||
_audioPlayer?.setReleaseMode(
|
||||
playMod == AudioPlayMod.loop ? ReleaseMode.loop : ReleaseMode.stop);
|
||||
|
||||
_audioDurationSub = _audioPlayer?.onDurationChanged.listen((event) {
|
||||
audioValue.value = AudioPlayerValue.copyWith(value..duration = event);
|
||||
@@ -270,7 +276,8 @@ class AudioPlayerManager {
|
||||
audioValue.value = AudioPlayerValue.copyWith(value..isPlaying = true);
|
||||
break;
|
||||
case PlayerState.paused:
|
||||
audioValue.value = AudioPlayerValue.copyWith(value..isPlaying = false);
|
||||
audioValue.value =
|
||||
AudioPlayerValue.copyWith(value..isPlaying = false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -292,7 +299,8 @@ class AudioPlayerManager {
|
||||
audioValue.value = AudioPlayerValue.copyWith(value..isPlaying = true);
|
||||
});
|
||||
|
||||
audioValue.value = AudioPlayerValue.copyWith(value..isInitialized = _audioPlayer != null);
|
||||
audioValue.value =
|
||||
AudioPlayerValue.copyWith(value..isInitialized = _audioPlayer != null);
|
||||
}
|
||||
|
||||
void setPlaySpeed(double speed) {
|
||||
@@ -355,9 +363,11 @@ class AudioPlayerManager {
|
||||
}
|
||||
|
||||
void setPlayMod(AudioPlayMod mod) {
|
||||
_audioPlayer?.setReleaseMode(mod == AudioPlayMod.loop ? ReleaseMode.loop : ReleaseMode.stop);
|
||||
_audioPlayer?.setReleaseMode(
|
||||
mod == AudioPlayMod.loop ? ReleaseMode.loop : ReleaseMode.stop);
|
||||
playMod = mod;
|
||||
audioValue.value = AudioPlayerValue.copyWith(value..isLooping = mod == AudioPlayMod.loop);
|
||||
audioValue.value =
|
||||
AudioPlayerValue.copyWith(value..isLooping = mod == AudioPlayMod.loop);
|
||||
}
|
||||
|
||||
Future<void> playWithIndex(int index) async {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
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_model/acg/comic_chapters_model.dart';
|
||||
import 'package:hgmj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:hgmj/tools_base/widget/stagger_in_item.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/acg/comic_chapters_model.dart';
|
||||
import 'package:wydj/hj_model/cartoon_media_info.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/tools_base/widget/stagger_in_item.dart';
|
||||
|
||||
import 'acg_source_manager.dart';
|
||||
import 'free_badge.dart';
|
||||
@@ -63,7 +63,8 @@ class _CartoonSubSetAlertState extends State<CartoonSubSetAlert> {
|
||||
16.sizeBoxW,
|
||||
const Text(
|
||||
'漫画列表',
|
||||
style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
),
|
||||
10.sizeBoxW,
|
||||
const Spacer(),
|
||||
@@ -117,13 +118,16 @@ class _CartoonSubSetAlertState extends State<CartoonSubSetAlert> {
|
||||
//与详情/阅读抽屉子集 title 一致:第X话(CartoonDetailPage 只处理 image,恒为漫画)
|
||||
'第${info.episodeNumber ?? ''}${mediaInfo?.unit ?? ''}',
|
||||
style: TextStyle(
|
||||
color: sel ? Colors.white.withValues(alpha: .9) : Colors.white.withValues(alpha: .45),
|
||||
color: sel
|
||||
? Colors.white.withValues(alpha: .9)
|
||||
: Colors.white.withValues(alpha: .45),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
//无任何权限时,前 N 集免费展示「免费」角标
|
||||
if (mediaInfo?.hasPermission == false && info.inFreeEpisode) ...[
|
||||
if (mediaInfo?.hasPermission == false &&
|
||||
info.inFreeEpisode) ...[
|
||||
8.sizeBoxW,
|
||||
const FreeBadge(),
|
||||
],
|
||||
|
||||
@@ -2,26 +2,26 @@ import 'dart:math';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/extension/extensions.dart';
|
||||
import 'package:hgmj/hj_model/comment/comment_model.dart';
|
||||
import 'package:hgmj/hj_model/comment/reply_model.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_page/comment/cell/reply_comment_item.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/comment_service.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/common_service.dart';
|
||||
import 'package:hgmj/hj_utils/date_time_util.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
import 'package:wydj/hj_model/comment/comment_model.dart';
|
||||
import 'package:wydj/hj_model/comment/reply_model.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/comment/cell/reply_comment_item.dart';
|
||||
import 'package:wydj/hj_utils/api_service/comment_service.dart';
|
||||
import 'package:wydj/hj_utils/api_service/common_service.dart';
|
||||
import 'package:wydj/hj_utils/date_time_util.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:like_button/like_button.dart';
|
||||
|
||||
import '../../../tools_base/widget/net_image_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
import '../../home/widget/user_avatar.dart';
|
||||
import '../../home/widget/user_name_view.dart';
|
||||
import '../widget/comment_rich_text.dart';
|
||||
import '../widget/comment_top_banner.dart';
|
||||
import 'package:hgmj/hj_model/banner/comment_top_banner_model.dart';
|
||||
import 'package:wydj/hj_model/banner/comment_top_banner_model.dart';
|
||||
|
||||
/// 一条评论:头像 + 昵称 + 正文(可带图) + 时间/点赞/回复 + 折叠的回复列表
|
||||
class CommentItem extends StatefulWidget {
|
||||
@@ -93,7 +93,8 @@ class _CommentItemState extends State<CommentItem> {
|
||||
),
|
||||
if ((comment.vipLevel ?? 0) > 0) ...[
|
||||
4.sizeBoxW,
|
||||
Image.asset("vip_v.webp".commentPath, width: 16),
|
||||
Image.asset("vip_v.webp".commentPath,
|
||||
width: 16),
|
||||
]
|
||||
],
|
||||
),
|
||||
@@ -108,11 +109,13 @@ class _CommentItemState extends State<CommentItem> {
|
||||
margin: EdgeInsets.only(top: 6),
|
||||
alignment: Alignment.centerLeft,
|
||||
constraints: BoxConstraints(maxWidth: 150),
|
||||
child: NetworkImageLoader(imageUrl: comment.image ?? ""),
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: comment.image ?? ""),
|
||||
),
|
||||
),
|
||||
// 置顶评论配置 Banner(多图轮播,支持 GIF / 内外链)
|
||||
if (widget.topBanners?.isNotEmpty == true) CommentTopBanner(banners: widget.topBanners!),
|
||||
if (widget.topBanners?.isNotEmpty == true)
|
||||
CommentTopBanner(banners: widget.topBanners!),
|
||||
8.sizeBoxH,
|
||||
Row(
|
||||
children: [
|
||||
@@ -124,7 +127,8 @@ class _CommentItemState extends State<CommentItem> {
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
if (!comment.isOfficial && !comment.isHideLikeOrComment) ...[
|
||||
if (!comment.isOfficial &&
|
||||
!comment.isHideLikeOrComment) ...[
|
||||
ValueListenableBuilder(
|
||||
valueListenable: isLikedNof,
|
||||
builder: (context, value, child) => Row(
|
||||
@@ -134,7 +138,9 @@ class _CommentItemState extends State<CommentItem> {
|
||||
onTap: (_) => _toggleLike(),
|
||||
size: 20,
|
||||
likeBuilder: (isLiked) {
|
||||
return Image.asset(isLiked ? 'like_red.webp'.commentPath : 'like_white.webp'.commentPath);
|
||||
return Image.asset(isLiked
|
||||
? 'like_red.webp'.commentPath
|
||||
: 'like_white.webp'.commentPath);
|
||||
},
|
||||
),
|
||||
Text(
|
||||
@@ -149,15 +155,18 @@ class _CommentItemState extends State<CommentItem> {
|
||||
),
|
||||
12.sizeBoxW,
|
||||
GestureDetector(
|
||||
onTap: () => widget.replyHandler?.call(comment),
|
||||
child: Image.asset('msg_icon.png'.commentPath, width: 20),
|
||||
onTap: () =>
|
||||
widget.replyHandler?.call(comment),
|
||||
child: Image.asset('msg_icon.png'.commentPath,
|
||||
width: 20),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
_replyList(),
|
||||
// 展开更多评论
|
||||
if ((comment.replies?.length ?? 0) > 0) _moreReplyBar(),
|
||||
if ((comment.replies?.length ?? 0) > 0)
|
||||
_moreReplyBar(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -192,7 +201,11 @@ class _CommentItemState extends State<CommentItem> {
|
||||
children: [
|
||||
Container(width: 20, height: 1, color: const Color(0xff989898)),
|
||||
4.sizeBoxW,
|
||||
Text(text, style: const TextStyle(fontSize: 12, color: Color(0xff989898), fontWeight: FontWeight.w500)),
|
||||
Text(text,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xff989898),
|
||||
fontWeight: FontWeight.w500)),
|
||||
2.sizeBoxW,
|
||||
isUp ? Transform.rotate(angle: pi, child: chevron) : chevron,
|
||||
],
|
||||
@@ -250,8 +263,8 @@ class _CommentItemState extends State<CommentItem> {
|
||||
if (comment.hasMoreReply ?? false) {
|
||||
final curTime = DateTimeUtil.format2utc(DateTime.now());
|
||||
final fastId = comment.replies!.first.id ?? '';
|
||||
final result =
|
||||
await CommentService.getReplyList(widget.objId, comment.id ?? '', curTime, comment.replyPage ?? _page, 5, fastId);
|
||||
final result = await CommentService.getReplyList(widget.objId,
|
||||
comment.id ?? '', curTime, comment.replyPage ?? _page, 5, fastId);
|
||||
comment.hasMoreReply = result?.hasNext ?? false;
|
||||
comment.replies?.addAll(result?.list ?? []);
|
||||
if (result?.hasNext == true) {
|
||||
@@ -296,7 +309,8 @@ class _CommentItemState extends State<CommentItem> {
|
||||
length,
|
||||
(i) => ReplyCommentItem(
|
||||
replies[i],
|
||||
replyHandler: (reply) => widget.replyHandler?.call(comment, reply: reply),
|
||||
replyHandler: (reply) =>
|
||||
widget.replyHandler?.call(comment, reply: reply),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
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/extension/extensions.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:like_button/like_button.dart';
|
||||
|
||||
import '../../../hj_model/comment/reply_model.dart';
|
||||
import '../../../hj_utils/api_service/common_service.dart';
|
||||
import '../../../tools_base/widget/net_image_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
import '../../user_center_page/user_center_page.dart';
|
||||
|
||||
/// 评论下的一条回复:小头像 + 「A ▸ B」 + 正文(可带图) + 时间/点赞/回复
|
||||
@@ -81,7 +81,8 @@ class _ReplyCommentItemState extends State<ReplyCommentItem> {
|
||||
3.sizeBoxW,
|
||||
Text(
|
||||
reply.toUserName ?? '',
|
||||
style: TextStyle(color: Color(0x73FFFFFF), fontSize: 14),
|
||||
style:
|
||||
TextStyle(color: Color(0x73FFFFFF), fontSize: 14),
|
||||
),
|
||||
]
|
||||
],
|
||||
@@ -111,7 +112,8 @@ class _ReplyCommentItemState extends State<ReplyCommentItem> {
|
||||
children: [
|
||||
Text(
|
||||
reply.createdAt?.utcToAgo() ?? "",
|
||||
style: const TextStyle(color: Color(0x73FFFFFF), fontSize: 12),
|
||||
style: const TextStyle(
|
||||
color: Color(0x73FFFFFF), fontSize: 12),
|
||||
),
|
||||
const Spacer(),
|
||||
ValueListenableBuilder(
|
||||
@@ -123,7 +125,9 @@ class _ReplyCommentItemState extends State<ReplyCommentItem> {
|
||||
onTap: (_) => _toggleLike(),
|
||||
size: 20,
|
||||
likeBuilder: (isLiked) {
|
||||
return Image.asset(isLiked ? 'like_red.webp'.commentPath : 'like_white.webp'.commentPath);
|
||||
return Image.asset(isLiked
|
||||
? 'like_red.webp'.commentPath
|
||||
: 'like_white.webp'.commentPath);
|
||||
},
|
||||
),
|
||||
Text(
|
||||
@@ -139,7 +143,8 @@ class _ReplyCommentItemState extends State<ReplyCommentItem> {
|
||||
12.sizeBoxW,
|
||||
GestureDetector(
|
||||
onTap: () => widget.replyHandler?.call(reply),
|
||||
child: Image.asset('msg_icon.png'.commentPath, width: 20),
|
||||
child:
|
||||
Image.asset('msg_icon.png'.commentPath, width: 20),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/sheet_handle_bar.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/sheet_handle_bar.dart';
|
||||
|
||||
import 'comment_views.dart';
|
||||
|
||||
@@ -35,7 +35,10 @@ Future showCommentDialog(
|
||||
padding: const EdgeInsets.only(left: 16, bottom: 16),
|
||||
child: Text(
|
||||
"${commentCount ?? 0}条评论",
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 14),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
|
||||
@@ -3,10 +3,10 @@ import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_pickers/image_pickers.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/group_text_filed.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/group_text_filed.dart';
|
||||
|
||||
/// 评论输入弹层:点空白关闭,自动聚焦拉起键盘
|
||||
class CommentInputView extends StatefulWidget {
|
||||
@@ -125,19 +125,24 @@ class _CommentInputViewState extends State<CommentInputView> {
|
||||
controller: textCtr,
|
||||
height: 32,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
textStyle: TextStyle(color: Colors.white, fontSize: 14),
|
||||
textStyle:
|
||||
TextStyle(color: Colors.white, fontSize: 14),
|
||||
onSubmitted: (value) {
|
||||
Get.back(result: true);
|
||||
},
|
||||
placeholder: widget.hint ?? '请在此输入评论...',
|
||||
placeholderTextStyle: TextStyle(color: Color(0xff4D4D4D), fontSize: 14),
|
||||
decoration: BoxDecoration(color: Color(0xff1A1A1A), borderRadius: BorderRadius.circular(40)),
|
||||
placeholderTextStyle: TextStyle(
|
||||
color: Color(0xff4D4D4D), fontSize: 14),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xff1A1A1A),
|
||||
borderRadius: BorderRadius.circular(40)),
|
||||
),
|
||||
),
|
||||
),
|
||||
12.sizeBoxW,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 12, top: 4, bottom: 4),
|
||||
padding: const EdgeInsets.only(
|
||||
right: 12, top: 4, bottom: 4),
|
||||
child: GestureDetector(
|
||||
onTap: _pickImage,
|
||||
child: Image.asset(
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/comment/comment_model.dart';
|
||||
import 'package:hgmj/hj_model/comment/reply_model.dart';
|
||||
import 'package:hgmj/hj_page/comment/comment_input_view.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/comment_service.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/common_service.dart';
|
||||
import 'package:hgmj/hj_utils/date_time_util.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_model/comment/comment_model.dart';
|
||||
import 'package:wydj/hj_model/comment/reply_model.dart';
|
||||
import 'package:wydj/hj_page/comment/comment_input_view.dart';
|
||||
import 'package:wydj/hj_utils/api_service/comment_service.dart';
|
||||
import 'package:wydj/hj_utils/api_service/common_service.dart';
|
||||
import 'package:wydj/hj_utils/date_time_util.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
import '../../hj_model/banner/comment_top_banner_model.dart';
|
||||
@@ -49,7 +49,8 @@ mixin CommentMixin on GetxController {
|
||||
String? sendImagePath;
|
||||
if (selectedImagePath.value?.isNotEmpty == true) {
|
||||
try {
|
||||
ImageUploadResultModel? imgResult = await FileUploadTool().uploadImage(selectedImagePath.value!);
|
||||
ImageUploadResultModel? imgResult =
|
||||
await FileUploadTool().uploadImage(selectedImagePath.value!);
|
||||
sendImagePath = imgResult?.coverImg ?? "";
|
||||
if (sendImagePath.isEmpty) {
|
||||
isSendingMsg.value = false;
|
||||
@@ -102,8 +103,10 @@ mixin CommentMixin on GetxController {
|
||||
showToast('已提交,审核通过后将展示');
|
||||
hintText = null;
|
||||
//插在第一条普通评论前面,置顶那几条不动
|
||||
final insertIndex = comments.indexWhere((e) => !e.isHideLikeOrComment);
|
||||
comments.insert(insertIndex == -1 ? comments.length : insertIndex, res);
|
||||
final insertIndex =
|
||||
comments.indexWhere((e) => !e.isHideLikeOrComment);
|
||||
comments.insert(
|
||||
insertIndex == -1 ? comments.length : insertIndex, res);
|
||||
}
|
||||
update();
|
||||
}
|
||||
@@ -116,7 +119,8 @@ mixin CommentMixin on GetxController {
|
||||
}
|
||||
|
||||
// isSend: true 点击了发送按钮, 如果没有发送内容弹键盘, 有内容直接发送
|
||||
readyReplyComment(CommentModel? comment, {ReplyModel? replyModel, bool? isSend}) async {
|
||||
readyReplyComment(CommentModel? comment,
|
||||
{ReplyModel? replyModel, bool? isSend}) async {
|
||||
replyComment = comment;
|
||||
replyCommentModel = replyModel;
|
||||
if (replyModel != null) {
|
||||
@@ -156,7 +160,8 @@ mixin CommentMixin on GetxController {
|
||||
page = 1;
|
||||
}
|
||||
final currentT = DateTimeUtil.format2utc(DateTime.now()) ?? "";
|
||||
final result = await CommentService.getCommentList(id, currentT, page, 20);
|
||||
final result =
|
||||
await CommentService.getCommentList(id, currentT, page, 20);
|
||||
totalCallback?.call(result?.total ?? 0);
|
||||
refreshCtr?.refreshCompleted();
|
||||
refreshCtr?.loadComplete();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_page/comment/cell/comment_item.dart';
|
||||
import 'package:hgmj/hj_page/comment/comment_mixin.dart';
|
||||
import 'package:hgmj/hj_page/comment/widget/comment_foot_view.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/comment/cell/comment_item.dart';
|
||||
import 'package:wydj/hj_page/comment/comment_mixin.dart';
|
||||
import 'package:wydj/hj_page/comment/widget/comment_foot_view.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import '../home/widget/quick_search_view.dart';
|
||||
|
||||
@@ -41,7 +41,6 @@ class CommentLogic extends GetxController with CommentMixin {
|
||||
isLoading = false;
|
||||
fetchComments(objId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CommentView extends StatelessWidget {
|
||||
@@ -63,7 +62,10 @@ class CommentView extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder(
|
||||
init: CommentLogic(objId, commentType: objType, totalCallback: totalCallback, vModel: videoModel),
|
||||
init: CommentLogic(objId,
|
||||
commentType: objType,
|
||||
totalCallback: totalCallback,
|
||||
vModel: videoModel),
|
||||
tag: objId,
|
||||
builder: (logic) => LayoutBuilder(builder: (_, cons) {
|
||||
if (cons.maxHeight < 58) return SizedBox.shrink();
|
||||
@@ -84,7 +86,10 @@ class CommentView extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
margin: EdgeInsets.fromLTRB(12, 0, 12, 12),
|
||||
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Color(0x08ffffff)))),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom:
|
||||
BorderSide(color: Color(0x08ffffff)))),
|
||||
child: QuickSearchView(logic.quickSearchList),
|
||||
),
|
||||
),
|
||||
@@ -92,15 +97,19 @@ class CommentView extends StatelessWidget {
|
||||
itemCount: logic.comments.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final topIndex = logic.topPinnedCommentIndex;
|
||||
final showBanner = index == topIndex && logic.commentTopBanners.isNotEmpty;
|
||||
final showBanner = index == topIndex &&
|
||||
logic.commentTopBanners.isNotEmpty;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: CommentItem(
|
||||
key: ValueKey(logic.comments[index].id),
|
||||
logic.comments[index],
|
||||
objId: objId,
|
||||
topBanners: showBanner ? logic.commentTopBanners : null,
|
||||
replyHandler: (comment, {reply}) => logic.readyReplyComment(comment, replyModel: reply),
|
||||
topBanners:
|
||||
showBanner ? logic.commentTopBanners : null,
|
||||
replyHandler: (comment, {reply}) =>
|
||||
logic.readyReplyComment(comment,
|
||||
replyModel: reply),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -114,7 +123,8 @@ class CommentView extends StatelessWidget {
|
||||
Obx(
|
||||
() => CommentFootView(
|
||||
isSending: logic.isSendingMsg.value,
|
||||
onComment: (isSend) => logic.readyReplyComment(null, isSend: isSend),
|
||||
onComment: (isSend) =>
|
||||
logic.readyReplyComment(null, isSend: isSend),
|
||||
textCtr: logic.commentController,
|
||||
imgPath: logic.selectedImagePath.value,
|
||||
onImgChange: (value) => logic.selectedImagePath.value = value,
|
||||
|
||||
@@ -4,14 +4,14 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:image_pickers/image_pickers.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/group_text_filed.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/group_text_filed.dart';
|
||||
|
||||
import '../../../hj_utils/api_service/mine_service.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import '../../mine/collec_history_buy/col_his_buy_sub_page.dart';
|
||||
|
||||
/// 底部评论条:假输入框 + 选图 + 收藏 + 发送
|
||||
@@ -50,7 +50,8 @@ class _CommentFootViewState extends State<CommentFootView> {
|
||||
selectCount: 1,
|
||||
showCamera: false,
|
||||
);
|
||||
if (listMedia.isNotEmpty) widget.onImgChange?.call(listMedia.first.path ?? '');
|
||||
if (listMedia.isNotEmpty)
|
||||
widget.onImgChange?.call(listMedia.first.path ?? '');
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
@@ -60,7 +61,8 @@ class _CommentFootViewState extends State<CommentFootView> {
|
||||
try {
|
||||
final preCollect = isCollect;
|
||||
|
||||
await MineService.postCollect(widget.video?.id, LoadDataType.post.apiType, !isCollect);
|
||||
await MineService.postCollect(
|
||||
widget.video?.id, LoadDataType.post.apiType, !isCollect);
|
||||
|
||||
if (!preCollect) {
|
||||
widget.video?.collectCount = (widget.video?.collectCount ?? 0) + 1;
|
||||
@@ -82,100 +84,106 @@ class _CommentFootViewState extends State<CommentFootView> {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.black,
|
||||
padding: EdgeInsets.only(left: 18.w, right: 18.w, bottom: screen.paddingBottom),
|
||||
padding: EdgeInsets.only(
|
||||
left: 18.w, right: 18.w, bottom: screen.paddingBottom),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SizedBox(
|
||||
height: 58,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.onComment(false),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 2),
|
||||
child: GroupTextFiled(
|
||||
controller: widget.textCtr,
|
||||
height: 32,
|
||||
enabled: false,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
textStyle: TextStyle(color: Colors.white, fontSize: 14),
|
||||
placeholder: '请在此输入评论...',
|
||||
placeholderTextStyle: TextStyle(color: Color(0xff525252), fontSize: 14),
|
||||
decoration: BoxDecoration(color: Colors.white.withValues(alpha: .1), borderRadius: BorderRadius.circular(16)),
|
||||
children: [
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.onComment(false),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 2),
|
||||
child: GroupTextFiled(
|
||||
controller: widget.textCtr,
|
||||
height: 32,
|
||||
enabled: false,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
textStyle: TextStyle(color: Colors.white, fontSize: 14),
|
||||
placeholder: '请在此输入评论...',
|
||||
placeholderTextStyle:
|
||||
TextStyle(color: Color(0xff525252), fontSize: 14),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: .1),
|
||||
borderRadius: BorderRadius.circular(16)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
12.sizeBoxW,
|
||||
Stack(
|
||||
children: [
|
||||
12.sizeBoxW,
|
||||
Stack(
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.fromLTRB(0, 4, 4, 4),
|
||||
width: 30,
|
||||
height: 30,
|
||||
alignment: Alignment.center,
|
||||
child: GestureDetector(
|
||||
onTap: _pickImage,
|
||||
child: widget.imgPath?.isNotEmpty == true
|
||||
? Image.file(
|
||||
File(widget.imgPath!),
|
||||
width: 30,
|
||||
height: 30,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Image.asset(
|
||||
'icon_pic.webp'.commentPath,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.imgPath?.isNotEmpty == true)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
widget.onImgChange?.call(null);
|
||||
setState(() {});
|
||||
},
|
||||
child: Image.asset(
|
||||
"close_grey.png".commonImgPath,
|
||||
width: 12,
|
||||
height: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.showCollect)
|
||||
Container(
|
||||
margin: EdgeInsets.fromLTRB(0, 4, 4, 4),
|
||||
width: 30,
|
||||
height: 30,
|
||||
alignment: Alignment.center,
|
||||
child: GestureDetector(
|
||||
onTap: _pickImage,
|
||||
child: widget.imgPath?.isNotEmpty == true
|
||||
? Image.file(
|
||||
File(widget.imgPath!),
|
||||
width: 30,
|
||||
height: 30,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Image.asset(
|
||||
'icon_pic.webp'.commentPath,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.imgPath?.isNotEmpty == true)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
widget.onImgChange?.call(null);
|
||||
setState(() {});
|
||||
},
|
||||
child: Image.asset(
|
||||
"close_grey.png".commonImgPath,
|
||||
width: 12,
|
||||
height: 12,
|
||||
),
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: _onCollect,
|
||||
child: Image.asset(
|
||||
isCollect
|
||||
? "collect_red.png".commonImgPath
|
||||
: "collect_path.png".commonImgPath,
|
||||
width: 24,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.showCollect)
|
||||
Container(
|
||||
),
|
||||
SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
alignment: Alignment.center,
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: _onCollect,
|
||||
child: Image.asset(
|
||||
isCollect ? "collect_red.png".commonImgPath : "collect_path.png".commonImgPath,
|
||||
width: 24,
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.onComment(true),
|
||||
child: widget.isSending
|
||||
? CupertinoActivityIndicator(
|
||||
color: AppColors.actionRed,
|
||||
radius: 12,
|
||||
)
|
||||
: Image.asset('ic_send.webp'.commentPath),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.onComment(true),
|
||||
child: widget.isSending
|
||||
? CupertinoActivityIndicator(
|
||||
color: AppColors.actionRed,
|
||||
radius: 12,
|
||||
)
|
||||
: Image.asset('ic_send.webp'.commentPath),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/hj_model/comment/comment_model.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:wydj/hj_model/comment/comment_model.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
|
||||
/// 评论正文:命中搜索词时把该词渲染成可点的橙色链接,其余按纯文本
|
||||
class CommentRichText extends StatelessWidget {
|
||||
@@ -13,8 +13,11 @@ class CommentRichText extends StatelessWidget {
|
||||
const style = TextStyle(color: Color(0xE5FFFFFF), fontSize: 14);
|
||||
final keyword = model?.searchKeyword ?? "";
|
||||
//按关键词切开,段与段之间插链接;切不出两段就当纯文本
|
||||
final parts = keyword.isEmpty ? <String>[] : (model?.content?.split(keyword) ?? []);
|
||||
if (model?.linkStr?.isNotEmpty != true || keyword.isEmpty || parts.length <= 1) {
|
||||
final parts =
|
||||
keyword.isEmpty ? <String>[] : (model?.content?.split(keyword) ?? []);
|
||||
if (model?.linkStr?.isNotEmpty != true ||
|
||||
keyword.isEmpty ||
|
||||
parts.length <= 1) {
|
||||
return Text(model?.content ?? '', style: style);
|
||||
}
|
||||
return Text.rich(
|
||||
@@ -29,7 +32,8 @@ class CommentRichText extends StatelessWidget {
|
||||
onTap: () => pushToPageByLink(model?.linkStr),
|
||||
child: Text(
|
||||
keyword,
|
||||
style: const TextStyle(color: Color(0xffF68804), fontSize: 14, height: 1.2),
|
||||
style: const TextStyle(
|
||||
color: Color(0xffF68804), fontSize: 14, height: 1.2),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/hj_model/banner/comment_top_banner_model.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/banner/ads_banner.dart';
|
||||
import 'package:hgmj/tools_base/widget/card_swiper/src/swiper.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/hj_model/banner/comment_top_banner_model.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/banner/ads_banner.dart';
|
||||
import 'package:wydj/tools_base/widget/card_swiper/src/swiper.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
/// 评论区置顶评论下方 Banner:支持多图轮播(含 GIF),按 linkType 跳转内外链
|
||||
class CommentTopBanner extends StatefulWidget {
|
||||
final List<CommentTopBannerModel> banners;
|
||||
final double borderRadius;
|
||||
|
||||
/// 宽高比,默认对齐站内 Banner 素材 720×150;勿用固定高度,窄/宽屏 cover 会裁切
|
||||
final double aspectRatio;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/config/config.dart';
|
||||
import 'package:wydj/config/config.dart';
|
||||
import '../../main_page/provider/bottom_bar_provider.dart';
|
||||
|
||||
class CommunityMainModuleLogic extends GetxController
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import '../../../tools_base/indicator/custom_tab_indicator.dart';
|
||||
import '../../../tools_base/loading/loading_center_widget.dart';
|
||||
@@ -28,15 +28,24 @@ class CommunityModulePage extends StatelessWidget {
|
||||
labelPadding: EdgeInsets.zero,
|
||||
padding: EdgeInsets.zero,
|
||||
tabAlignment: TabAlignment.start,
|
||||
indicator: CustomIndicator(width: 16, height: 2, offsetY: 6, color: Color(0xFFFFC000)),
|
||||
indicator: CustomIndicator(
|
||||
width: 16,
|
||||
height: 2,
|
||||
offsetY: 6,
|
||||
color: Color(0xFFFFC000)),
|
||||
indicatorWeight: 1,
|
||||
unselectedLabelStyle: TextStyle(color: Colors.white.withValues(alpha: .9), fontSize: 16),
|
||||
labelStyle: TextStyle(color: Colors.white.withValues(alpha: .9), fontSize: 16, fontWeight: FontWeight.w500),
|
||||
unselectedLabelStyle: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .9), fontSize: 16),
|
||||
labelStyle: TextStyle(
|
||||
color: Colors.white.withValues(alpha: .9),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500),
|
||||
isScrollable: true,
|
||||
tabs: logic.modules
|
||||
.map(
|
||||
(e) => Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 13.h),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 16.w, vertical: 13.h),
|
||||
child: Text(e.moduleName ?? ''),
|
||||
),
|
||||
)
|
||||
@@ -55,7 +64,8 @@ class CommunityModulePage extends StatelessWidget {
|
||||
model: value,
|
||||
index: key,
|
||||
cancelCallBack: () {
|
||||
logic.tabController.index = logic.tabController.previousIndex;
|
||||
logic.tabController.index =
|
||||
logic.tabController.previousIndex;
|
||||
},
|
||||
).keepAlive,
|
||||
),
|
||||
|
||||
@@ -2,12 +2,12 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/vid_service.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/event_bus_util.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/events.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/api_service/vid_service.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/tools_base/event_bus/event_bus_util.dart';
|
||||
import 'package:wydj/tools_base/event_bus/events.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
import '../../../hj_model/home/plate_model.dart';
|
||||
@@ -21,7 +21,8 @@ class CommunityTabLogic extends GetxController {
|
||||
CommunityTabLogic(this.model, {this.index = 0});
|
||||
|
||||
RefreshController? refreshController;
|
||||
late ScrollController sctrl = CommunityBottomProvider().scrollCtr(MediaStyle.Community, index);
|
||||
late ScrollController sctrl =
|
||||
CommunityBottomProvider().scrollCtr(MediaStyle.Community, index);
|
||||
|
||||
int page = 1;
|
||||
bool isLoading = true;
|
||||
@@ -60,7 +61,8 @@ class CommunityTabLogic extends GetxController {
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_collectStatusSub = eventBus.on<CollectStatusModel>(_onCollectStatusChanged);
|
||||
_collectStatusSub =
|
||||
eventBus.on<CollectStatusModel>(_onCollectStatusChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -91,7 +93,8 @@ class CommunityTabLogic extends GetxController {
|
||||
sctrl.jumpTo(0);
|
||||
}
|
||||
|
||||
Future<void> fetchPagedata({bool isRefresh = true, bool needLoading = false}) async {
|
||||
Future<void> fetchPagedata(
|
||||
{bool isRefresh = true, bool needLoading = false}) async {
|
||||
if (isRefresh) {
|
||||
page = 1;
|
||||
}
|
||||
@@ -110,19 +113,24 @@ class CommunityTabLogic extends GetxController {
|
||||
dataSource.clear();
|
||||
refreshController?.refreshCompleted();
|
||||
}
|
||||
(res?.hasNext ?? false) ? refreshController?.loadComplete() : refreshController?.loadNoData();
|
||||
(res?.hasNext ?? false)
|
||||
? refreshController?.loadComplete()
|
||||
: refreshController?.loadNoData();
|
||||
dataSource.addAll(res?.allVideoInfo ?? []);
|
||||
if ((res?.allSection?.isNotEmpty ?? false) && specials.isEmpty) {
|
||||
specials.addAll(res!.allSection?.firstOrNull?.allTags ?? []);
|
||||
if (model?.defaultTagId?.isNotEmpty == true) {
|
||||
tagIndex = specials.indexWhere((element) => element.id == model?.defaultTagId);
|
||||
tagIndex = specials
|
||||
.indexWhere((element) => element.id == model?.defaultTagId);
|
||||
}
|
||||
}
|
||||
page += 1;
|
||||
} catch (e) {
|
||||
// 接口异常兜底:结束刷新/加载态,避免 loading、下拉/上拉指示器卡死
|
||||
debugLog(e);
|
||||
isRefresh ? refreshController?.refreshCompleted() : refreshController?.loadComplete();
|
||||
isRefresh
|
||||
? refreshController?.refreshCompleted()
|
||||
: refreshController?.loadComplete();
|
||||
} finally {
|
||||
isLoading = false;
|
||||
update();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.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/banner/ads_grid_view.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/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/banner/ads_grid_view.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import '../../../hj_model/home/plate_model.dart';
|
||||
import '../../../hj_model/video_model.dart';
|
||||
@@ -14,7 +14,7 @@ import '../../../tools_base/widget/net_image_widget.dart';
|
||||
import '../widget/community_middle_header.dart';
|
||||
import '../widget/community_post_widget.dart';
|
||||
import 'community_tab_logic.dart';
|
||||
import 'package:hgmj/extension/extensions.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
|
||||
class CommunityTabPage extends StatelessWidget {
|
||||
final ModuleData model;
|
||||
@@ -36,40 +36,40 @@ class CommunityTabPage extends StatelessWidget {
|
||||
builder: (logic) {
|
||||
return pullYsRefresh(
|
||||
onInit: (ctr) => logic.refreshController = ctr,
|
||||
onRefresh: (_) => logic.fetchPagedata(),
|
||||
onLoading: (_) => logic.fetchPagedata(isRefresh: false),
|
||||
child: CustomScrollView(
|
||||
controller: logic.sctrl,
|
||||
slivers: [
|
||||
if (model.pureVersion != true)
|
||||
SliverToBoxAdapter(
|
||||
child: AdsGridView(
|
||||
7,
|
||||
autoStyle: true,
|
||||
padding: EdgeInsets.fromLTRB(16.w, 0, 16.w, 10.h),
|
||||
),
|
||||
),
|
||||
onRefresh: (_) => logic.fetchPagedata(),
|
||||
onLoading: (_) => logic.fetchPagedata(isRefresh: false),
|
||||
child: CustomScrollView(
|
||||
controller: logic.sctrl,
|
||||
slivers: [
|
||||
if (model.pureVersion != true)
|
||||
SliverToBoxAdapter(
|
||||
child: _buildSpecialView(logic),
|
||||
),
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
floating: true,
|
||||
delegate: MySliverDelegate(
|
||||
maxHeight: 34,
|
||||
minHeight: 34,
|
||||
child: CommunityMiddleHeader(
|
||||
sortOnTap: (sort) {
|
||||
logic.sort = sort;
|
||||
logic.fetchPagedata(needLoading: true);
|
||||
},
|
||||
),
|
||||
child: AdsGridView(
|
||||
7,
|
||||
autoStyle: true,
|
||||
padding: EdgeInsets.fromLTRB(16.w, 0, 16.w, 10.h),
|
||||
),
|
||||
),
|
||||
_buildTableView(logic),
|
||||
],
|
||||
),
|
||||
);
|
||||
SliverToBoxAdapter(
|
||||
child: _buildSpecialView(logic),
|
||||
),
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
floating: true,
|
||||
delegate: MySliverDelegate(
|
||||
maxHeight: 34,
|
||||
minHeight: 34,
|
||||
child: CommunityMiddleHeader(
|
||||
sortOnTap: (sort) {
|
||||
logic.sort = sort;
|
||||
logic.fetchPagedata(needLoading: true);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildTableView(logic),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -88,7 +88,8 @@ class CommunityTabPage extends StatelessWidget {
|
||||
itemCount: logic.specials.length,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return InkWell(enableFeedback: false,
|
||||
return InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => logic.changeSpecialsIndex(index),
|
||||
child: _buildSpecialTagCell(logic, index),
|
||||
);
|
||||
@@ -124,7 +125,9 @@ class CommunityTabPage extends StatelessWidget {
|
||||
height: double.infinity,
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(6), color: Colors.black.withValues(alpha: .6)),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
color: Colors.black.withValues(alpha: .6)),
|
||||
),
|
||||
if (model.hotMark?.isNotEmpty == true)
|
||||
Positioned(
|
||||
@@ -162,12 +165,20 @@ class CommunityTabPage extends StatelessWidget {
|
||||
Text(
|
||||
"${model.tagName}",
|
||||
style: TextStyle(
|
||||
color: logic.tagIndex == index ? AppColors.actionRed : Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
color: logic.tagIndex == index
|
||||
? AppColors.actionRed
|
||||
: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
2.sizeBoxH,
|
||||
Text(
|
||||
"${model.videoCount?.countStr}个帖子",
|
||||
style: TextStyle(color: logic.tagIndex == index ? AppColors.actionRed : Colors.white, fontSize: 12),
|
||||
style: TextStyle(
|
||||
color: logic.tagIndex == index
|
||||
? AppColors.actionRed
|
||||
: Colors.white,
|
||||
fontSize: 12),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
|
||||
import '../../main_page/main_logic.dart';
|
||||
import '../../main_page/provider/bottom_bar_provider.dart';
|
||||
|
||||
class CommunityMainLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
class CommunityMainLogic extends GetxController
|
||||
with GetTickerProviderStateMixin {
|
||||
final int index;
|
||||
|
||||
CommunityMainLogic({this.index = 0});
|
||||
@@ -30,13 +31,18 @@ class CommunityMainLogic extends GetxController with GetTickerProviderStateMixin
|
||||
];
|
||||
|
||||
// tab 顺序对应的媒体类型:社区/色图/小说
|
||||
static const List<MediaStyle> _tabTypes = [MediaStyle.Community, MediaStyle.Pic, MediaStyle.Novel];
|
||||
static const List<MediaStyle> _tabTypes = [
|
||||
MediaStyle.Community,
|
||||
MediaStyle.Pic,
|
||||
MediaStyle.Novel
|
||||
];
|
||||
|
||||
late TabController tabCtr;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
tabCtr = TabController(length: tabs.length, vsync: this, initialIndex: index);
|
||||
tabCtr =
|
||||
TabController(length: tabs.length, vsync: this, initialIndex: index);
|
||||
tabCtr.addListener(() {
|
||||
if (tabCtr.indexIsChanging) return;
|
||||
CommunityBottomProvider().communityType = _tabTypes[tabCtr.index];
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
|
||||
import '../../../config/config.dart';
|
||||
import '../../cartoon/cartoon_sub_module_page.dart';
|
||||
@@ -25,7 +25,8 @@ class CommunityMainPage extends StatefulWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class CommunityMainPageState extends State<CommunityMainPage> with SingleTickerProviderStateMixin {
|
||||
class CommunityMainPageState extends State<CommunityMainPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -37,7 +38,8 @@ class CommunityMainPageState extends State<CommunityMainPage> with SingleTickerP
|
||||
//提前加载图片资源
|
||||
precacheImage(AssetImage('community_main_sel.png'.communityPath), context);
|
||||
precacheImage(AssetImage('community_pic_sel.png'.communityPath), context);
|
||||
precacheImage(AssetImage('community_chatgroup_sel.png'.communityPath), context);
|
||||
precacheImage(
|
||||
AssetImage('community_chatgroup_sel.png'.communityPath), context);
|
||||
precacheImage(AssetImage('community_noval_sel.png'.communityPath), context);
|
||||
}
|
||||
|
||||
@@ -56,7 +58,8 @@ class CommunityMainPageState extends State<CommunityMainPage> with SingleTickerP
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: _buildTabbar(_)),
|
||||
if (Config.signIcon != null && Config.signIcon!.isNotEmpty) ...[
|
||||
if (Config.signIcon != null &&
|
||||
Config.signIcon!.isNotEmpty) ...[
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => Get.to(SignDailyPage()),
|
||||
@@ -85,7 +88,8 @@ class CommunityMainPageState extends State<CommunityMainPage> with SingleTickerP
|
||||
children: [
|
||||
//社区
|
||||
CommunityModulePage(
|
||||
defaultIndex: widget.index == 0 ? widget.subTabIndex : 0,
|
||||
defaultIndex:
|
||||
widget.index == 0 ? widget.subTabIndex : 0,
|
||||
).keepAlive,
|
||||
//图集
|
||||
CartoonSubModulePage(
|
||||
|
||||
@@ -2,16 +2,18 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/tag_service.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/api_service/tag_service.dart';
|
||||
|
||||
class CommunityTagLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
class CommunityTagLogic extends GetxController
|
||||
with GetTickerProviderStateMixin {
|
||||
final scrollCtr = ScrollController();
|
||||
double? offset;
|
||||
bool isPinned = false;
|
||||
TagsBean model;
|
||||
StreamController<bool> showAppCtr = StreamController.broadcast();
|
||||
late final TabController mainTabCtr = TabController(length: sorts.length, vsync: this);
|
||||
late final TabController mainTabCtr =
|
||||
TabController(length: sorts.length, vsync: this);
|
||||
|
||||
RxBool isLoadingFollow = false.obs;
|
||||
final sorts = [2, 1, 5]; //排序类型 1:最新上架 2:最多收藏 3:本月最热 4:最多观看
|
||||
|
||||
@@ -2,12 +2,12 @@ import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:hgmj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/unique_tag_mixin.dart';
|
||||
import 'package:wydj/tools_base/widget/keep_alive_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../../tools_base/widget/follow_button.dart';
|
||||
@@ -23,7 +23,6 @@ class UserCenterSortTypeEvent {
|
||||
}
|
||||
|
||||
class CommunityTagDetailPage extends StatefulWidget {
|
||||
|
||||
final TagsBean model;
|
||||
|
||||
const CommunityTagDetailPage({super.key, required this.model});
|
||||
@@ -32,7 +31,8 @@ class CommunityTagDetailPage extends StatefulWidget {
|
||||
State<CommunityTagDetailPage> createState() => _CommunityTagDetailPageState();
|
||||
}
|
||||
|
||||
class _CommunityTagDetailPageState extends State<CommunityTagDetailPage> with UniqueTagMixin {
|
||||
class _CommunityTagDetailPageState extends State<CommunityTagDetailPage>
|
||||
with UniqueTagMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<CommunityTagLogic>(
|
||||
@@ -44,7 +44,8 @@ class _CommunityTagDetailPageState extends State<CommunityTagDetailPage> with Un
|
||||
children: [
|
||||
ExtendedNestedScrollView(
|
||||
controller: controller.scrollCtr,
|
||||
pinnedHeaderSliverHeightBuilder: () => AppBar().preferredSize.height + screen.paddingTop,
|
||||
pinnedHeaderSliverHeightBuilder: () =>
|
||||
AppBar().preferredSize.height + screen.paddingTop,
|
||||
headerSliverBuilder: (_, istop) {
|
||||
return [
|
||||
SliverAppBar(
|
||||
@@ -73,7 +74,9 @@ class _CommunityTagDetailPageState extends State<CommunityTagDetailPage> with Un
|
||||
controller: controller.mainTabCtr,
|
||||
children: controller.sorts
|
||||
.map(
|
||||
(e) => TagDetailSubView<TagCOVERController>(tag: controller.model, postSort: e).keepAlive,
|
||||
(e) => TagDetailSubView<TagCOVERController>(
|
||||
tag: controller.model, postSort: e)
|
||||
.keepAlive,
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
@@ -98,7 +101,9 @@ class _CommunityTagDetailPageState extends State<CommunityTagDetailPage> with Un
|
||||
GestureDetector(
|
||||
onTap: () => Get.back(),
|
||||
child: Image.asset(
|
||||
isTop ? 'common_back.png'.commonImgPath : 'back_circle.png'.commonImgPath,
|
||||
isTop
|
||||
? 'common_back.png'.commonImgPath
|
||||
: 'back_circle.png'.commonImgPath,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
@@ -127,7 +132,8 @@ class _CommunityTagDetailPageState extends State<CommunityTagDetailPage> with Un
|
||||
mediaId: controller.model.id,
|
||||
isFollow: controller.model.hasCollected ?? false,
|
||||
followType: FollowEnum.tag,
|
||||
onSuccess: (success) => controller.model.hasCollected = success,
|
||||
onSuccess: (success) =>
|
||||
controller.model.hasCollected = success,
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/tag_service.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/event_bus_util.dart';
|
||||
import 'package:hgmj/tools_base/event_bus/events.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/api_service/tag_service.dart';
|
||||
import 'package:wydj/tools_base/event_bus/event_bus_util.dart';
|
||||
import 'package:wydj/tools_base/event_bus/events.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
import '../../../home/widget/collect_status_wrapper.dart';
|
||||
@@ -42,7 +42,8 @@ abstract class TagDetailSubController extends GetxController {
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_collectStatusSub = eventBus.on<CollectStatusModel>(_onCollectStatusChanged);
|
||||
_collectStatusSub =
|
||||
eventBus.on<CollectStatusModel>(_onCollectStatusChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -81,7 +82,9 @@ abstract class TagDetailSubController extends GetxController {
|
||||
page += 1;
|
||||
isLoading = false;
|
||||
update();
|
||||
res?.hasNext ?? false ? controller?.loadComplete() : controller?.loadNoData();
|
||||
res?.hasNext ?? false
|
||||
? controller?.loadComplete()
|
||||
: controller?.loadNoData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +122,8 @@ class TagCOVERController extends TagDetailSubController {
|
||||
|
||||
T instanceController<T>(TagsBean tag, {int? postSort}) {
|
||||
// Type 对象比较,避免 release 混淆下类名字符串匹配失败导致 throw→灰屏
|
||||
if (T == TagCOVERController) return TagCOVERController(tag, postSort: postSort) as T;
|
||||
if (T == TagCOVERController)
|
||||
return TagCOVERController(tag, postSort: postSort) as T;
|
||||
if (T == TagSPController) return TagSPController(tag) as T;
|
||||
if (T == TagVideoController) return TagVideoController(tag) as T;
|
||||
throw '$T 没有对应类型';
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import '../../../home/home_cell_style/video_simple_cell.dart';
|
||||
import '../../widget/community_post_widget.dart';
|
||||
import 'tag_detail_sub_controller.dart';
|
||||
|
||||
class TagDetailSubView<T extends TagDetailSubController> extends StatelessWidget {
|
||||
class TagDetailSubView<T extends TagDetailSubController>
|
||||
extends StatelessWidget {
|
||||
final TagsBean tag;
|
||||
|
||||
final int? postSort;
|
||||
@@ -25,7 +26,8 @@ class TagDetailSubView<T extends TagDetailSubController> extends StatelessWidget
|
||||
builder: (controller) {
|
||||
if (controller.isLoading) return LoadingCenterWidget();
|
||||
return pullYsRefresh(
|
||||
onLoading: (refreshController) => controller.fetchPageData(isRefresh: false),
|
||||
onLoading: (refreshController) =>
|
||||
controller.fetchPageData(isRefresh: false),
|
||||
onRefresh: (refreshController) => controller.fetchPageData(),
|
||||
child: () {
|
||||
if (controller.dataSource.isEmpty) return CErrorWidget();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_utils/pay/pay_manager.dart';
|
||||
import 'package:hgmj/extension/extensions.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/hj_utils/pay/pay_manager.dart';
|
||||
import 'package:wydj/extension/extensions.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';
|
||||
|
||||
import '../model/im_group_list_model.dart';
|
||||
@@ -32,7 +32,8 @@ class _GroupBuyBottomSheetState extends State<GroupBuyBottomSheet> {
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<GlobalStore>(
|
||||
builder: (_, store, __) {
|
||||
final enough = (store.wallet?.amount ?? 0) >= (widget.groupModel.price ?? 0);
|
||||
final enough =
|
||||
(store.wallet?.amount ?? 0) >= (widget.groupModel.price ?? 0);
|
||||
return _buildNormal(enough, store);
|
||||
},
|
||||
);
|
||||
@@ -76,7 +77,8 @@ class _GroupBuyBottomSheetState extends State<GroupBuyBottomSheet> {
|
||||
children: [
|
||||
Text(
|
||||
'${widget.groupModel.price ?? 0} 金币',
|
||||
style: TextStyle(color: AppColors.actionRed, fontSize: 14),
|
||||
style:
|
||||
TextStyle(color: AppColors.actionRed, fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -107,7 +109,8 @@ class _GroupBuyBottomSheetState extends State<GroupBuyBottomSheet> {
|
||||
),
|
||||
),
|
||||
12.sizeBoxW,
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () => pushToWalletPage(tabPosition: 1),
|
||||
child: Text(
|
||||
'充值',
|
||||
@@ -137,8 +140,13 @@ class _GroupBuyBottomSheetState extends State<GroupBuyBottomSheet> {
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
enough ? '${widget.groupModel.price ?? 0} 金币/立即支付' : '余额不足,前往充值',
|
||||
style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
|
||||
enough
|
||||
? '${widget.groupModel.price ?? 0} 金币/立即支付'
|
||||
: '余额不足,前往充值',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
import '../../../../hj_utils/api_service/group_service.dart';
|
||||
@@ -47,7 +47,9 @@ class GroupChatDetailLogic extends GetxController {
|
||||
msgList?.clear();
|
||||
}
|
||||
msgList?.addAll(retResp.list ?? []);
|
||||
retResp.hasNext == true ? refreshController?.loadComplete() : refreshController?.loadNoData();
|
||||
retResp.hasNext == true
|
||||
? refreshController?.loadComplete()
|
||||
: refreshController?.loadNoData();
|
||||
} catch (e) {
|
||||
debugLog(e);
|
||||
refreshController?.loadComplete();
|
||||
@@ -57,7 +59,9 @@ class GroupChatDetailLogic extends GetxController {
|
||||
}
|
||||
|
||||
Future readySendMsg({bool? isSend}) async {
|
||||
if (isSend == true && (textEditController.text.isNotEmpty || selectedImagePath.value?.isNotEmpty == true)) {
|
||||
if (isSend == true &&
|
||||
(textEditController.text.isNotEmpty ||
|
||||
selectedImagePath.value?.isNotEmpty == true)) {
|
||||
// 点击发送按钮有内容,直接发送内容, 否则弹出输入框
|
||||
sendMsgEvent();
|
||||
} else {
|
||||
@@ -82,7 +86,8 @@ class GroupChatDetailLogic extends GetxController {
|
||||
}
|
||||
|
||||
Future sendMsgEvent() async {
|
||||
if (textEditController.text.isEmpty && selectedImagePath.value?.isNotEmpty != true) {
|
||||
if (textEditController.text.isEmpty &&
|
||||
selectedImagePath.value?.isNotEmpty != true) {
|
||||
showToast("请输入消息内容");
|
||||
return;
|
||||
}
|
||||
@@ -91,7 +96,8 @@ class GroupChatDetailLogic extends GetxController {
|
||||
String? sendImagePath;
|
||||
if (selectedImagePath.value?.isNotEmpty == true) {
|
||||
try {
|
||||
ImageUploadResultModel? imgResult = await FileUploadTool().uploadImage(selectedImagePath.value!);
|
||||
ImageUploadResultModel? imgResult =
|
||||
await FileUploadTool().uploadImage(selectedImagePath.value!);
|
||||
sendImagePath = imgResult?.coverImg ?? "";
|
||||
if (sendImagePath.isEmpty) {
|
||||
isSendingMsg.value = false;
|
||||
@@ -106,13 +112,15 @@ class GroupChatDetailLogic extends GetxController {
|
||||
}
|
||||
}
|
||||
try {
|
||||
var ret = await GroupService.sendMessage(model.groupId, textEditController.text, sendImagePath);
|
||||
var ret = await GroupService.sendMessage(
|
||||
model.groupId, textEditController.text, sendImagePath);
|
||||
if (ret.isSuccess) {
|
||||
textEditController.text = "";
|
||||
selectedImagePath.value = null;
|
||||
showToast("消息已发送");
|
||||
if (ret.data is Map && (ret.data['message'] is Map)) {
|
||||
IMMessageModel sendModel = IMMessageModel.fromJson(ret.data['message']);
|
||||
IMMessageModel sendModel =
|
||||
IMMessageModel.fromJson(ret.data['message']);
|
||||
sendModel.portrait = globalStore.meInfo?.portrait;
|
||||
sendModel.name = globalStore.meInfo?.name;
|
||||
msgList?.insert(0, sendModel);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_page/comment/widget/comment_foot_view.dart';
|
||||
import 'package:wydj/hj_page/comment/widget/comment_foot_view.dart';
|
||||
|
||||
import 'package:hgmj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import '../model/im_group_list_model.dart';
|
||||
import 'soul_group_detail_logic.dart';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../../../../tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
import '../../model/im_message_resp.dart';
|
||||
|
||||
class ChatItemCell extends StatefulWidget {
|
||||
@@ -87,7 +87,8 @@ class _ChatItemCellState extends State<ChatItemCell> {
|
||||
SizedBox(height: 10),
|
||||
if (widget.model?.content?.isNotEmpty == true)
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 10),
|
||||
margin: EdgeInsets.only(top: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.05),
|
||||
@@ -106,7 +107,8 @@ class _ChatItemCellState extends State<ChatItemCell> {
|
||||
),
|
||||
),
|
||||
if (isImg)
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
_showImageScan(widget.model?.image ?? "");
|
||||
},
|
||||
@@ -155,7 +157,8 @@ class _ChatItemCellState extends State<ChatItemCell> {
|
||||
SizedBox(height: 10),
|
||||
if (widget.model?.content?.isNotEmpty == true)
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 10),
|
||||
margin: EdgeInsets.only(top: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xff1DC194),
|
||||
@@ -174,7 +177,8 @@ class _ChatItemCellState extends State<ChatItemCell> {
|
||||
),
|
||||
),
|
||||
if (isImg)
|
||||
InkWell(enableFeedback: false,
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
_showImageScan(widget.model?.image ?? "");
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
import '../../../hj_utils/api_service/group_service.dart';
|
||||
@@ -33,7 +33,9 @@ class GroupChatLogic extends GetxController {
|
||||
groupList?.clear();
|
||||
}
|
||||
groupList?.addAll(retResp?.list ?? []);
|
||||
retResp?.hasNext == true ? refreshController?.loadComplete() : refreshController?.loadNoData();
|
||||
retResp?.hasNext == true
|
||||
? refreshController?.loadComplete()
|
||||
: refreshController?.loadNoData();
|
||||
} catch (e) {
|
||||
debugLog(e);
|
||||
refreshController?.loadComplete();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_page/main_page/provider/bottom_bar_provider.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:hgmj/tools_base/banner/ads_grid_view.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:hgmj/tools_base/refresh/pull_refresh.dart';
|
||||
import 'package:wydj/hj_page/main_page/provider/bottom_bar_provider.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
import 'package:wydj/tools_base/banner/ads_grid_view.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_center_widget.dart';
|
||||
import 'package:wydj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import 'group_chat_logic.dart';
|
||||
import 'widget/chat_group_cell.dart';
|
||||
@@ -23,7 +23,8 @@ class GroupChatPage extends StatelessWidget {
|
||||
onRefresh: (ctr) => logic.refreshData(),
|
||||
onLoading: (ctr) => logic.loadMoreData(),
|
||||
child: CustomScrollView(
|
||||
controller: CommunityBottomProvider().scrollCtr(MediaStyle.GroupChat, 0),
|
||||
controller:
|
||||
CommunityBottomProvider().scrollCtr(MediaStyle.GroupChat, 0),
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: AdsGridView(
|
||||
@@ -45,7 +46,8 @@ class GroupChatPage extends StatelessWidget {
|
||||
)
|
||||
else
|
||||
SliverList.builder(
|
||||
itemBuilder: (ctx, index) => ChatGroupCell(logic.groupList![index]),
|
||||
itemBuilder: (ctx, index) =>
|
||||
ChatGroupCell(logic.groupList![index]),
|
||||
itemCount: logic.groupList!.length,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_alert_widget.dart';
|
||||
|
||||
import '../../../../alert/mine/vip_level_dialog.dart';
|
||||
import '../../../../assets_tool/app_colors.dart';
|
||||
@@ -13,7 +13,7 @@ import '../../../../tools_base/widget/header_widget.dart';
|
||||
import '../alert/group_buy_bottom_sheet.dart';
|
||||
import '../detail/soul_group_detail_page.dart';
|
||||
import '../model/im_group_list_model.dart';
|
||||
import 'package:hgmj/extension/extensions.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
|
||||
class ChatGroupCell extends StatefulWidget {
|
||||
final IMGroupItemModel model;
|
||||
@@ -45,7 +45,8 @@ class _ChatGroupCellState extends State<ChatGroupCell> {
|
||||
} else if (status == 1) {
|
||||
Get.to(GroupChatDetailPage(model));
|
||||
} else if (status == 2) {
|
||||
var ret = await Get.bottomSheet(GroupBuyBottomSheet(groupModel: widget.model));
|
||||
var ret = await Get.bottomSheet(
|
||||
GroupBuyBottomSheet(groupModel: widget.model));
|
||||
if (ret == true) {
|
||||
Get.to(GroupChatDetailPage(model));
|
||||
}
|
||||
@@ -69,7 +70,8 @@ class _ChatGroupCellState extends State<ChatGroupCell> {
|
||||
color: Colors.white.withValues(alpha: .05),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: InkWell(enableFeedback: false,
|
||||
child: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: _addGroupEvent,
|
||||
child: Row(
|
||||
children: [
|
||||
@@ -88,7 +90,10 @@ class _ChatGroupCellState extends State<ChatGroupCell> {
|
||||
children: [
|
||||
Text(
|
||||
model.name ?? '',
|
||||
style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
2.sizeBoxH,
|
||||
Text(
|
||||
@@ -116,7 +121,9 @@ class _ChatGroupCellState extends State<ChatGroupCell> {
|
||||
width: 52,
|
||||
height: 24,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(3), color: AppColors.actionRed),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
color: AppColors.actionRed),
|
||||
child: Text(
|
||||
'加入群聊',
|
||||
style: TextStyle(
|
||||
|
||||
+45
-21
@@ -3,16 +3,16 @@ import 'dart:ui';
|
||||
import 'package:easy_rich_text/easy_rich_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_page/video/video_player_alert.dart';
|
||||
import 'package:hgmj/hj_utils/pay/pay_manager.dart';
|
||||
import 'package:hgmj/hj_utils/buy_util.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/hj_utils/widget_util.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:hgmj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/video/video_player_alert.dart';
|
||||
import 'package:wydj/hj_utils/pay/pay_manager.dart';
|
||||
import 'package:wydj/hj_utils/buy_util.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/hj_utils/widget_util.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
|
||||
import '../../../../alert/video/vip_acg_dialog.dart';
|
||||
import '../../../../assets_tool/app_colors.dart';
|
||||
@@ -34,7 +34,8 @@ class _PostDetailVideoContentState extends State<PostDetailVideoContent> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isPlayable = model.isVideo() || model.isSeedPost();
|
||||
if (!isPlayable || model.sourceURL?.isNotEmpty != true) return const SizedBox.shrink();
|
||||
if (!isPlayable || model.sourceURL?.isNotEmpty != true)
|
||||
return const SizedBox.shrink();
|
||||
|
||||
final isLocked = needPostCoin(model);
|
||||
//非免费区的金币帖走金币解锁,其余走 VIP 解锁
|
||||
@@ -54,8 +55,12 @@ class _PostDetailVideoContentState extends State<PostDetailVideoContent> {
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
NetworkImageLoader(imageUrl: model.cover ?? '', width: double.infinity, height: double.infinity),
|
||||
Image.asset('circle_play.webp'.videoPath, width: 30, height: 30),
|
||||
NetworkImageLoader(
|
||||
imageUrl: model.cover ?? '',
|
||||
width: double.infinity,
|
||||
height: double.infinity),
|
||||
Image.asset('circle_play.webp'.videoPath,
|
||||
width: 30, height: 30),
|
||||
//未解锁蒙层
|
||||
if (isLocked)
|
||||
Positioned.fill(
|
||||
@@ -89,11 +94,17 @@ class _PostDetailVideoContentState extends State<PostDetailVideoContent> {
|
||||
'你只需花费 $coins 金币',
|
||||
defaultStyle: textStyle(16, Colors.white, FontWeight.w400),
|
||||
patternList: [
|
||||
EasyRichTextPattern(targetString: '$coins', style: textStyle(16, AppColors.actionRed, FontWeight.w400)),
|
||||
EasyRichTextPattern(
|
||||
targetString: '$coins',
|
||||
style: textStyle(16, AppColors.actionRed, FontWeight.w400)),
|
||||
],
|
||||
),
|
||||
16.sizeBoxH,
|
||||
const Text('即可解锁继续查看', style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w400)),
|
||||
const Text('即可解锁继续查看',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400)),
|
||||
16.sizeBoxH,
|
||||
_btn(
|
||||
'立即解锁',
|
||||
@@ -120,7 +131,11 @@ class _PostDetailVideoContentState extends State<PostDetailVideoContent> {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text('本视频需开通VIP免费观看', style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w400)),
|
||||
const Text('本视频需开通VIP免费观看',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400)),
|
||||
16.sizeBoxH,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -160,7 +175,9 @@ class _PostDetailVideoContentState extends State<PostDetailVideoContent> {
|
||||
width: width,
|
||||
height: 30,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(gradient: LinearGradient(colors: colors), borderRadius: BorderRadius.circular(15)),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(colors: colors),
|
||||
borderRadius: BorderRadius.circular(15)),
|
||||
child: Text(text, style: textStyle(12, textColor, FontWeight.w400)),
|
||||
),
|
||||
);
|
||||
@@ -192,7 +209,8 @@ class PostDetailCoverContent extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
//有视频源时封面已在视频区展示,这里剔除避免重复
|
||||
if (model.sourceURL?.isNotEmpty == true) model.seriesCover?.remove(model.cover);
|
||||
if (model.sourceURL?.isNotEmpty == true)
|
||||
model.seriesCover?.remove(model.cover);
|
||||
final covers = model.seriesCover ?? [];
|
||||
return Column(
|
||||
children: [
|
||||
@@ -206,7 +224,11 @@ class PostDetailCoverContent extends StatelessWidget {
|
||||
onTap: () => ImageBrowserPage.open(covers, index: index),
|
||||
child: ClipRRect(
|
||||
borderRadius: _radius(index, covers.length),
|
||||
child: NetworkImageLoader(imageUrl: url, width: double.infinity, fit: BoxFit.fill, borderRadius: 0),
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: url,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.fill,
|
||||
borderRadius: 0),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -219,8 +241,10 @@ class PostDetailCoverContent extends StatelessWidget {
|
||||
BorderRadius _radius(int index, int total) {
|
||||
const radius = Radius.circular(12);
|
||||
if (total == 1) return const BorderRadius.all(radius);
|
||||
if (index == 0) return const BorderRadius.only(topLeft: radius, topRight: radius);
|
||||
if (index == total - 1) return const BorderRadius.only(bottomLeft: radius, bottomRight: radius);
|
||||
if (index == 0)
|
||||
return const BorderRadius.only(topLeft: radius, topRight: radius);
|
||||
if (index == total - 1)
|
||||
return const BorderRadius.only(bottomLeft: radius, bottomRight: radius);
|
||||
return BorderRadius.zero;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-9
@@ -3,14 +3,14 @@ import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/common_service.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/api_service/common_service.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
|
||||
import '../../../../alert/video/share_media_dialog.dart';
|
||||
import '../../../mine/collec_history_buy/col_his_buy_sub_page.dart';
|
||||
import 'package:hgmj/extension/extensions.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
|
||||
/// 帖子详情操作栏:浏览量 / 点赞 / 评论 / 分享
|
||||
class PostDetailOperationView extends StatefulWidget {
|
||||
@@ -19,7 +19,8 @@ class PostDetailOperationView extends StatefulWidget {
|
||||
const PostDetailOperationView({super.key, required this.model});
|
||||
|
||||
@override
|
||||
State<PostDetailOperationView> createState() => _PostDetailOperationViewState();
|
||||
State<PostDetailOperationView> createState() =>
|
||||
_PostDetailOperationViewState();
|
||||
}
|
||||
|
||||
class _PostDetailOperationViewState extends State<PostDetailOperationView> {
|
||||
@@ -46,7 +47,9 @@ class _PostDetailOperationViewState extends State<PostDetailOperationView> {
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: _toggleLike,
|
||||
child: _iconLabel(
|
||||
icon: model.vidStatus?.hasLiked == true ? "like_red.png".commonImgPath : "like_empty_gray.png".communityPath,
|
||||
icon: model.vidStatus?.hasLiked == true
|
||||
? "like_red.png".commonImgPath
|
||||
: "like_empty_gray.png".communityPath,
|
||||
gap: 5.w,
|
||||
text: model.likeCount?.countOr("喜欢") ?? '',
|
||||
fontSize: 12.sp,
|
||||
@@ -103,8 +106,10 @@ class _PostDetailOperationViewState extends State<PostDetailOperationView> {
|
||||
final wasLiked = model.vidStatus?.hasLiked ?? false;
|
||||
final count = model.likeCount ?? 0;
|
||||
final res = wasLiked
|
||||
? await CommonService.cancelLike(model.id ?? '', LoadDataType.post.apiType)
|
||||
: await CommonService.sendLike(model.id ?? '', LoadDataType.post.apiType);
|
||||
? await CommonService.cancelLike(
|
||||
model.id ?? '', LoadDataType.post.apiType)
|
||||
: await CommonService.sendLike(
|
||||
model.id ?? '', LoadDataType.post.apiType);
|
||||
if (!res || !mounted) return;
|
||||
model.vidStatus?.hasLiked = !wasLiked;
|
||||
model.likeCount = max(0, count + (wasLiked ? -1 : 1));
|
||||
|
||||
+14
-7
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/pay/pay_manager.dart';
|
||||
import 'package:hgmj/tools_base/global_store/store.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/pay/pay_manager.dart';
|
||||
import 'package:wydj/tools_base/global_store/store.dart';
|
||||
|
||||
/// 帖子金币解锁弹窗:解锁成功回传 true,点空白关闭交给 barrier
|
||||
class PostDetailUnlockDialog extends StatelessWidget {
|
||||
@@ -32,7 +32,10 @@ class PostDetailUnlockDialog extends StatelessWidget {
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
gradient: LinearGradient(
|
||||
colors: [Color.fromRGBO(255, 238, 220, 1), Color.fromRGBO(249, 219, 191, 1)],
|
||||
colors: [
|
||||
Color.fromRGBO(255, 238, 220, 1),
|
||||
Color.fromRGBO(249, 219, 191, 1)
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
@@ -40,10 +43,14 @@ class PostDetailUnlockDialog extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset('post_detail_coin.png'.communityPath, width: 30, height: 30),
|
||||
Image.asset('post_detail_coin.png'.communityPath,
|
||||
width: 30, height: 30),
|
||||
Text(
|
||||
'${model.videoCoin()}金币解锁继续',
|
||||
style: const TextStyle(color: Color(0xff370000), fontSize: 14, fontWeight: FontWeight.w400),
|
||||
style: const TextStyle(
|
||||
color: Color(0xff370000),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
+20
-10
@@ -1,10 +1,10 @@
|
||||
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/screen.dart';
|
||||
import 'package:hgmj/routers/jump_router.dart';
|
||||
import 'package:hgmj/tools_base/widget/image_browser_page.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/routers/jump_router.dart';
|
||||
import 'package:wydj/tools_base/widget/image_browser_page.dart';
|
||||
|
||||
import '../../../../tools_base/richTextParsing/html_parser.dart';
|
||||
import '../../../../tools_base/widget/shrink_wrap.dart';
|
||||
@@ -24,7 +24,8 @@ class GameDetailWordContent extends StatelessWidget {
|
||||
children: [
|
||||
const Text('游戏介绍', style: TextStyle(color: Colors.white, fontSize: 16)),
|
||||
18.sizeBoxH,
|
||||
Text(model.content ?? '', style: const TextStyle(color: Colors.white, fontSize: 16)),
|
||||
Text(model.content ?? '',
|
||||
style: const TextStyle(color: Colors.white, fontSize: 16)),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -39,14 +40,17 @@ class PostDetailWordContent extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (model.newsType == 'ADULT_GAME') return const SizedBox.shrink();
|
||||
final contentStyle = TextStyle(color: const Color(0xFFDCDCDC), fontSize: 14.sp);
|
||||
final contentStyle =
|
||||
TextStyle(color: const Color(0xFFDCDCDC), fontSize: 14.sp);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
14.sizeBoxH,
|
||||
//标题
|
||||
if (model.title?.isNotEmpty == true)
|
||||
Padding(padding: EdgeInsets.only(bottom: 1.h), child: Text(model.title ?? '', style: contentStyle)),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 1.h),
|
||||
child: Text(model.title ?? '', style: contentStyle)),
|
||||
//标签
|
||||
_tags(),
|
||||
12.h.sizeBoxH,
|
||||
@@ -56,7 +60,9 @@ class PostDetailWordContent extends StatelessWidget {
|
||||
if (model.richText?.isNotEmpty == true)
|
||||
_richText()
|
||||
else if (model.content?.isNotEmpty == true)
|
||||
Padding(padding: EdgeInsets.only(bottom: 18.h), child: Text(model.content ?? '', style: contentStyle)),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 18.h),
|
||||
child: Text(model.content ?? '', style: contentStyle)),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -91,8 +97,12 @@ class PostDetailWordContent extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.fromLTRB(8, 3, 8, 3),
|
||||
margin: const EdgeInsets.only(right: 6),
|
||||
decoration: BoxDecoration(color: const Color(0x0DFFFFFF), borderRadius: BorderRadius.circular(3)),
|
||||
child: Text('#${e.name}', style: const TextStyle(color: Color(0x8CFFFFFF), fontSize: 12)),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x0DFFFFFF),
|
||||
borderRadius: BorderRadius.circular(3)),
|
||||
child: Text('#${e.name}',
|
||||
style: const TextStyle(
|
||||
color: Color(0x8CFFFFFF), fontSize: 12)),
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
|
||||
+28
-16
@@ -1,15 +1,15 @@
|
||||
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/assets_tool/images.dart';
|
||||
import 'package:hgmj/hj_utils/date_time_util.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:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/assets_tool/images.dart';
|
||||
import 'package:wydj/hj_utils/date_time_util.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 '../../../../hj_model/video_model.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'post_detail_unlock_dialog.dart';
|
||||
|
||||
/// 种子帖 / 黄游帖的资源信息与下载入口
|
||||
@@ -31,28 +31,36 @@ class _PostResourceInfoWidgetState extends State<PostResourceInfoWidget> {
|
||||
final me = globalStore.meInfo;
|
||||
//金币视频限免期内:全场免费 或 50 金币以内免费
|
||||
final isFreeTime = DateTimeUtil.calTime3(me?.goldVideoFreeExpire) > 0;
|
||||
if (isFreeTime && (me?.allGoldVideoFree == true || (model.coins ?? 0) < 50)) return false;
|
||||
return model.isCoinVideo() && !globalStore.isMe(model.publisher?.uid) && !(model.vidStatus?.hasPaid ?? false);
|
||||
if (isFreeTime && (me?.allGoldVideoFree == true || (model.coins ?? 0) < 50))
|
||||
return false;
|
||||
return model.isCoinVideo() &&
|
||||
!globalStore.isMe(model.publisher?.uid) &&
|
||||
!(model.vidStatus?.hasPaid ?? false);
|
||||
}
|
||||
|
||||
String get _buyDesc => _needLock ? '${model.realCoins ?? 0}金币解锁 即可下载种子' : '开通VIP 即可下载种子';
|
||||
String get _buyDesc =>
|
||||
_needLock ? '${model.realCoins ?? 0}金币解锁 即可下载种子' : '开通VIP 即可下载种子';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isSeed = model.newsType == 'SEED_LINK';
|
||||
if (!isSeed && model.newsType != 'ADULT_GAME') return const SizedBox();
|
||||
|
||||
const descStyle = TextStyle(color: Color(0xff999999), fontSize: 14, height: 1.5);
|
||||
const descStyle =
|
||||
TextStyle(color: Color(0xff999999), fontSize: 14, height: 1.5);
|
||||
//未解锁、或非 VIP 的非免费区内容,都只能看解锁入口
|
||||
final isLocked = _needLock || (!globalStore.isVIP && model.freeArea != true);
|
||||
final isLocked =
|
||||
_needLock || (!globalStore.isVIP && model.freeArea != true);
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
//种子帖的影片信息与下载说明
|
||||
if (isSeed) ...[
|
||||
if ((model.seedSize ?? 0) > 0) Text('[影片大小]:${model.seedSizeDesc}', style: descStyle),
|
||||
if ((model.seedPlayTime ?? 0) > 0) Text('[影片时长]:${model.seedPlayTimeDesc}', style: descStyle),
|
||||
if ((model.seedSize ?? 0) > 0)
|
||||
Text('[影片大小]:${model.seedSizeDesc}', style: descStyle),
|
||||
if ((model.seedPlayTime ?? 0) > 0)
|
||||
Text('[影片时长]:${model.seedPlayTimeDesc}', style: descStyle),
|
||||
const Text(
|
||||
'[下载说明]:解锁后请复制种子的下载链接到手机自带浏览器(谷歌/UC/夸克/火狐 等)打开!或使用BT软件(迅雷/Vuze/uTorrent/BitTorrent 等)进行下载.',
|
||||
style: descStyle,
|
||||
@@ -68,13 +76,17 @@ class _PostResourceInfoWidgetState extends State<PostResourceInfoWidget> {
|
||||
onTap: _showUnlock,
|
||||
child: Text(
|
||||
_buyDesc,
|
||||
style: const TextStyle(fontSize: 16, color: AppColors.primaryHighColor, fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: AppColors.primaryHighColor,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
)
|
||||
: InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: _copyLink,
|
||||
child: Image.asset('link_copy_icon.webp'.communityPath, width: 180, height: 32),
|
||||
child: Image.asset('link_copy_icon.webp'.communityPath,
|
||||
width: 180, height: 32),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_page/comment/comment_mixin.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/vid_service.dart';
|
||||
import 'package:hgmj/hj_utils/const.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/comment/comment_mixin.dart';
|
||||
import 'package:wydj/hj_utils/api_service/vid_service.dart';
|
||||
import 'package:wydj/hj_utils/const.dart';
|
||||
|
||||
import '../../../hj_utils/history_util.dart';
|
||||
import 'post_detail_page.dart';
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/extension/extensions.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_page/comment/cell/comment_item.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/banner/ads_grid_view.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/unique_tag_mixin.dart';
|
||||
import 'package:wydj/extension/extensions.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/comment/cell/comment_item.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/banner/ads_grid_view.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/unique_tag_mixin.dart';
|
||||
|
||||
import '../../comment/widget/comment_foot_view.dart';
|
||||
import '../../home/widget/quick_search_view.dart';
|
||||
@@ -21,18 +21,20 @@ import 'post_detail_logic.dart';
|
||||
|
||||
/// 过滤掉广告位,只留真实帖子
|
||||
List<VideoModel>? _filters(List<VideoModel>? videoModel) {
|
||||
return (videoModel ?? []).where((e) => !e.isRandomAd() && !e.isAdsArr()).toList();
|
||||
return (videoModel ?? [])
|
||||
.where((e) => !e.isRandomAd() && !e.isAdsArr())
|
||||
.toList();
|
||||
}
|
||||
|
||||
class PostDetailPageArgument {
|
||||
final List<VideoModel>? videoModels;
|
||||
String? id;
|
||||
|
||||
PostDetailPageArgument({List<VideoModel>? models, this.id}) : videoModels = _filters(models);
|
||||
PostDetailPageArgument({List<VideoModel>? models, this.id})
|
||||
: videoModels = _filters(models);
|
||||
}
|
||||
|
||||
class PostDetailPage extends StatefulWidget {
|
||||
|
||||
final PostDetailPageArgument argument;
|
||||
|
||||
const PostDetailPage({super.key, required this.argument});
|
||||
@@ -55,7 +57,10 @@ class _PostDetailPageState extends State<PostDetailPage> with UniqueTagMixin {
|
||||
final topIndex = logic.topPinnedCommentIndex;
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(titleSpacing: 18.w, automaticallyImplyLeading: false, title: _titleView(logic)),
|
||||
appBar: AppBar(
|
||||
titleSpacing: 18.w,
|
||||
automaticallyImplyLeading: false,
|
||||
title: _titleView(logic)),
|
||||
body: logic.isLoading || model == null
|
||||
? SizedBox(height: 300, child: LoadingCenterWidget())
|
||||
: Column(
|
||||
@@ -66,24 +71,35 @@ class _PostDetailPageState extends State<PostDetailPage> with UniqueTagMixin {
|
||||
child: pullYsRefresh(
|
||||
enablePullDown: false,
|
||||
onInit: (refreshCtr) => logic.refreshCtr = refreshCtr,
|
||||
onLoading: (_) => logic.fetchComments(logic.args.id ?? ''),
|
||||
onLoading: (_) =>
|
||||
logic.fetchComments(logic.args.id ?? ''),
|
||||
child: CustomScrollView(
|
||||
controller: logic.scrollCtr,
|
||||
slivers: [
|
||||
SliverToBoxAdapter(child: 14.h.sizeBoxH),
|
||||
//发帖人信息
|
||||
SliverToBoxAdapter(child: PostUserInfoView(model: model, isDetailStyle: true)),
|
||||
SliverToBoxAdapter(
|
||||
child: PostUserInfoView(
|
||||
model: model, isDetailStyle: true)),
|
||||
//正文
|
||||
SliverToBoxAdapter(child: PostDetailWordContent(model: model)),
|
||||
SliverToBoxAdapter(
|
||||
child: PostDetailWordContent(model: model)),
|
||||
//富文本帖自带图,不再单独铺封面
|
||||
if (model.richText?.isNotEmpty != true)
|
||||
SliverToBoxAdapter(child: PostDetailCoverContent(model: model)),
|
||||
SliverToBoxAdapter(child: GameDetailWordContent(model: model)),
|
||||
SliverToBoxAdapter(child: PostDetailVideoContent(model: model)),
|
||||
SliverToBoxAdapter(child: PostResourceInfoWidget(videoModel: model)),
|
||||
SliverToBoxAdapter(
|
||||
child:
|
||||
PostDetailCoverContent(model: model)),
|
||||
SliverToBoxAdapter(
|
||||
child: GameDetailWordContent(model: model)),
|
||||
SliverToBoxAdapter(
|
||||
child: PostDetailVideoContent(model: model)),
|
||||
SliverToBoxAdapter(
|
||||
child: PostResourceInfoWidget(
|
||||
videoModel: model)),
|
||||
SliverToBoxAdapter(child: 16.sizeBoxH),
|
||||
//点赞/收藏/分享
|
||||
SliverToBoxAdapter(child: PostDetailOperationView(model: model)),
|
||||
SliverToBoxAdapter(
|
||||
child: PostDetailOperationView(model: model)),
|
||||
SliverToBoxAdapter(
|
||||
child: AdsGridView(
|
||||
7,
|
||||
@@ -98,15 +114,23 @@ class _PostDetailPageState extends State<PostDetailPage> with UniqueTagMixin {
|
||||
Text(
|
||||
'${model.commentCount?.countStr}条评论',
|
||||
style: TextStyle(
|
||||
fontSize: 14, fontWeight: FontWeight.w400, color: Colors.white.withValues(alpha: 0.9)),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.white
|
||||
.withValues(alpha: 0.9)),
|
||||
),
|
||||
if (logic.quickSearchList.isNotEmpty) ...[18.sizeBoxH, QuickSearchView(logic.quickSearchList)]
|
||||
if (logic.quickSearchList.isNotEmpty) ...[
|
||||
18.sizeBoxH,
|
||||
QuickSearchView(logic.quickSearchList)
|
||||
]
|
||||
],
|
||||
).paddingOnly(bottom: 14),
|
||||
),
|
||||
//评论列表
|
||||
if (logic.comments.isEmpty)
|
||||
SliverToBoxAdapter(child: SizedBox(height: 220, child: CErrorWidget()))
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: 220, child: CErrorWidget()))
|
||||
else
|
||||
SliverList.builder(
|
||||
itemCount: logic.comments.length,
|
||||
@@ -114,8 +138,13 @@ class _PostDetailPageState extends State<PostDetailPage> with UniqueTagMixin {
|
||||
logic.comments[index],
|
||||
objId: model.id ?? '',
|
||||
//置顶那条上方插一组 Banner
|
||||
topBanners: index == topIndex && logic.commentTopBanners.isNotEmpty ? logic.commentTopBanners : null,
|
||||
replyHandler: (comment, {reply}) => logic.readyReplyComment(comment, replyModel: reply),
|
||||
topBanners: index == topIndex &&
|
||||
logic.commentTopBanners.isNotEmpty
|
||||
? logic.commentTopBanners
|
||||
: null,
|
||||
replyHandler: (comment, {reply}) =>
|
||||
logic.readyReplyComment(comment,
|
||||
replyModel: reply),
|
||||
),
|
||||
)
|
||||
],
|
||||
@@ -128,11 +157,13 @@ class _PostDetailPageState extends State<PostDetailPage> with UniqueTagMixin {
|
||||
() => CommentFootView(
|
||||
video: model,
|
||||
showCollect: true,
|
||||
onComment: (isSend) => logic.readyReplyComment(null, isSend: isSend),
|
||||
onComment: (isSend) =>
|
||||
logic.readyReplyComment(null, isSend: isSend),
|
||||
isSending: logic.isSendingMsg.value,
|
||||
textCtr: logic.commentController,
|
||||
imgPath: logic.selectedImagePath.value,
|
||||
onImgChange: (value) => logic.selectedImagePath.value = value,
|
||||
onImgChange: (value) =>
|
||||
logic.selectedImagePath.value = value,
|
||||
),
|
||||
)
|
||||
],
|
||||
@@ -168,7 +199,9 @@ class _PostDetailPageState extends State<PostDetailPage> with UniqueTagMixin {
|
||||
children: [
|
||||
_backBtn(),
|
||||
4.sizeBoxW,
|
||||
Expanded(child: PostUserInfoView(model: logic.model!, isDetailStyle: true, avatarSize: 30)),
|
||||
Expanded(
|
||||
child: PostUserInfoView(
|
||||
model: logic.model!, isDetailStyle: true, avatarSize: 30)),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/search_service.dart';
|
||||
import 'package:hgmj/tools_base/debug_log.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/api_service/search_service.dart';
|
||||
import 'package:wydj/tools_base/debug_log.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
import 'chose_tag_page.dart';
|
||||
|
||||
@@ -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_page/community/publish_page/chose_tag_logic.dart';
|
||||
import 'package:hgmj/hj_page/home/search_page/widget/topic_item.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_model/video_model.dart';
|
||||
import 'package:wydj/hj_page/community/publish_page/chose_tag_logic.dart';
|
||||
import 'package:wydj/hj_page/home/search_page/widget/topic_item.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';
|
||||
|
||||
enum ChoseTopicEntry {
|
||||
home('选择标签'),
|
||||
@@ -48,7 +48,8 @@ class ChoseTopicPage extends StatelessWidget {
|
||||
|
||||
Widget _buildBody(ChoseTopicLogic logic) {
|
||||
if (logic.isLoading) return LoadingCenterWidget();
|
||||
if (logic.dataSource.isEmpty) return CErrorWidget(retryOnTap: logic.loadTags);
|
||||
if (logic.dataSource.isEmpty)
|
||||
return CErrorWidget(retryOnTap: logic.loadTags);
|
||||
return _buildList(logic);
|
||||
}
|
||||
|
||||
@@ -60,7 +61,8 @@ class ChoseTopicPage extends StatelessWidget {
|
||||
itemCount: logic.dataSource.length,
|
||||
itemBuilder: (_, index) {
|
||||
final model = logic.dataSource[index];
|
||||
final selected = logic.selectTags.indexWhere((e) => e.id == model.id) != -1;
|
||||
final selected =
|
||||
logic.selectTags.indexWhere((e) => e.id == model.id) != -1;
|
||||
return TopicItem(
|
||||
model: model,
|
||||
isSelect: selected,
|
||||
|
||||
@@ -4,16 +4,16 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:image_pickers/image_pickers.dart';
|
||||
import 'package:hgmj/hj_model/video_model.dart';
|
||||
import 'package:hgmj/hj_utils/api_service/vid_service.dart';
|
||||
import 'package:hgmj/hj_utils/file_util.dart';
|
||||
import 'package:hgmj/hj_utils/media_info.dart';
|
||||
import 'package:hgmj/tools_base/file_upload/file_upload_tool.dart';
|
||||
import 'package:hgmj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:hgmj/tools_base/toast.dart';
|
||||
import 'package:wydj/hj_model/video_model.dart';
|
||||
import 'package:wydj/hj_utils/api_service/vid_service.dart';
|
||||
import 'package:wydj/hj_utils/file_util.dart';
|
||||
import 'package:wydj/hj_utils/media_info.dart';
|
||||
import 'package:wydj/tools_base/file_upload/file_upload_tool.dart';
|
||||
import 'package:wydj/tools_base/loading/loading_alert_widget.dart';
|
||||
import 'package:wydj/tools_base/toast.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:video_thumbnail/video_thumbnail.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_alert.dart';
|
||||
import 'package:wydj/tools_base/widget/common_alert.dart';
|
||||
|
||||
import 'publish_page.dart';
|
||||
|
||||
@@ -221,7 +221,8 @@ class PublishLogic extends GetxController {
|
||||
}
|
||||
|
||||
/// 提交发布([mediaInfo] 仅视频帖有)
|
||||
Future<void> _submitPost(List<String> seriesCover, MediaInfo? mediaInfo) async {
|
||||
Future<void> _submitPost(
|
||||
List<String> seriesCover, MediaInfo? mediaInfo) async {
|
||||
final result = await VidService.submit(
|
||||
title: titleController.text,
|
||||
newsType: _generateNewsType(),
|
||||
@@ -373,7 +374,9 @@ class PublishLogic extends GetxController {
|
||||
}
|
||||
|
||||
String _generateNewsType() {
|
||||
if (type == PublishType.homeImg || type == PublishType.homeImgText || type == PublishType.squireImgText) return 'COVER';
|
||||
if (type == PublishType.homeImg ||
|
||||
type == PublishType.homeImgText ||
|
||||
type == PublishType.squireImgText) return 'COVER';
|
||||
final duration = video.value.playTime ?? 0;
|
||||
if (duration <= 300) return 'SP';
|
||||
return 'SP';
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgmj/assets_tool/app_colors.dart';
|
||||
import 'package:hgmj/hj_page/community/publish_page/chose_tag_page.dart';
|
||||
import 'package:hgmj/hj_page/community/publish_page/publish_logic.dart';
|
||||
import 'package:hgmj/hj_page/community/publish_page/publish_rule_page.dart';
|
||||
import 'package:hgmj/hj_page/community/publish_page/widget/publish_widget.dart';
|
||||
import 'package:hgmj/hj_utils/screen.dart';
|
||||
import 'package:hgmj/tools_base/widget/common_alert.dart';
|
||||
import 'package:wydj/assets_tool/app_colors.dart';
|
||||
import 'package:wydj/hj_page/community/publish_page/chose_tag_page.dart';
|
||||
import 'package:wydj/hj_page/community/publish_page/publish_logic.dart';
|
||||
import 'package:wydj/hj_page/community/publish_page/publish_rule_page.dart';
|
||||
import 'package:wydj/hj_page/community/publish_page/widget/publish_widget.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/common_alert.dart';
|
||||
|
||||
enum PublishType {
|
||||
homeImg(RuleType.home, ChoseTopicEntry.home, '发布图片'),
|
||||
@@ -69,7 +69,6 @@ extension PublishMore on PublishType {
|
||||
}
|
||||
|
||||
class PublishPage extends StatelessWidget {
|
||||
|
||||
final PublishType type;
|
||||
|
||||
const PublishPage({super.key, this.type = PublishType.homeImgText});
|
||||
@@ -94,7 +93,8 @@ class PublishPage extends StatelessWidget {
|
||||
showCancel: false,
|
||||
confirmText: '我知道了',
|
||||
),
|
||||
child: const Text('规则', style: TextStyle(color: Color(0x8CFFFFFF))),
|
||||
child:
|
||||
const Text('规则', style: TextStyle(color: Color(0x8CFFFFFF))),
|
||||
),
|
||||
18.w.sizeBoxW,
|
||||
],
|
||||
@@ -132,7 +132,11 @@ class PublishPage extends StatelessWidget {
|
||||
),
|
||||
child: const Text(
|
||||
'确定发布',
|
||||
style: TextStyle(color: Colors.black, fontSize: 16, height: 27 / 14, fontWeight: FontWeight.w500),
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
height: 27 / 14,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,12 +4,12 @@ import 'package:easy_rich_text/easy_rich_text.dart';
|
||||
import 'package:flutter/material.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/hj_model/video_model.dart';
|
||||
import 'package:hgmj/tools_base/widget/add_media_source_button.dart';
|
||||
import 'package:hgmj/hj_utils/screen.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_model/video_model.dart';
|
||||
import 'package:wydj/tools_base/widget/add_media_source_button.dart';
|
||||
import 'package:wydj/hj_utils/screen.dart';
|
||||
import 'package:wydj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../../home/widget/support_up_alert.dart';
|
||||
import '../chose_tag_page.dart';
|
||||
@@ -40,9 +40,14 @@ class ChoseVideoWidget extends StatelessWidget {
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text('添加视频', style: TextStyle(color: Colors.white, fontSize: 16.sp, fontWeight: FontWeight.w500)),
|
||||
Text('添加视频',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w500)),
|
||||
10.sizeBoxW,
|
||||
Text('最大300M以内', style: TextStyle(color: Color(0xff666666), fontSize: 12.sp)),
|
||||
Text('最大300M以内',
|
||||
style: TextStyle(color: Color(0xff666666), fontSize: 12.sp)),
|
||||
],
|
||||
),
|
||||
14.h.sizeBoxH,
|
||||
@@ -51,7 +56,11 @@ class ChoseVideoWidget extends StatelessWidget {
|
||||
return Row(children: [
|
||||
6.h.sizeBoxW,
|
||||
if (controller.video.value.localPath == null)
|
||||
AddMediaSourceButton(width: cellW, height: cellW, onTap: controller.choseVideo, isVideo: true)
|
||||
AddMediaSourceButton(
|
||||
width: cellW,
|
||||
height: cellW,
|
||||
onTap: controller.choseVideo,
|
||||
isVideo: true)
|
||||
else
|
||||
_cover(cellW),
|
||||
]);
|
||||
@@ -67,7 +76,8 @@ class ChoseVideoWidget extends StatelessWidget {
|
||||
constraints: const BoxConstraints(maxWidth: 230, maxHeight: 219),
|
||||
child: Stack(
|
||||
children: [
|
||||
VideoCoverWidget(controller.video.value.localCover ?? '', width: size, height: size, isLocal: true),
|
||||
VideoCoverWidget(controller.video.value.localCover ?? '',
|
||||
width: size, height: size, isLocal: true),
|
||||
Positioned(
|
||||
right: 6,
|
||||
top: 6,
|
||||
@@ -75,8 +85,11 @@ class ChoseVideoWidget extends StatelessWidget {
|
||||
onTap: () => controller.deleteSelectVideo(),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(color: Colors.white.withValues(alpha: .8), borderRadius: BorderRadius.circular(10)),
|
||||
child: const Icon(Icons.close, size: 12, color: Color(0xff333333)),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: .8),
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
child:
|
||||
const Icon(Icons.close, size: 12, color: Color(0xff333333)),
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -97,7 +110,8 @@ class TopicWidget extends StatelessWidget {
|
||||
return Obx(
|
||||
() => GestureDetector(
|
||||
onTap: () async {
|
||||
final model = await Get.to(ChoseTopicPage(entry: controller.type.tag, selectTags: controller.topics));
|
||||
final model = await Get.to(ChoseTopicPage(
|
||||
entry: controller.type.tag, selectTags: controller.topics));
|
||||
if (model is TagsBean) {
|
||||
controller.topics
|
||||
..clear()
|
||||
@@ -120,9 +134,17 @@ class TopicWidget extends StatelessWidget {
|
||||
Widget _emptyTip() {
|
||||
return Row(
|
||||
children: [
|
||||
Text("#", style: TextStyle(color: Color(0xff989898), fontSize: 24.sp, fontWeight: FontWeight.bold)),
|
||||
Text("#",
|
||||
style: TextStyle(
|
||||
color: Color(0xff989898),
|
||||
fontSize: 24.sp,
|
||||
fontWeight: FontWeight.bold)),
|
||||
10.sizeBoxW,
|
||||
Text('选择标签', style: TextStyle(color: Color(0xff989898), fontSize: 12.sp, fontWeight: FontWeight.w500)),
|
||||
Text('选择标签',
|
||||
style: TextStyle(
|
||||
color: Color(0xff989898),
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w500)),
|
||||
const Spacer(),
|
||||
Icon(Icons.arrow_forward_ios, size: 16.sp, color: Color(0xffDCDCDC)),
|
||||
],
|
||||
@@ -135,12 +157,20 @@ class TopicWidget extends StatelessWidget {
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
child: NetworkImageLoader(imageUrl: controller.topics.first.coverImg ?? '', width: 38, height: 38),
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: controller.topics.first.coverImg ?? '',
|
||||
width: 38,
|
||||
height: 38),
|
||||
),
|
||||
5.sizeBoxW,
|
||||
Text(
|
||||
controller.topics.firstOrNull?.name != null ? '#${controller.topics.firstOrNull?.name}' : '',
|
||||
style: TextStyle(color: Colors.white, fontSize: 16.sp, fontWeight: FontWeight.w500),
|
||||
controller.topics.firstOrNull?.name != null
|
||||
? '#${controller.topics.firstOrNull?.name}'
|
||||
: '',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
Spacer(),
|
||||
Icon(Icons.arrow_forward_ios, size: 16.sp, color: Color(0xffDCDCDC)),
|
||||
@@ -176,7 +206,8 @@ class InputTitleWidget extends StatelessWidget {
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: '请填写标题',
|
||||
hintStyle: TextStyle(color: Color(0xff525252), fontSize: 12.sp, height: 22 / 15),
|
||||
hintStyle: TextStyle(
|
||||
color: Color(0xff525252), fontSize: 12.sp, height: 22 / 15),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
isDense: true,
|
||||
),
|
||||
@@ -246,7 +277,13 @@ class ChoseImageWidget extends StatelessWidget {
|
||||
final Color? highlightTextColor;
|
||||
final double? highlightTextSize;
|
||||
|
||||
ChoseImageWidget({super.key, this.title, this.hint, this.highlightText, this.highlightTextColor, this.highlightTextSize});
|
||||
ChoseImageWidget(
|
||||
{super.key,
|
||||
this.title,
|
||||
this.hint,
|
||||
this.highlightText,
|
||||
this.highlightTextColor,
|
||||
this.highlightTextSize});
|
||||
|
||||
final controller = Get.find<PublishLogic>();
|
||||
|
||||
@@ -259,15 +296,22 @@ class ChoseImageWidget extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 10,
|
||||
children: [
|
||||
Text(title ?? '添加图片', style: TextStyle(color: Colors.white, fontSize: 16.sp, fontWeight: FontWeight.w500)),
|
||||
Text(title ?? '添加图片',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w500)),
|
||||
EasyRichText(
|
||||
hint ?? '添加图集 图片数量最多上传9张哦~',
|
||||
defaultStyle: TextStyle(color: Color(0xff666666), fontSize: 12.sp),
|
||||
defaultStyle:
|
||||
TextStyle(color: Color(0xff666666), fontSize: 12.sp),
|
||||
patternList: [
|
||||
EasyRichTextPattern(
|
||||
targetString: highlightText ?? '',
|
||||
style: TextStyle(
|
||||
color: highlightTextColor ?? Colors.white, fontSize: highlightTextSize ?? 16.sp, fontWeight: FontWeight.w500),
|
||||
color: highlightTextColor ?? Colors.white,
|
||||
fontSize: highlightTextSize ?? 16.sp,
|
||||
fontWeight: FontWeight.w500),
|
||||
)
|
||||
],
|
||||
),
|
||||
@@ -310,7 +354,8 @@ class ChoseImageWidget extends StatelessWidget {
|
||||
height: size,
|
||||
child: Stack(
|
||||
children: [
|
||||
Image.file(File(path), width: size, height: size, fit: BoxFit.cover),
|
||||
Image.file(File(path),
|
||||
width: size, height: size, fit: BoxFit.cover),
|
||||
Positioned(
|
||||
right: 6,
|
||||
top: 6,
|
||||
@@ -319,7 +364,9 @@ class ChoseImageWidget extends StatelessWidget {
|
||||
child: Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(color: Colors.white.withValues(alpha: .8), borderRadius: BorderRadius.circular(10)),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: .8),
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
alignment: Alignment.center,
|
||||
child: const Icon(Icons.close, size: 14),
|
||||
),
|
||||
@@ -344,7 +391,9 @@ class SettingGoldWidget extends StatelessWidget {
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
final res = await Get.bottomSheet(
|
||||
SupportUPAlert(isPublish: true, selectCoin: int.tryParse(controller.gold.value ?? '')),
|
||||
SupportUPAlert(
|
||||
isPublish: true,
|
||||
selectCoin: int.tryParse(controller.gold.value ?? '')),
|
||||
);
|
||||
controller.gold.value = res?.toString();
|
||||
},
|
||||
@@ -354,22 +403,32 @@ class SettingGoldWidget extends StatelessWidget {
|
||||
decoration: publishDecoration,
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset('community_coin.webp'.communityPath, width: 20, height: 20),
|
||||
Image.asset('community_coin.webp'.communityPath,
|
||||
width: 20, height: 20),
|
||||
10.sizeBoxW,
|
||||
const Text('设置价格', style: TextStyle(color: Color(0xFF989898), fontSize: 12, fontWeight: FontWeight.w600)),
|
||||
const Text('设置价格',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF989898),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600)),
|
||||
const Spacer(),
|
||||
Obx(
|
||||
() => Text(
|
||||
controller.gold.value == null ? '免费' : '${controller.gold.value} 金币',
|
||||
controller.gold.value == null
|
||||
? '免费'
|
||||
: '${controller.gold.value} 金币',
|
||||
style: TextStyle(
|
||||
color: controller.gold.value == null ? Color(0xFF989898) : AppColors.actionRed,
|
||||
color: controller.gold.value == null
|
||||
? Color(0xFF989898)
|
||||
: AppColors.actionRed,
|
||||
// color: Color(0xffF68216),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
5.sizeBoxW,
|
||||
const Icon(Icons.arrow_forward_ios, color: Color(0xffDCDCDC), size: 12)
|
||||
const Icon(Icons.arrow_forward_ios,
|
||||
color: Color(0xffDCDCDC), size: 12)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user