角标和占位图替换

This commit is contained in:
谢宇宁
2026-09-21 23:21:09 +07:00
parent 4d7e30da95
commit f6a91760f3
10 changed files with 5 additions and 86 deletions
-1
View File
@@ -238,7 +238,6 @@ class _DramaListPageState extends State<DramaListPage> with UniqueTagMixin {
videoModel: model,
textLines: 1,
coverRightText: model.dramaInfo?.episodeNumberStatus,
showLevelIcon: false,
onTap: () => _openDrama(model),
onTagTap: (tag) => DramaListPage.toTag(tag),
);
@@ -1,44 +0,0 @@
import 'package:flutter/material.dart';
import '../../../config/config.dart';
import '../../../hj_model/video_model.dart';
import '../../../hj_utils/free_play_manager.dart';
/// 封面右上角的售卖角标:免费试看 / 金币 / VIP,三者互斥,都不满足就不占位。
/// 展不展示还受 ping 下发的 freeMark / coinMark / vipMark 三个开关控制
class LevelMarkChip extends StatelessWidget {
final VideoModel? videoModel;
const LevelMarkChip(this.videoModel, {super.key});
@override
Widget build(BuildContext context) {
if (videoModel?.freeArea == true) return const SizedBox();
// 免费试看:ping 免费类角标总开关 freeMark + 实时试看权益(次数用尽即不再展示)
if (Config.freeMark && FreePlayManager().canShowFreeTrialBadge(videoModel)) {
return _chip("免费试看", const Color(0xff141414), const [Color(0xff35DEBC), Color(0xff22BB9C)]);
}
final isCoin = videoModel?.isCoinVideo() == true;
if (isCoin && Config.coinMark) {
return _chip("金币", const Color(0xff8B3E00), const [Color(0xffFFE580), Color(0xffFACC15)]);
}
if (!isCoin && Config.vipMark) {
return _chip("VIP", const Color(0xff141414), const [Color(0xffF8F3AE), Color(0xffDDAC44)]);
}
return const SizedBox();
}
Widget _chip(String text, Color textColor, List<Color> gradientColors) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 6),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
gradient: LinearGradient(colors: gradientColors),
),
child: Text(
text,
style: TextStyle(color: textColor, fontSize: 10, height: 1.6),
),
);
}
}
@@ -3,10 +3,8 @@ import 'package:tgdj/hj_utils/api_service/common_service.dart';
import 'package:tgdj/hj_utils/screen.dart';
import '../../../hj_model/video_model.dart';
import '../../../hj_utils/free_play_manager.dart';
import '../../../routers/jump_router.dart';
import '../../../tools_base/widget/net_image_widget.dart';
import 'level_mark_chip.dart';
import 'package:tgdj/extension/extensions.dart';
/// 横版视频 item:左封面(带售卖角标) + 右标题/收藏数,用在专题的小列表样式
@@ -30,15 +28,6 @@ class VideoHorCell extends StatelessWidget {
borderRadius: 4,
imageUrl: videoModel?.cover ?? "",
),
Positioned(
right: 6,
top: 6,
// 监听免费次数变化:会话内试看用尽时角标实时刷新,不再残留「免费试看」
child: ValueListenableBuilder<int>(
valueListenable: FreePlayManager().revision,
builder: (_, __, ___) => LevelMarkChip(videoModel),
),
),
],
),
12.sizeBoxW,
@@ -11,10 +11,8 @@ import 'package:tgdj/tools_base/global_store/store.dart';
import '../../../hj_model/splash/ads_model.dart';
import '../../../hj_model/video_model.dart';
import '../../../hj_utils/free_play_manager.dart';
import '../../../tools_base/banner/ads_banner_widget.dart';
import '../../../tools_base/widget/net_image_widget.dart';
import 'level_mark_chip.dart';
/// 竖版视频 item:封面(角标/售卖标/暗网遮罩) + 标题 +(可选)标签/评论数。
/// 命中广告数据时整体换成 [VideoSimpleAdsCell]
@@ -29,7 +27,6 @@ class VideoSimpleCell extends StatelessWidget {
final double titleFontSize; // 标题字号,小卡场景传小值
final double coverFontSize; // 封面底部播放量/时长字号,小卡场景传小值避免溢出
final String? coverRightText; // 封面右下角文案,默认时长;短剧传「共N集」
final bool showLevelIcon; // 封面右上角「金币/VIP/免费试看」角标;短剧按集卖,整部剧标一个对不上,传 false
final ValueChanged<TagsBean>? onTagTap; // 左下角标签点击;短剧跳标签详情
const VideoSimpleCell({
@@ -44,7 +41,6 @@ class VideoSimpleCell extends StatelessWidget {
this.titleFontSize = 12,
this.coverFontSize = 10,
this.coverRightText,
this.showLevelIcon = true,
this.onTagTap,
});
@@ -134,16 +130,6 @@ class VideoSimpleCell extends StatelessWidget {
child: isFromHY ? _buildCoverHYBottom() : _buildCoverNormalBottom(),
),
),
if (showLevelIcon)
Positioned(
right: 6,
top: 6,
// 监听免费次数变化:会话内试看用尽时角标实时刷新,不再残留「免费试看」
child: ValueListenableBuilder<int>(
valueListenable: FreePlayManager().revision,
builder: (_, __, ___) => LevelMarkChip(videoModel),
),
),
if (_needVipUnlock)
Container(
color: Colors.black.withValues(alpha: 0.1),
@@ -211,7 +211,6 @@ class _SearchVideoResultPageState extends State<SearchVideoResultPage> {
videoModel: model,
textLines: 1,
coverRightText: model.dramaInfo?.episodeNumberStatus,
showLevelIcon: false,
isFromSearch: true,
onTap: () => _openDrama(model),
),
@@ -299,7 +298,6 @@ class _SearchVideoResultPageState extends State<SearchVideoResultPage> {
videoModel: videoModel,
textLines: 1,
coverRightText: videoModel.dramaInfo?.episodeNumberStatus,
showLevelIcon: false,
isFromSearch: true,
onTap: () => _openDrama(videoModel),
),
@@ -64,7 +64,11 @@ class _CommonSearchBarViewState extends State<CommonSearchBarView> {
borderRadius: BorderRadius.circular(99),
),
child: Config.searchHints.isEmpty
? Text('请输入关键字', style: _hintStyle)
//父级给的是 36 的紧约束,Text 会撑满高度后从顶部起排,要 Align 压回垂直居中
? Align(
alignment: Alignment.centerLeft,
child: Text('请输入关键字', style: _hintStyle),
)
: MarqueeWidget(
count: Config.searchHints.length,
onIndexChanged: (index) =>
@@ -82,7 +82,6 @@ abstract class ColHisBuySubLogic extends ListBaseLogic {
videoModel: model,
textLines: 1,
coverRightText: (model as VideoModel).dramaInfo?.episodeNumberStatus,
showLevelIcon: false,
onTap: () => _openDrama(model),
),
};
@@ -149,7 +149,6 @@ class _VideoCacheCellState extends State<VideoCacheCell> {
//短剧和「热门短剧」橱窗一个样式:标题是剧名,封面右下角标本条是第几集;
//按集卖,整部剧标一个金币/VIP 角标对不上,跟橱窗一样关掉
coverRightText: isDrama ? '第${model.episodeNo ?? 1}集' : null,
showLevelIcon: !isDrama,
);
}