mod: 首页推荐代码

This commit is contained in:
guozhigq
2023-08-18 18:22:20 +08:00
parent 47a3c964c0
commit b55568ef2a
4 changed files with 57 additions and 82 deletions

View File

@ -1,8 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/pages/rcmd/controller.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
class LiveCard extends StatelessWidget { class LiveCard extends StatelessWidget {
@ -95,7 +93,7 @@ class LiveContent extends StatelessWidget {
liveItem.title, liveItem.title,
textAlign: TextAlign.start, textAlign: TextAlign.start,
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500), style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500),
maxLines: Get.find<RcmdController>().crossAxisCount, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
SizedBox( SizedBox(

View File

@ -14,8 +14,7 @@ import 'package:pilipala/common/widgets/network_img_layer.dart';
// 视频卡片 - 垂直布局 // 视频卡片 - 垂直布局
class VideoCardV extends StatelessWidget { class VideoCardV extends StatelessWidget {
// ignore: prefer_typing_uninitialized_variables final dynamic videoItem;
final videoItem;
final Function()? longPress; final Function()? longPress;
final Function()? longPressEnd; final Function()? longPressEnd;
@ -89,48 +88,20 @@ class VideoCardV extends StatelessWidget {
onTap: () async => onPushDetail(heroTag), onTap: () async => onPushDetail(heroTag),
child: Column( child: Column(
children: [ children: [
ClipRRect( AspectRatio(
borderRadius: const BorderRadius.only( aspectRatio: StyleString.aspectRatio,
topLeft: StyleString.imgRadius, child: LayoutBuilder(builder: (context, boxConstraints) {
topRight: StyleString.imgRadius, double maxWidth = boxConstraints.maxWidth;
bottomLeft: StyleString.imgRadius, double maxHeight = boxConstraints.maxHeight;
bottomRight: StyleString.imgRadius, return Hero(
), tag: heroTag,
child: AspectRatio( child: NetworkImgLayer(
aspectRatio: StyleString.aspectRatio, src: videoItem.pic,
child: LayoutBuilder(builder: (context, boxConstraints) { width: maxWidth,
double maxWidth = boxConstraints.maxWidth; height: maxHeight,
double maxHeight = boxConstraints.maxHeight; ),
return Stack( );
children: [ }),
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: videoItem.pic,
width: maxWidth,
height: maxHeight,
),
),
// if (videoItem.stat.view is int &&
// videoItem.stat.danmaku is int)
// Positioned(
// left: 0,
// right: 0,
// bottom: 0,
// child: AnimatedOpacity(
// opacity: 1,
// duration: const Duration(milliseconds: 200),
// child: VideoStat(
// view: videoItem.stat.view,
// danmaku: videoItem.stat.danmaku,
// duration: videoItem.duration,
// ),
// ),
// ),
],
);
}),
),
), ),
VideoContent(videoItem: videoItem) VideoContent(videoItem: videoItem)
], ],
@ -155,7 +126,6 @@ class VideoContent extends StatelessWidget {
children: [ children: [
Text( Text(
videoItem.title, videoItem.title,
textAlign: TextAlign.start,
style: const TextStyle(fontSize: 13), style: const TextStyle(fontSize: 13),
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -182,21 +152,15 @@ class VideoContent extends StatelessWidget {
) )
], ],
Expanded( Expanded(
child: LayoutBuilder(builder: child: Text(
(BuildContext context, BoxConstraints constraints) { videoItem.owner.name,
return SizedBox( maxLines: 1,
width: constraints.maxWidth, style: TextStyle(
child: Text( fontSize:
videoItem.owner.name, Theme.of(context).textTheme.labelMedium!.fontSize,
maxLines: 1, color: Theme.of(context).colorScheme.outline,
style: TextStyle( ),
fontSize: ),
Theme.of(context).textTheme.labelMedium!.fontSize,
color: Theme.of(context).colorScheme.outline,
),
),
);
}),
), ),
if (videoItem.goto == 'av') if (videoItem.goto == 'av')
SizedBox( SizedBox(

View File

@ -8,9 +8,8 @@ import 'package:pilipala/utils/storage.dart';
class RcmdController extends GetxController { class RcmdController extends GetxController {
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
int _currentPage = 0; int _currentPage = 0;
int crossAxisCount = 2; RxList<RecVideoItemAppModel> videoList = <RecVideoItemAppModel>[].obs;
RxList<RecVideoItemAppModel> videoList = [RecVideoItemAppModel()].obs; bool isLoadingMore = true;
bool isLoadingMore = false;
OverlayEntry? popupDialog; OverlayEntry? popupDialog;
Box recVideo = GStrorage.recVideo; Box recVideo = GStrorage.recVideo;
@ -29,6 +28,9 @@ class RcmdController extends GetxController {
// 获取推荐 // 获取推荐
Future queryRcmdFeed(type) async { Future queryRcmdFeed(type) async {
if (isLoadingMore == false) {
return;
}
if (type == 'onRefresh') { if (type == 'onRefresh') {
_currentPage = 0; _currentPage = 0;
} }
@ -37,7 +39,7 @@ class RcmdController extends GetxController {
); );
if (res['status']) { if (res['status']) {
if (type == 'init') { if (type == 'init') {
if (videoList.length > 1) { if (videoList.isNotEmpty) {
videoList.addAll(res['data']); videoList.addAll(res['data']);
} else { } else {
videoList.value = res['data']; videoList.value = res['data'];
@ -56,6 +58,7 @@ class RcmdController extends GetxController {
// 下拉刷新 // 下拉刷新
Future onRefresh() async { Future onRefresh() async {
isLoadingMore = true;
queryRcmdFeed('onRefresh'); queryRcmdFeed('onRefresh');
} }

View File

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
@ -41,7 +42,9 @@ class _RcmdPageState extends State<RcmdPage>
scrollController.position.maxScrollExtent - 200) { scrollController.position.maxScrollExtent - 200) {
if (!_rcmdController.isLoadingMore) { if (!_rcmdController.isLoadingMore) {
_rcmdController.isLoadingMore = true; _rcmdController.isLoadingMore = true;
_rcmdController.onLoad(); WidgetsBinding.instance.addPostFrameCallback((_) async {
_rcmdController.onLoad();
});
} }
} }
@ -74,30 +77,36 @@ class _RcmdPageState extends State<RcmdPage>
controller: _rcmdController.scrollController, controller: _rcmdController.scrollController,
slivers: [ slivers: [
SliverPadding( SliverPadding(
// 单列布局 EdgeInsets.zero padding:
padding: _rcmdController.crossAxisCount == 1 const EdgeInsets.fromLTRB(0, StyleString.safeSpace, 0, 0),
? EdgeInsets.zero
: const EdgeInsets.fromLTRB(0, StyleString.safeSpace, 0, 0),
sliver: FutureBuilder( sliver: FutureBuilder(
future: _futureBuilderFuture, future: _futureBuilderFuture,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
Map data = snapshot.data as Map; Map data = snapshot.data as Map;
if (data['status']) { if (data['status']) {
return SliverLayoutBuilder( return Platform.isAndroid || Platform.isIOS
builder: (context, boxConstraints) { ? Obx(() => contentGrid(
return Obx(() => contentGrid( _rcmdController, _rcmdController.videoList))
_rcmdController, _rcmdController.videoList)); : SliverLayoutBuilder(
}); builder: (context, boxConstraints) {
return Obx(() => contentGrid(
_rcmdController, _rcmdController.videoList));
});
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => {}, fn: () {
setState(() {
_futureBuilderFuture =
_rcmdController.queryRcmdFeed('init');
});
},
); );
} }
} else { } else {
// 缓存数据 // 缓存数据
if (_rcmdController.videoList.length > 1) { if (_rcmdController.videoList.isNotEmpty) {
return contentGrid( return contentGrid(
_rcmdController, _rcmdController.videoList); _rcmdController, _rcmdController.videoList);
} }
@ -118,9 +127,10 @@ class _RcmdPageState extends State<RcmdPage>
OverlayEntry _createPopupDialog(videoItem) { OverlayEntry _createPopupDialog(videoItem) {
return OverlayEntry( return OverlayEntry(
builder: (context) => AnimatedDialog( builder: (context) => AnimatedDialog(
child: OverlayPop(videoItem: videoItem), child: OverlayPop(videoItem: videoItem),
)); ),
);
} }
Widget contentGrid(ctr, videoList) { Widget contentGrid(ctr, videoList) {