mod: 接口整理、增加up粉丝请求

This commit is contained in:
guozhigq
2023-04-21 16:07:34 +08:00
parent 171c16a4f9
commit 3aee691d00
10 changed files with 210 additions and 108 deletions

View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
class HttpError extends StatelessWidget {
HttpError({required this.errMsg, required this.fn, super.key});
String errMsg = '';
final Function()? fn;
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: SizedBox(
height: 150,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
errMsg,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
fn!();
},
child: const Text('点击重试'))
],
),
),
);
}
}

View File

@ -5,8 +5,12 @@ class Api {
static const String hotList = '/x/web-interface/popular'; static const String hotList = '/x/web-interface/popular';
// 视频详情 // 视频详情
// 竖屏 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 videoIntro = '/x/web-interface/view';
// 视频详情页 相关视频 // 视频详情页 相关视频
static const String relatedList = '/x/web-interface/archive/related'; static const String relatedList = '/x/web-interface/archive/related';
// 用户(被)关注数、投稿数
// https://api.bilibili.com/x/relation/stat?vmid=697166795
static const String userStat = '/x/relation/stat';
} }

13
lib/http/user.dart Normal file
View File

@ -0,0 +1,13 @@
import 'package:pilipala/http/api.dart';
import 'package:pilipala/http/init.dart';
class UserHttp {
static Future<dynamic> userStat(mid) async {
var res = await Request().get(Api.userStat, data: {'vmid': mid});
if (res.data['code'] == 0) {
return {'status': true, 'data': res.data['data']};
} else {
return {'status': false};
}
}
}

View File

