258 lines
8.9 KiB
Dart
258 lines
8.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:jydj/assets_tool/app_colors.dart';
|
|
import 'package:jydj/assets_tool/images.dart';
|
|
import 'package:jydj/hj_page/home/provider/home_update_marker_provider.dart';
|
|
import 'package:jydj/hj_utils/const.dart';
|
|
import 'package:jydj/hj_utils/holiday_theme.dart';
|
|
import 'package:jydj/hj_utils/screen.dart';
|
|
import 'package:jydj/tools_base/indicator/custom_tab_indicator.dart';
|
|
import 'package:jydj/tools_base/loading/loading_center_widget.dart';
|
|
import 'package:jydj/tools_base/widget/keep_alive_widget.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import '../cartoon/cartoon_sub_detail_page.dart';
|
|
import '../main_page/provider/bottom_bar_provider.dart';
|
|
import 'activity_float/home_float_widget.dart';
|
|
import 'home_drawer.dart';
|
|
import 'home_main_logic.dart';
|
|
import 'home_sub_module/home_tab_drama_page.dart';
|
|
import 'home_sub_module/home_tab_section_page.dart';
|
|
import 'home_sub_module/home_tab_sort_page.dart';
|
|
import 'search_page/widget/common_search_widget.dart';
|
|
|
|
class HomeMainPage extends StatelessWidget {
|
|
const HomeMainPage({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Material(
|
|
color: const Color(0xff050f17),
|
|
child: GetBuilder<HomeMainLogic>(
|
|
init: HomeMainLogic(),
|
|
tag: "HomeMainLogic",
|
|
builder: (logic) {
|
|
final isHoliday = holidayTheme.openHoliday;
|
|
return Stack(
|
|
fit: StackFit.expand,
|
|
children: [
|
|
//节日皮肤:铺底色 + 顶部通栏背景图
|
|
if (isHoliday) ...[
|
|
Container(color: AppColors.primaryColor),
|
|
Positioned(
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
child: Image.asset(HolidayTheme.theme.mainBg, fit: BoxFit.fitWidth),
|
|
),
|
|
],
|
|
Scaffold(
|
|
key: logic.scaffoldKey,
|
|
backgroundColor: isHoliday ? Colors.transparent : null,
|
|
endDrawer: HSHomeDrawer(homeLogic: logic),
|
|
//浮窗放 body 里,endDrawer 才能盖住,避免挡住抽屉里的模块点击
|
|
body: Stack(
|
|
fit: StackFit.expand,
|
|
children: [
|
|
_body(logic, isHoliday),
|
|
const Positioned(right: 12, bottom: 40, child: HomeFloatWidget()),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _body(HomeMainLogic logic, bool isHoliday) {
|
|
if (logic.isLoading) return const LoadingCenterWidget();
|
|
return Column(
|
|
children: [
|
|
//顶部搜索栏(状态栏 + 导航栏高度)
|
|
Container(
|
|
color: isHoliday ? Colors.transparent : Colors.black,
|
|
padding: EdgeInsets.only(top: screen.paddingTop),
|
|
height: kToolbarHeight + screen.paddingTop,
|
|
child: CommonSearchBarView(logic: logic),
|
|
),
|
|
//排序变化时 tabViewKey 变,整个 TabView 连 TabController 一起重建
|
|
Expanded(child: HomeTabView(key: ValueKey(logic.tabViewKey), logic: logic)),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class HomeTabView extends StatefulWidget {
|
|
final HomeMainLogic logic;
|
|
final bool isDarkStyle;
|
|
|
|
const HomeTabView({
|
|
super.key,
|
|
required this.logic,
|
|
this.isDarkStyle = false,
|
|
});
|
|
|
|
@override
|
|
State<HomeTabView> createState() => _HomeTabViewState();
|
|
}
|
|
|
|
class _HomeTabViewState extends State<HomeTabView> with SingleTickerProviderStateMixin {
|
|
HomeMainLogic get logic => widget.logic;
|
|
|
|
bool get isDarkStyle => widget.isDarkStyle;
|
|
|
|
late final TabController tabCtr;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
final count = logic.tabs.length;
|
|
tabCtr = TabController(
|
|
// 防止 tab 数量不足时 initialIndex 越界导致断言崩溃
|
|
initialIndex: count > 0 ? logic.selectedTabIndex.clamp(0, count - 1) : 0,
|
|
length: count,
|
|
vsync: this,
|
|
);
|
|
tabCtr.addListener(_onTabChange);
|
|
logic.tabCtr = tabCtr;
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
// controller 在本 State vsync 创建,归本 State 释放(排序换 key 会重建 State)
|
|
tabCtr.removeListener(_onTabChange);
|
|
tabCtr.dispose();
|
|
// 换 key 重建时新 State 可能已把自己的 ctr 写进 logic,只清掉自己那一份
|
|
if (identical(logic.tabCtr, tabCtr)) logic.tabCtr = null;
|
|
super.dispose();
|
|
}
|
|
|
|
void _onTabChange() {
|
|
if (tabCtr.indexIsChanging) return;
|
|
if (isDarkStyle) {
|
|
DarkwebBottomProvider().setScrollController(tabCtr.index);
|
|
return;
|
|
}
|
|
HomeBottomProvider().setScrollController(tabCtr.index);
|
|
final tabs = logic.tabs;
|
|
if (tabCtr.index < tabs.length && tabs[tabCtr.index].id == '-110') {
|
|
// 进入「最新」:清 Tab 红点;默认排序即「今日最新」,一并视为已查看
|
|
HomeUpdateMarkerProvider().markHomeLatestViewed();
|
|
HomeUpdateMarkerProvider().markTodayLatestViewed();
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final isHoliday = holidayTheme.openHoliday;
|
|
return Column(
|
|
children: [
|
|
Container(
|
|
height: 48.h,
|
|
color: isHoliday ? Colors.transparent : Colors.black,
|
|
child: _tabBar(),
|
|
),
|
|
Expanded(
|
|
child: Stack(
|
|
fit: StackFit.expand,
|
|
children: [
|
|
if (isDarkStyle) Image.asset("aw_bg.webp".homePath),
|
|
TabBarView(
|
|
controller: tabCtr,
|
|
children: List.generate(logic.tabs.length, (index) {
|
|
final module = logic.tabs[index];
|
|
if (module.type == 1 || module.type == 3) {
|
|
//1首页(原首页视频) 3暗网
|
|
//showType==2 走分区聚合页,其余走排序列表页
|
|
if (module.showType == 2) {
|
|
return HomeTabSectionPage(index, module, isDarkStyle: isDarkStyle).keepAlive;
|
|
} else {
|
|
return HomeTabSortPage(index, module, isDarkStyle: isDarkStyle).keepAlive;
|
|
}
|
|
} else if (module.isACG) {
|
|
/// 动漫/漫画/小说
|
|
return CartoonSubDetailPage(tagData: module, type: MediaStyle.Cartoon, index: index).keepAlive;
|
|
} else if (module.isDrama) {
|
|
/// 短剧
|
|
return HomeTabDramaPage(index, module, isDarkStyle: isDarkStyle).keepAlive;
|
|
} else {
|
|
//兜底
|
|
return HomeTabSortPage(index, module, isDarkStyle: isDarkStyle).keepAlive;
|
|
}
|
|
}),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _tabBar() {
|
|
return Consumer<HomeUpdateMarkerProvider>(
|
|
builder: (_, marker, __) {
|
|
return Row(
|
|
children: [
|
|
Expanded(
|
|
child: TabBar(
|
|
tabAlignment: TabAlignment.start,
|
|
tabs: logic.tabs.map((e) {
|
|
//「最新」有更新时右上角挂红点
|
|
final showDot = !isDarkStyle && e.id == '-110' && marker.showHomeLatestDot;
|
|
return Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 14.w),
|
|
alignment: Alignment.center,
|
|
child: Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
Text(e.moduleName ?? ''),
|
|
if (showDot)
|
|
Positioned(
|
|
right: -8,
|
|
top: -2,
|
|
child: HomeUpdateMarkerProvider.buildRedDot(),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
isScrollable: true,
|
|
padding: const EdgeInsets.only(bottom: 2),
|
|
labelPadding: EdgeInsets.zero,
|
|
unselectedLabelStyle: const TextStyle(fontSize: 14),
|
|
unselectedLabelColor: const Color(0x80FFFFFF),
|
|
labelStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
|
labelColor: isDarkStyle ? const Color(0xffFFC000) : const Color(0xffFFC000),
|
|
indicator: CustomIndicator(
|
|
height: 2,
|
|
width: 16.w,
|
|
color: const Color(0xffFFC000),
|
|
offsetY: 4,
|
|
),
|
|
controller: tabCtr,
|
|
),
|
|
),
|
|
_buildMenuIcon(),
|
|
10.sizeBoxW,
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
/// 右侧菜单入口
|
|
Widget _buildMenuIcon() {
|
|
return InkWell(
|
|
enableFeedback: false,
|
|
onTap: () => widget.logic.openEndDrawer(),
|
|
child: Container(
|
|
padding: EdgeInsets.only(bottom: 4),
|
|
child: Image.asset('acg_menu.png'.acgImgPath, width: 24, color: const Color(0xff989898)),
|
|
),
|
|
);
|
|
}
|
|
}
|