Files
2026-09-15 15:44:13 +07:00

155 lines
5.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hgdj/hj_utils/screen.dart';
import 'package:hgdj/tools_base/widget/net_image_widget.dart';
import 'package:hgdj/tools_base/widget/sheet_handle_bar.dart';
import '../../hj_page/mine/mine_vip/pay_order_source.dart';
import '../../hj_page/mine/mine_vip/vip_support_model.dart';
import '../../hj_page/mine/widgets/gradient_text.dart';
import 'guide_common.dart';
import 'guide_config.dart';
import 'guide_manager.dart';
/// 吸底型付费引导弹窗(通用壳):横条 + 标题 + [badge] + 主图 + 副文案 + 开通按钮,
/// 首页/播放页各自传 title/subtitle/buttonText 组装
class GuideBottomSheet extends StatelessWidget {
final VipProductModel card;
final Widget title; // 各场景自定义
final Widget? badge; // 标题下方的小标签(免费次数场景用),不传不占位
final Widget subtitle; // 主图下方文案
final String buttonText;
final PaySourcePage sourcePage;
final String cover; // 场景下发的主图,相对路径由 ImageCacheManager 拼域名
const GuideBottomSheet({
super.key,
required this.card,
required this.title,
this.badge,
required this.subtitle,
required this.buttonText,
required this.sourcePage,
required this.cover,
});
/// [scene] 决定主图/卡/下单来源,调用方须先用开关判过能弹
/// 返回 true = 点了开通并已跳会员页(调用方据此别恢复播放)
static Future<bool> show({
required GuideScene scene,
required Widget title,
required Widget subtitle,
Widget? badge,
String? buttonText,
}) async {
final card = await loadGuideCard(scene);
if (card == null) return false; // 配置有误不弹
final goVip = await Get.bottomSheet<bool>(
GuideBottomSheet(
card: card,
title: title,
badge: badge,
subtitle: subtitle,
buttonText: buttonText ?? '立即开通 · 仅需¥${card.discountedPriceUI}',
sourcePage: guideSourcePage(scene),
cover: GuideManager().configOf(scene)?.cover ?? '', //已校验非空
),
isScrollControlled: true,
backgroundColor: Colors.transparent,
);
return goVip ?? false;
}
/// 播放页引导(长短视频共用文案):文案优先用下发的,没配走默认。
/// [buttonText] 短视频传无价文案,长视频走默认带价文案
static Future<bool> showVideo({String? buttonText}) {
final config = GuideManager().configOf(GuideScene.videoPreviewEnd);
return show(
scene: GuideScene.videoPreviewEnd,
title: Text(
config?.title?.isNotEmpty == true
? config!.title!
: '该视频为VIP内容\n只能观看试看内容哦~',
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white, fontSize: 17, fontWeight: FontWeight.w600),
),
subtitle: GradientText(
config?.description?.isNotEmpty == true
? config!.description!
: '想要查看完整内容,需要开通会员',
gradient:
const LinearGradient(colors: [Colors.white, Color(0xffEFD394)]),
style: const TextStyle(
color: Colors.white, fontSize: 15, fontWeight: FontWeight.w500),
),
buttonText: buttonText,
);
}
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: Container(
width: double.infinity,
padding: EdgeInsets.fromLTRB(16, 18, 16, 18 + screen.paddingBottom),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xff0F0F0F), Colors.black]),
border: Border(
top: BorderSide(
color: Color(0x4DE4BB6D))), // rgba(228,187,109,0.3)
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SheetHandleBar(),
18.sizeBoxH,
title,
if (badge != null) ...[18.sizeBoxH, badge!],
18.sizeBoxH,
// 主图(场景下发)
SizedBox(
width: 270,
height: 122,
child: NetworkImageLoader(
imageUrl: cover, fit: BoxFit.fill, borderRadius: 8),
),
18.sizeBoxH,
subtitle,
18.sizeBoxH,
// 开通按钮
GestureDetector(
onTap: () => goVipDetail(card, sourcePage: sourcePage),
child: Container(
width: double.infinity,
height: 52,
alignment: Alignment.center,
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xffFFB03F), Color(0xffF2680C)]),
borderRadius: BorderRadius.circular(26),
boxShadow: [
BoxShadow(
color: const Color(0x73F2680C),
blurRadius: 18,
offset: const Offset(0, 6))
], // rgba(242,104,12,0.45)
),
child: Text(buttonText,
style: const TextStyle(
color: Colors.white,
fontSize: 17,
fontWeight: FontWeight.w700)),
),
),
],
),
),
);
}
}