@ -1,11 +1,58 @@
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/model_hot_video_item.dart';
import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/models/video_detail_res.dart';
/// res.data['code'] == 0 请求正常返回结果
/// res.data['data'] 为结果
/// 返回{'status': bool, 'data': List}
/// view层根据 status 判断渲染逻辑
class VideoHttp { class VideoHttp {
// 首页推荐视频
static Future rcmdVideoList(data) async {
var res = await Request().get(
Api.recommendList,
data: {
'feed_version': 'V3',
'ps': data['ps'],
'fresh_idx': data['fresh_idx']
},
);
if (res.data['code'] == 0) {
List<RecVideoItemModel> list = [];
for (var i in res.data['data']['item']) {
list.add(RecVideoItemModel.fromJson(i));
}
return {'status': true, 'data': list};
} else {
return {'status': false, 'data': []};
}
}
// 最热视频
static Future hotVideoList(data) async {
var res = await Request().get(
Api.hotList,
data: {
'pn': data['pn'],
'ps': data['ps'],
},
);
if (res.data['code'] == 0) {
List<HotVideoItemModel> list = [];
for (var i in res.data['data']['list']) {
list.add(HotVideoItemModel.fromJson(i));
}
return {'status': true, 'data': list};
} else {
return {'status': false, 'data': []};
}
}
// 视频信息 标题、简介 // 视频信息 标题、简介
static Future videoDetail(data) async { static Future videoIntro(aid) async {
var res = await Request().get(Api.videoDetail, data: data); var res = await Request().get(Api.videoIntro, data: {'aid': aid});
VideoDetailResponse result = VideoDetailResponse.fromJson(res.data); VideoDetailResponse result = VideoDetailResponse.fromJson(res.data);
if (result.code == 0) { if (result.code == 0) {
return {'status': true, 'data': result.data!}; return {'status': true, 'data': result.data!};
@ -25,8 +72,17 @@ class VideoHttp {
} }
} }
static Future videoRecommend(data) async { // 相关视频
var res = await Request().get(Api.relatedList, data: data); static Future relatedVideoList(aid) async {
return res; var res = await Request().get(Api.relatedList, data: {'aid': aid});
if (res.data['code'] == 0) {
List<HotVideoItemModel> list = [];
for (var i in res.data['data']) {
list.add(HotVideoItemModel.fromJson(i));
}
return {'status': true, 'data': list};
} else {
return {'status': true, 'data': []};
}
} }
} }

View File

@ -1,7 +1,6 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/api.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/http/init.dart';
import 'package:pilipala/models/model_rec_video_item.dart'; import 'package:pilipala/models/model_rec_video_item.dart';
class HomeController extends GetxController { class HomeController extends GetxController {
@ -21,22 +20,20 @@ class HomeController extends GetxController {
// 获取推荐 // 获取推荐
Future queryRcmdFeed(type) async { Future queryRcmdFeed(type) async {
var res = await Request().get( var res = await VideoHttp.rcmdVideoList({
Api.recommendList, 'ps': count,
data: {'feed_version': "V3", 'ps': count, 'fresh_idx': _currentPage}, 'fresh_idx': _currentPage,
); });
List<RecVideoItemModel> list = []; if (res['status']) {
for (var i in res.data['data']['item']) { if (type == 'init') {
list.add(RecVideoItemModel.fromJson(i)); videoList.value = res['data'];
} else if (type == 'onRefresh') {
videoList.insertAll(0, res['data']);
} else if (type == 'onLoad') {
videoList.addAll(res['data']);
}
_currentPage += 1;
} }
if (type == 'init') {
videoList.value = list;
} else if (type == 'onRefresh') {
videoList.insertAll(0, list);
} else if (type == 'onLoad') {
videoList.addAll(list);
}
_currentPage += 1;
isLoadingMore = false; isLoadingMore = false;
} }

View File

@ -1,8 +1,6 @@
import 'package:flutter/animation.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/api.dart'; import 'package:flutter/material.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/model_hot_video_item.dart'; import 'package:pilipala/models/model_hot_video_item.dart';
class HotController extends GetxController { class HotController extends GetxController {
@ -21,22 +19,20 @@ class HotController extends GetxController {
// 获取推荐 // 获取推荐
Future queryHotFeed(type) async { Future queryHotFeed(type) async {
var res = await Request().get( var res = await VideoHttp.hotVideoList({
Api.hotList, 'pn': _currentPage,
data: {'pn': _currentPage, 'ps': _count}, 'ps': _count,
); });
List<HotVideoItemModel> list = []; if (res['status']) {
for (var i in res.data['data']['list']) { if (type == 'init') {
list.add(HotVideoItemModel.fromJson(i)); videoList.value = res['data'];
} else if (type == 'onRefresh') {
videoList.insertAll(0, res['data']);
} else if (type == 'onLoad') {
videoList.addAll(res['data']);
}
_currentPage += 1;
} }
if (type == 'init') {
videoList.value = list;
} else if (type == 'onRefresh') {
videoList.insertAll(0, list);
} else if (type == 'onLoad') {
videoList.addAll(list);
}
_currentPage += 1;
isLoadingMore = false; isLoadingMore = false;
} }

View File

@ -1,6 +1,6 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/api.dart'; import 'package:pilipala/http/user.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/video.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'; import 'package:pilipala/pages/video/detail/controller.dart';
@ -20,6 +20,12 @@ class VideoIntroController extends GetxController {
// 视频详情 请求返回 // 视频详情 请求返回
Rx<VideoDetailData> videoDetail = VideoDetailData().obs; Rx<VideoDetailData> videoDetail = VideoDetailData().obs;
// 请求返回的信息
String responseMsg = '请求异常';
// up主粉丝数
Map userStat = {'follower': '-'};
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -36,17 +42,28 @@ class VideoIntroController extends GetxController {
} }
} }
Future queryVideoDetail() async { // 获取视频简介
var res = await Request().get(Api.videoDetail, data: { Future queryVideoIntro() async {
'aid': aid, var result = await VideoHttp.videoIntro(aid);
}); if (result['status']) {
VideoDetailResponse result = VideoDetailResponse.fromJson(res.data); videoDetail.value = result['data']!;
videoDetail.value = result.data!; Get.find<VideoDetailController>().tabs.value = [
Get.find<VideoDetailController>().tabs.value = [ '简介',
'简介', '评论 ${result['data']!.stat!.reply}'
'评论 ${result.data!.stat!.reply}' ];
]; } else {
// await Future.delayed(const Duration(seconds: 3)); responseMsg = result['msg'];
return true; }
// 获取到粉丝数再返回
await queryUserStat();
return result;
}
// 获取up主粉丝数
Future queryUserStat() async {
var result = await UserHttp.userStat(videoDetail.value.owner!.mid);
if (result['status']) {
userStat = result['data'];
}
} }
} }

View File

@ -1,6 +1,7 @@
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';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/pages/video/detail/widgets/expandable_section.dart'; import 'package:pilipala/pages/video/detail/widgets/expandable_section.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/common/widgets/stat/danmu.dart'; import 'package:pilipala/common/widgets/stat/danmu.dart';
@ -43,27 +44,29 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FutureBuilder( return FutureBuilder(
future: videoIntroController.queryVideoDetail(), future: videoIntroController.queryVideoIntro(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data) { if (snapshot.data['status']) {
// 请求成功 // 请求成功
// return _buildView(context, false, videoDetail); // return _buildView(context, false, videoDetail);
return VideoInfo(loadingStatus: false, videoDetail: videoDetail); return VideoInfo(
loadingStatus: false,
videoDetail: videoDetail,
videoIntroController: videoIntroController);
} else { } else {
// 请求错误 // 请求错误
return Center( return HttpError(
child: IconButton( errMsg: snapshot.data['msg'],
icon: const Icon(Icons.refresh), fn: () => setState(() {}),
onPressed: () {
setState(() {});
},
),
); );
} }
} else { } else {
// return _buildView(context, true, videoDetail); // return _buildView(context, true, videoDetail);
return VideoInfo(loadingStatus: true, videoDetail: videoDetail); return VideoInfo(
loadingStatus: true,
videoDetail: videoDetail,
videoIntroController: videoIntroController);
} }
}, },
); );
@ -90,8 +93,13 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
class VideoInfo extends StatefulWidget { class VideoInfo extends StatefulWidget {
bool loadingStatus = false; bool loadingStatus = false;
VideoDetailData? videoDetail; VideoDetailData? videoDetail;
VideoIntroController? videoIntroController;
VideoInfo({Key? key, required this.loadingStatus, this.videoDetail}) VideoInfo(
{Key? key,
required this.loadingStatus,
this.videoDetail,
this.videoIntroController})
: super(key: key); : super(key: key);
@override @override
@ -150,19 +158,17 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
? widget.videoDetail!.owner!.name ? widget.videoDetail!.owner!.name
: videoItem['owner'].name), : videoItem['owner'].name),
const SizedBox(height: 2), const SizedBox(height: 2),
// Text.rich( Text(
// TextSpan( widget.loadingStatus
// style: TextStyle( ? '- 粉丝'
// color: Theme.of(context) : '${Utils.numFormat(widget.videoIntroController!.userStat['follower'])}粉丝',
// .colorScheme style: TextStyle(
// .outline, fontSize: Theme.of(context)
// fontSize: 11), .textTheme
// children: const [ .labelSmall!
// TextSpan(text: '2.6万粉丝'), .fontSize,
// TextSpan(text: ' '), color: Theme.of(context).colorScheme.outline),
// TextSpan(text: '2.6万粉丝'), )
// ]),
// ),
]), ]),
const Spacer(), const Spacer(),
AnimatedOpacity( AnimatedOpacity(

View File

@ -1,8 +1,5 @@
import 'dart:convert';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/model_hot_video_item.dart';
class ReleatedController extends GetxController { class ReleatedController extends GetxController {
// 视频aid // 视频aid
@ -10,22 +7,5 @@ class ReleatedController extends GetxController {
// 推荐视频列表 // 推荐视频列表
List relatedVideoList = []; List relatedVideoList = [];
Future<dynamic> queryVideoRecommend() async { Future<dynamic> queryRelatedVideo() => VideoHttp.relatedVideoList(aid);
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

@ -16,22 +16,22 @@ class _RelatedVideoPanelState extends State<RelatedVideoPanel> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FutureBuilder( return FutureBuilder(
future: _releatedController.queryVideoRecommend(), future: _releatedController.queryRelatedVideo(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data!.isNotEmpty) { if (snapshot.data!['status']) {
// 请求成功 // 请求成功
List videoList = _releatedController.relatedVideoList; // List videoList = _releatedController.relatedVideoList;
return SliverList( return SliverList(
delegate: SliverChildBuilderDelegate((context, index) { delegate: SliverChildBuilderDelegate((context, index) {
if (index == videoList.length) { if (index == snapshot.data['data'].length) {
return SizedBox(height: MediaQuery.of(context).padding.bottom); return SizedBox(height: MediaQuery.of(context).padding.bottom);
} else { } else {
return VideoCardH( return VideoCardH(
videoItem: videoList[index], videoItem: snapshot.data['data'][index],
); );
} }
}, childCount: videoList.length + 1)); }, childCount: snapshot.data['data'].length + 1));
} else { } else {
// 请求错误 // 请求错误
return const Center( return const Center(