mod: 首页推荐代码
This commit is contained in:
@ -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(
|
||||||
|
@ -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(
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
Reference in New Issue
Block a user