mod: 相关推荐视频开发、页面跳转Hero、一些字段修改

This commit is contained in:
guozhigq
2023-04-21 14:06:01 +08:00
parent f3b7ad0302
commit 171c16a4f9
15 changed files with 152 additions and 31 deletions

View File

@ -13,13 +13,15 @@ class VideoCardH extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
int aid = videoItem.aid;
String heroTag = Utils.makeHeroTag(aid);
return Material( return Material(
child: Ink( child: Ink(
child: InkWell( child: InkWell(
onTap: () async { onTap: () async {
await Future.delayed(const Duration(milliseconds: 200)); await Future.delayed(const Duration(milliseconds: 200));
int aid = videoItem['id'] ?? videoItem['aid']; Get.toNamed('/video?aid=$aid',
Get.toNamed('/video?aid=$aid', arguments: {'videoItem': videoItem}); arguments: {'videoItem': videoItem, 'heroTag': heroTag});
}, },
child: Container( child: Container(
padding: const EdgeInsets.fromLTRB( padding: const EdgeInsets.fromLTRB(
@ -44,13 +46,16 @@ class VideoCardH extends StatelessWidget {
double PR = MediaQuery.of(context).devicePixelRatio; double PR = MediaQuery.of(context).devicePixelRatio;
return Stack( return Stack(
children: [ children: [
NetworkImgLayer( Hero(
tag: heroTag,
child: NetworkImgLayer(
// src: videoItem['pic'] + // src: videoItem['pic'] +
// '@${(maxWidth * 2).toInt()}w', // '@${(maxWidth * 2).toInt()}w',
src: videoItem.pic + '@.webp', src: videoItem.pic + '@.webp',
width: maxWidth, width: maxWidth,
height: maxHeight, height: maxHeight,
), ),
),
// Image.network( videoItem['pic'], width: double.infinity, height: double.infinity,), // Image.network( videoItem['pic'], width: double.infinity, height: double.infinity,),
Positioned( Positioned(
right: 4, right: 4,
@ -109,7 +114,7 @@ class VideoContent extends StatelessWidget {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
const Spacer(), const Spacer(),
if (videoItem.rcmdReason != '' && if (videoItem.rcmdReason != null &&
videoItem.rcmdReason.content != '') videoItem.rcmdReason.content != '')
Container( Container(
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5), padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),

View File

@ -6,4 +6,7 @@ class Api {
// 视频详情 // 视频详情
// 竖屏 https://api.bilibili.com/x/web-interface/view?aid=527403921 // 竖屏 https://api.bilibili.com/x/web-interface/view?aid=527403921
static const String videoDetail = '/x/web-interface/view'; static const String videoDetail = '/x/web-interface/view';
// 视频详情页 相关视频
static const String relatedList = '/x/web-interface/archive/related';
} }

View File

@ -25,8 +25,8 @@ class VideoHttp {
} }
} }
// static Future videoRecommend(data) async { static Future videoRecommend(data) async {
// var res = await Request().get(Api.videoRecommend, data: data); var res = await Request().get(Api.relatedList, data: data);
// return res; return res;
// } }
} }

View File

@ -80,7 +80,9 @@ class HotVideoItemModel {
pubLocation = json["pub_location"]; pubLocation = json["pub_location"];
seasontype = json["seasontype"]; seasontype = json["seasontype"];
isOgv = json["isOgv"]; isOgv = json["isOgv"];
rcmdReason = RcmdReason.fromJson(json['rcmd_reason']); rcmdReason = json['rcmd_reason'] != ''
? RcmdReason.fromJson(json['rcmd_reason'])
: null;
} }
} }

View File

@ -1,6 +1,9 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
class VideoDetailController extends GetxController { class VideoDetailController extends GetxController {
// tabs
RxList<String> tabs = <String>['简介', '评论'].obs;
// 视频aid // 视频aid
String aid = Get.parameters['aid']!; String aid = Get.parameters['aid']!;
@ -14,6 +17,7 @@ class VideoDetailController extends GetxController {
RxBool isLoading = false.obs; RxBool isLoading = false.obs;
String heroTag = ''; String heroTag = '';
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();

View File

@ -2,6 +2,7 @@ import 'package:get/get.dart';
import 'package:pilipala/http/api.dart'; import 'package:pilipala/http/api.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/init.dart';
import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/models/video_detail_res.dart';
import 'package:pilipala/pages/video/detail/controller.dart';
class VideoIntroController extends GetxController { class VideoIntroController extends GetxController {
// 视频aid // 视频aid
@ -41,6 +42,10 @@ class VideoIntroController extends GetxController {
}); });
VideoDetailResponse result = VideoDetailResponse.fromJson(res.data); VideoDetailResponse result = VideoDetailResponse.fromJson(res.data);
videoDetail.value = result.data!; videoDetail.value = result.data!;
Get.find<VideoDetailController>().tabs.value = [
'简介',
'评论 ${result.data!.stat!.reply}'
];
// await Future.delayed(const Duration(seconds: 3)); // await Future.delayed(const Duration(seconds: 3));
return true; return true;
} }

View File

@ -1,4 +1,4 @@
library video_detail_introduction; library video_intro_panel;
export './controller.dart'; export './controller.dart';
export './view.dart'; export './view.dart';

View File

@ -1,4 +1,3 @@
import 'package:flutter/rendering.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
@ -17,11 +16,16 @@ class VideoIntroPanel extends StatefulWidget {
State<VideoIntroPanel> createState() => _VideoIntroPanelState(); State<VideoIntroPanel> createState() => _VideoIntroPanelState();
} }
class _VideoIntroPanelState extends State<VideoIntroPanel> { class _VideoIntroPanelState extends State<VideoIntroPanel>
with AutomaticKeepAliveClientMixin {
final VideoIntroController videoIntroController = final VideoIntroController videoIntroController =
Get.put(VideoIntroController()); Get.put(VideoIntroController());
VideoDetailData? videoDetail; VideoDetailData? videoDetail;
// 添加页面缓存
@override
bool get wantKeepAlive => true;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -42,10 +46,10 @@ class _VideoIntroPanelState extends State<VideoIntroPanel> {
future: videoIntroController.queryVideoDetail(), future: videoIntroController.queryVideoDetail(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
print(snapshot.data);
if (snapshot.data) { if (snapshot.data) {
// 请求成功 // 请求成功
return _buildView(context, false, videoDetail); // return _buildView(context, false, videoDetail);
return VideoInfo(loadingStatus: false, videoDetail: videoDetail);
} else { } else {
// 请求错误 // 请求错误
return Center( return Center(
@ -58,7 +62,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel> {
); );
} }
} else { } else {
return _buildView(context, true, videoDetail); // return _buildView(context, true, videoDetail);
return VideoInfo(loadingStatus: true, videoDetail: videoDetail);
} }
}, },
); );
@ -320,7 +325,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
), ),
), ),
_actionGrid(context), _actionGrid(context),
const SizedBox(height: 5), // const SizedBox(height: 5),
], ],
) )
: const Center(child: CircularProgressIndicator()), : const Center(child: CircularProgressIndicator()),

