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
Widget build(BuildContext context) {
int aid = videoItem.aid;
String heroTag = Utils.makeHeroTag(aid);
return Material(
child: Ink(
child: InkWell(
onTap: () async {
await Future.delayed(const Duration(milliseconds: 200));
int aid = videoItem['id'] ?? videoItem['aid'];
Get.toNamed('/video?aid=$aid', arguments: {'videoItem': videoItem});
Get.toNamed('/video?aid=$aid',
arguments: {'videoItem': videoItem, 'heroTag': heroTag});
},
child: Container(
padding: const EdgeInsets.fromLTRB(
@ -44,12 +46,15 @@ class VideoCardH extends StatelessWidget {
double PR = MediaQuery.of(context).devicePixelRatio;
return Stack(
children: [
NetworkImgLayer(
// src: videoItem['pic'] +
// '@${(maxWidth * 2).toInt()}w',
src: videoItem.pic + '@.webp',
width: maxWidth,
height: maxHeight,
Hero(
tag: heroTag,
child: NetworkImgLayer(
// src: videoItem['pic'] +
// '@${(maxWidth * 2).toInt()}w',
src: videoItem.pic + '@.webp',
width: maxWidth,
height: maxHeight,
),
),
// Image.network( videoItem['pic'], width: double.infinity, height: double.infinity,),
Positioned(
@ -109,7 +114,7 @@ class VideoContent extends StatelessWidget {
overflow: TextOverflow.ellipsis,
),
const Spacer(),
if (videoItem.rcmdReason != '' &&
if (videoItem.rcmdReason != null &&
videoItem.rcmdReason.content != '')
Container(
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
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 {
// var res = await Request().get(Api.videoRecommend, data: data);
// return res;
// }
static Future videoRecommend(data) async {
var res = await Request().get(Api.relatedList, data: data);
return res;
}
}

View File

@ -80,7 +80,9 @@ class HotVideoItemModel {
pubLocation = json["pub_location"];
seasontype = json["seasontype"];
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';
class VideoDetailController extends GetxController {
// tabs
RxList<String> tabs = <String>['简介', '评论'].obs;
// 视频aid
String aid = Get.parameters['aid']!;
@ -14,6 +17,7 @@ class VideoDetailController extends GetxController {
RxBool isLoading = false.obs;
String heroTag = '';
@override
void onInit() {
super.onInit();

View File

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

View File

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

View File

@ -1,4 +1,3 @@
import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:pilipala/common/constants.dart';
@ -17,11 +16,16 @@ class VideoIntroPanel extends StatefulWidget {
State<VideoIntroPanel> createState() => _VideoIntroPanelState();
}
class _VideoIntroPanelState extends State<VideoIntroPanel> {
class _VideoIntroPanelState extends State<VideoIntroPanel>
with AutomaticKeepAliveClientMixin {
final VideoIntroController videoIntroController =
Get.put(VideoIntroController());
VideoDetailData? videoDetail;
// 添加页面缓存
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
@ -42,10 +46,10 @@ class _VideoIntroPanelState extends State<VideoIntroPanel> {
future: videoIntroController.queryVideoDetail(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
print(snapshot.data);
if (snapshot.data) {
// 请求成功
return _buildView(context, false, videoDetail);
// return _buildView(context, false, videoDetail);
return VideoInfo(loadingStatus: false, videoDetail: videoDetail);
} else {
// 请求错误
return Center(
@ -58,7 +62,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel> {
);
}
} 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),
const SizedBox(height: 5),
// const SizedBox(height: 5),
],
)
: 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/pages/video/detail/controller.dart';
import 'package:pilipala/pages/video/detail/introduction/index.dart';
import 'package:pilipala/pages/video/detail/related/index.dart';
class VideoDetailPage extends StatefulWidget {
const VideoDetailPage({Key? key}) : super(key: key);
@ -15,12 +16,10 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
final VideoDetailController videoDetailController =
Get.put(VideoDetailController());
final _tabs = <String>['简介', '评论'];
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: _tabs.length, // tab的数量.
length: videoDetailController.tabs.length, // tab的数量.
child: SafeArea(
top: false,
bottom: false,
@ -80,14 +79,16 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 180,
width: 280,
margin: const EdgeInsets.only(left: 20),
child: TabBar(
splashBorderRadius: BorderRadius.circular(6),
dividerColor: Colors.transparent,
tabs: _tabs
.map((String name) => Tab(text: name))
.toList(),
child: Obx(
() => TabBar(
splashBorderRadius: BorderRadius.circular(6),
dividerColor: Colors.transparent,
tabs: videoDetailController.tabs
.map((String name) => Tab(text: name))
.toList(),
),
),
),
// 弹幕开关
@ -117,6 +118,14 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
context),
),
const VideoIntroPanel(),
SliverToBoxAdapter(
child: Divider(
color:
Theme.of(context).dividerColor.withOpacity(0.1),
),
),
const SliverPadding(padding: EdgeInsets.only(bottom: 5)),
const RelatedVideoPanel(),
],
);
}),