mod: 最热合并到首页

This commit is contained in:
guozhigq
2023-07-11 13:01:51 +08:00
parent bc3ac3c9f6
commit e5a05c22ea
16 changed files with 405 additions and 272 deletions

View File

@ -1,77 +1,42 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/pages/hot/index.dart';
import 'package:pilipala/pages/rcmd/index.dart';
class HomeController extends GetxController {
final ScrollController scrollController = ScrollController();
int count = 12;
int _currentPage = 1;
int crossAxisCount = 2;
RxList<RecVideoItemModel> videoList = [RecVideoItemModel()].obs;
bool isLoadingMore = false;
class HomeController extends GetxController with GetTickerProviderStateMixin {
bool flag = false;
OverlayEntry? popupDialog;
Box recVideo = GStrorage.recVideo;
List tabs = [
{'label': '直播', 'type': 'live'},
{'label': '推荐', 'type': 'rcm'},
{'label': '热门', 'type': 'hot'},
];
int initialIndex = 1;
late TabController tabController;
List ctrList = [
'',
Get.find<RcmdController>,
Get.find<HotController>,
];
@override
void onInit() {
super.onInit();
if (recVideo.get('cacheList') != null &&
recVideo.get('cacheList').isNotEmpty) {
List<RecVideoItemModel> list = [];
for (var i in recVideo.get('cacheList')) {
list.add(i);
}
videoList.value = list;
}
}
// 获取推荐
Future queryRcmdFeed(type) async {
var res = await VideoHttp.rcmdVideoList(
ps: count,
freshIdx: _currentPage,
tabController = TabController(
initialIndex: initialIndex,
length: tabs.length,
vsync: this,
);
if (res['status']) {
if (type == 'init') {
if (videoList.length > 1) {
videoList.addAll(res['data']);
} else {
videoList.value = res['data'];
}
} else if (type == 'onRefresh') {
videoList.insertAll(0, res['data']);
} else if (type == 'onLoad') {
videoList.addAll(res['data']);
}
recVideo.put('cacheList', res['data']);
_currentPage += 1;
}
isLoadingMore = false;
return res;
}
// 下拉刷新
Future onRefresh() async {
queryRcmdFeed('onRefresh');
void onRefresh() {
int index = tabController.index;
var ctr = ctrList[index];
ctr().onRefresh();
}
// 上拉加载
Future onLoad() async {
queryRcmdFeed('onLoad');
}
// 返回顶部并刷新
void animateToTop() async {
if (scrollController.offset >=
MediaQuery.of(Get.context!).size.height * 5) {
scrollController.jumpTo(0);
} else {
await scrollController.animateTo(0,
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
}
void animateToTop() {
int index = tabController.index;
var ctr = ctrList[index];
ctr().animateToTop();
}
}

View File

@ -1,13 +1,9 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/skeleton/video_card_v.dart';
import 'package:pilipala/common/widgets/animated_dialog.dart';
import 'package:pilipala/common/widgets/overlay_pop.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/video_card_v.dart';
import 'package:pilipala/pages/hot/index.dart';
import 'package:pilipala/pages/rcmd/index.dart';
import './controller.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/pages/home/widgets/app_bar.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@ -17,10 +13,10 @@ class HomePage extends StatefulWidget {
}
class _HomePageState extends State<HomePage>
with AutomaticKeepAliveClientMixin {
with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
final HomeController _homeController = Get.put(HomeController());
Future? _futureBuilderFuture;
List videoList = [];
// late TabController? _tabController;
@override
bool get wantKeepAlive => true;
@ -28,181 +24,93 @@ class _HomePageState extends State<HomePage>
@override
void initState() {
super.initState();
_futureBuilderFuture = _homeController.queryRcmdFeed('init');
_homeController.videoList.listen((value) {
videoList = value;
setState(() {});
});
_homeController.scrollController.addListener(
() {
if (_homeController.scrollController.position.pixels >=
_homeController.scrollController.position.maxScrollExtent - 200) {
if (!_homeController.isLoadingMore) {
_homeController.isLoadingMore = true;
_homeController.onLoad();
}
}
},
);
// _tabController = TabController(
// initialIndex: _homeController.initialIndex,
// length: _homeController.tabs.length,
// vsync: this,
// );
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
// body: NestedScrollView(
// headerSliverBuilder: (context, innerBoxIsScrolled) => [
// const HomeAppBar()
// ],
body: RefreshIndicator(
displacement: kToolbarHeight + MediaQuery.of(context).padding.top,
onRefresh: () async {
return await _homeController.onRefresh();
},
child: CustomScrollView(
controller: _homeController.scrollController,
slivers: [
const HomeAppBar(),
// SliverPersistentHeader(
// delegate: MySliverPersistentHeaderDelegate(),
// pinned: true,
// ),
SliverPadding(
// 单列布局 EdgeInsets.zero
padding: _homeController.crossAxisCount == 1
? EdgeInsets.zero
: const EdgeInsets.fromLTRB(
StyleString.cardSpace, 0, StyleString.cardSpace, 8),
sliver: FutureBuilder(
future: _futureBuilderFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Map data = snapshot.data as Map;
if (data['status']) {
return Obx(() => contentGrid(
_homeController, _homeController.videoList));
} else {
return HttpError(
errMsg: data['msg'],
fn: () => setState(() {}),
);
}
} else {
// 缓存数据
if (_homeController.videoList.length > 1) {
return contentGrid(
_homeController, _homeController.videoList);
}
// 骨架屏
else {
return contentGrid(_homeController, []);
}
}
},
appBar: AppBar(
titleSpacing: 0,
title: Padding(
padding: const EdgeInsets.only(left: 4, right: 4),
child: Stack(
children: [
const Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.only(left: 8),
child: Text(
'PLPL',
style: TextStyle(
height: 2.8,
fontSize: 17,
fontWeight: FontWeight.bold,
letterSpacing: 1,
fontFamily: 'Jura-Bold',
),
),
),
),
),
const LoadingMore()
],
),
),
// ),
);
}
OverlayEntry _createPopupDialog(videoItem) {
return OverlayEntry(
builder: (context) => AnimatedDialog(
child: OverlayPop(videoItem: videoItem),
));
}
Widget contentGrid(ctr, videoList) {
return SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
// 行间距
mainAxisSpacing: StyleString.cardSpace,
// 列间距
crossAxisSpacing: StyleString.cardSpace,
// 列数
crossAxisCount: ctr.crossAxisCount,
mainAxisExtent: MediaQuery.of(context).size.width /
ctr.crossAxisCount /
StyleString.aspectRatio +
70,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return videoList!.isNotEmpty
?
// VideoCardV(videoItem: videoList![index])
VideoCardV(
videoItem: videoList[index],
longPress: () {
_homeController.popupDialog =
_createPopupDialog(videoList[index]);
Overlay.of(context).insert(_homeController.popupDialog!);
},
longPressEnd: () {
_homeController.popupDialog?.remove();
},
)
: const VideoCardVSkeleton();
},
childCount: videoList!.isNotEmpty ? videoList!.length : 10,
),
);
}
}
class MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
border: Border(
bottom: BorderSide(
color: Theme.of(context).dividerColor.withOpacity(0.1),
),
)),
child: const Text(
'我是一个SliverPersistentHeader',
),
);
}
@override
double get maxExtent => 55.0;
@override
double get minExtent => 55.0;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) =>
true; // 如果内容需要更新设置为true
}
// loading more
class LoadingMore extends StatelessWidget {
const LoadingMore({super.key});
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: Container(
height: MediaQuery.of(context).padding.bottom + 80,
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
child: Center(
child: Text(
'加载中...',
style: TextStyle(
color: Theme.of(context).colorScheme.outline, fontSize: 13),
Align(
alignment: Alignment.center,
child: Theme(
data: ThemeData(
splashColor: Colors.transparent, // 点击时的水波纹颜色设置为透明
highlightColor: Colors.transparent, // 点击时的背景高亮颜色设置为透明
),
child: TabBar(
controller: _homeController.tabController,
tabs: [
for (var i in _homeController.tabs) Tab(text: i['label']),
],
isScrollable: true,
indicatorWeight: 0,
indicatorPadding:
const EdgeInsets.symmetric(horizontal: 3, vertical: 8),
indicator: BoxDecoration(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
indicatorSize: TabBarIndicatorSize.tab,
labelColor:
Theme.of(context).colorScheme.onSecondaryContainer,
labelStyle: const TextStyle(fontSize: 13),
dividerColor: Colors.transparent,
unselectedLabelColor: Theme.of(context).colorScheme.outline,
onTap: (value) => {_homeController.initialIndex = value},
),
),
),
Align(
alignment: Alignment.centerRight,
child: Hero(
tag: 'searchTag',
child: IconButton(
onPressed: () {
Get.toNamed('/search');
},
icon: const Icon(CupertinoIcons.search, size: 21),
),
),
),
],
),
),
),
body: TabBarView(
controller: _homeController.tabController,
children: const [
SizedBox(),
RcmdPage(),
HotPage(),
],
),
);
}
}