View File

@ -0,0 +1,4 @@
library video_player;
export './controller.dart';
export './view.dart';

View File

View File

@ -0,0 +1,31 @@
import 'dart:convert';
import 'package:get/get.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/model_hot_video_item.dart';
class ReleatedController extends GetxController {
// 视频aid
String aid = Get.parameters['aid']!;
// 推荐视频列表
List relatedVideoList = [];
Future<dynamic> queryVideoRecommend() async {
try {
var res = await VideoHttp.videoRecommend({'aid': aid});
List<HotVideoItemModel> list = [];
try {
for (var i in res.data['data']) {
list.add(HotVideoItemModel.fromJson(i));
}
relatedVideoList = list;
} catch (err) {
return err.toString();
}
return res.data['data'];
} catch (err) {
return err.toString();
}
}
}

View File

@ -0,0 +1,4 @@
library releated_video_panel;
export './controller.dart';
export './view.dart';

View File

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/video_card_h.dart';
import './controller.dart';
class RelatedVideoPanel extends StatefulWidget {
const RelatedVideoPanel({super.key});
@override
State<RelatedVideoPanel> createState() => _RelatedVideoPanelState();
}
class _RelatedVideoPanelState extends State<RelatedVideoPanel> {
final ReleatedController _releatedController = Get.put(ReleatedController());
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _releatedController.queryVideoRecommend(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data!.isNotEmpty) {
// 请求成功
List videoList = _releatedController.relatedVideoList;
return SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
if (index == videoList.length) {
return SizedBox(height: MediaQuery.of(context).padding.bottom);
} else {
return VideoCardH(
videoItem: videoList[index],
);
}
}, childCount: videoList.length + 1));
} else {
// 请求错误
return const Center(
child: Text('出错了'),
);
}
} else {
return const SliverToBoxAdapter(
child: Text('请求中'),
);
}
},
);
}
}

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/pages/video/detail/controller.dart'; import 'package:pilipala/pages/video/detail/controller.dart';
import 'package:pilipala/pages/video/detail/introduction/index.dart'; import 'package:pilipala/pages/video/detail/introduction/index.dart';
import 'package:pilipala/pages/video/detail/related/index.dart';
class VideoDetailPage extends StatefulWidget { class VideoDetailPage extends StatefulWidget {
const VideoDetailPage({Key? key}) : super(key: key); const VideoDetailPage({Key? key}) : super(key: key);
@ -15,12 +16,10 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
final VideoDetailController videoDetailController = final VideoDetailController videoDetailController =
Get.put(VideoDetailController()); Get.put(VideoDetailController());
final _tabs = <String>['简介', '评论'];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DefaultTabController( return DefaultTabController(
length: _tabs.length, // tab的数量. length: videoDetailController.tabs.length, // tab的数量.
child: SafeArea( child: SafeArea(
top: false, top: false,
bottom: false, bottom: false,
@ -80,16 +79,18 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
Container( Container(
width: 180, width: 280,
margin: const EdgeInsets.only(left: 20), margin: const EdgeInsets.only(left: 20),
child: TabBar( child: Obx(
() => TabBar(
splashBorderRadius: BorderRadius.circular(6), splashBorderRadius: BorderRadius.circular(6),
dividerColor: Colors.transparent, dividerColor: Colors.transparent,
tabs: _tabs tabs: videoDetailController.tabs
.map((String name) => Tab(text: name)) .map((String name) => Tab(text: name))
.toList(), .toList(),
), ),
), ),
),
// 弹幕开关 // 弹幕开关
// const Spacer(), // const Spacer(),
// Flexible( // Flexible(
@ -117,6 +118,14 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
context), context),
), ),
const VideoIntroPanel(), const VideoIntroPanel(),
SliverToBoxAdapter(
child: Divider(
color:
Theme.of(context).dividerColor.withOpacity(0.1),
),
),
const SliverPadding(padding: EdgeInsets.only(bottom: 5)),
const RelatedVideoPanel(),
], ],
); );
}), }),