feat: 关注页面
This commit is contained in:
@ -167,4 +167,17 @@ class Api {
|
||||
|
||||
// 番剧/剧集明细
|
||||
static const String bangumiInfo = '/pgc/view/web/season';
|
||||
|
||||
// 全部关注的up
|
||||
// vmid 用户id pn 页码 ps 每页个数,最大50 order: desc
|
||||
// order_type 排序规则 最近访问传空,最常访问传 attention
|
||||
static const String followings = '/x/relation/followings';
|
||||
|
||||
// 指定分类的关注
|
||||
// https://api.bilibili.com/x/relation/tag?mid=17340771&tagid=-10&pn=1&ps=20
|
||||
static const String tagFollowings = '/x/relation/tag';
|
||||
|
||||
// 关注分类
|
||||
// https://api.bilibili.com/x/relation/tags
|
||||
static const String followingsClass = '/x/relation/tags';
|
||||
}
|
||||
|
27
lib/http/follow.dart
Normal file
27
lib/http/follow.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'package:pilipala/http/index.dart';
|
||||
import 'package:pilipala/models/follow/result.dart';
|
||||
|
||||
class FollowHttp {
|
||||
static Future followings(
|
||||
{int? vmid, int? pn, int? ps, String? orderType}) async {
|
||||
var res = await Request().get(Api.followings, data: {
|
||||
'vmid': vmid,
|
||||
'pn': pn,
|
||||
'ps': ps,
|
||||
'order': 'desc',
|
||||
'order_type': orderType,
|
||||
});
|
||||
if (res.data['code'] == 0) {
|
||||
return {
|
||||
'status': true,
|
||||
'data': FollowDataModel.fromJson(res.data['data'])
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
'status': false,
|
||||
'data': [],
|
||||
'msg': res.data['message'],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
52
lib/models/follow/result.dart
Normal file
52
lib/models/follow/result.dart
Normal file
@ -0,0 +1,52 @@
|
||||
class FollowDataModel {
|
||||
FollowDataModel({
|
||||
this.total,
|
||||
this.list,
|
||||
});
|
||||
|
||||
int? total;
|
||||
List<FollowItemModel>? list;
|
||||
|
||||
FollowDataModel.fromJson(Map<String, dynamic> json) {
|
||||
total = json['total'];
|
||||
list = json['list']
|
||||
.map<FollowItemModel>((e) => FollowItemModel.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
class FollowItemModel {
|
||||
FollowItemModel({
|
||||
this.mid,
|
||||
this.attribute,
|
||||
this.mtime,
|
||||
this.tag,
|
||||
this.special,
|
||||
this.uname,
|
||||
this.face,
|
||||
this.sign,
|
||||
this.officialVerify,
|
||||
});
|
||||
|
||||
int? mid;
|
||||
int? attribute;
|
||||
int? mtime;
|
||||
List? tag;
|
||||
int? special;
|
||||
String? uname;
|
||||
String? face;
|
||||
String? sign;
|
||||
Map? officialVerify;
|
||||
|
||||
FollowItemModel.fromJson(Map<String, dynamic> json) {
|
||||
mid = json['mid'];
|
||||
attribute = json['attribute'];
|
||||
mtime = json['mtime'];
|
||||
tag = json['tag'];
|
||||
special = json['special'];
|
||||
uname = json['uname'];
|
||||
face = json['face'];
|
||||
sign = json['sign'] == '' ? '还没有签名' : json['sign'];
|
||||
officialVerify = json['official_verify'];
|
||||
}
|
||||
}
|
@ -62,11 +62,22 @@ class _UpPanelState extends State<UpPanel> {
|
||||
top: 5, left: 12, right: 12, bottom: 5),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: const [
|
||||
Text(
|
||||
children: [
|
||||
const Text(
|
||||
'最常访问',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(
|
||||
height: 26,
|
||||
child: TextButton(
|
||||
style: ButtonStyle(
|
||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||
),
|
||||
onPressed: () => Get.toNamed('/follow'),
|
||||
child:
|
||||
const Text('查看全部', style: TextStyle(fontSize: 12)),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
36
lib/pages/follow/controller.dart
Normal file
36
lib/pages/follow/controller.dart
Normal file
@ -0,0 +1,36 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:pilipala/http/follow.dart';
|
||||
import 'package:pilipala/models/follow/result.dart';
|
||||
import 'package:pilipala/utils/storage.dart';
|
||||
|
||||
class FollowController extends GetxController {
|
||||
Box user = GStrorage.user;
|
||||
int pn = 1;
|
||||
int total = 0;
|
||||
RxList<FollowItemModel> followList = [FollowItemModel()].obs;
|
||||
|
||||
Future queryFollowings(type) async {
|
||||
if (type == 'init') {
|
||||
pn = 1;
|
||||
}
|
||||
var res = await FollowHttp.followings(
|
||||
vmid: user.get(UserBoxKey.userMid),
|
||||
pn: pn,
|
||||
ps: 20,
|
||||
orderType: 'attention',
|
||||
);
|
||||
if (res['status']) {
|
||||
if (type == 'init') {
|
||||
followList.value = res['data'].list;
|
||||
total = res['data'].total;
|
||||
} else if (type == 'onRefresh') {
|
||||
followList.insertAll(0, res['data'].list);
|
||||
} else if (type == 'onLoad') {
|
||||
followList.addAll(res['data'].list);
|
||||
}
|
||||
pn += 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
4
lib/pages/follow/index.dart
Normal file
4
lib/pages/follow/index.dart
Normal file
@ -0,0 +1,4 @@
|
||||
library following;
|
||||
|
||||
export './controller.dart';
|
||||
export './view.dart';
|
84
lib/pages/follow/view.dart
Normal file
84
lib/pages/follow/view.dart
Normal file
@ -0,0 +1,84 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pilipala/common/widgets/http_error.dart';
|
||||
import 'package:pilipala/models/follow/result.dart';
|
||||
|
||||
import 'controller.dart';
|
||||
import 'widgets/follow_item.dart';
|
||||
|
||||
class FollowPage extends StatefulWidget {
|
||||
const FollowPage({super.key});
|
||||
|
||||
@override
|
||||
State<FollowPage> createState() => _FollowPageState();
|
||||
}
|
||||
|
||||
class _FollowPageState extends State<FollowPage> {
|
||||
final FollowController _followController = Get.put(FollowController());
|
||||
final ScrollController scrollController = ScrollController();
|
||||
Future? _futureBuilderFuture;
|
||||
bool _isLoadingMore = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_futureBuilderFuture = _followController.queryFollowings('init');
|
||||
scrollController.addListener(
|
||||
() async {
|
||||
if (scrollController.position.pixels >=
|
||||
scrollController.position.maxScrollExtent - 200) {
|
||||
if (!_isLoadingMore) {
|
||||
_isLoadingMore = true;
|
||||
await _followController.queryFollowings('onLoad');
|
||||
_isLoadingMore = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 0,
|
||||
centerTitle: false,
|
||||
title: const Text('关注的用户'),
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
onRefresh: () async =>
|
||||
await _followController.queryFollowings('init'),
|
||||
child: FutureBuilder(
|
||||
future: _futureBuilderFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
var data = snapshot.data;
|
||||
if (data['status']) {
|
||||
List<FollowItemModel> list = _followController.followList;
|
||||
return Obx(
|
||||
() => list.length == 1
|
||||
? SizedBox()
|
||||
: ListView.builder(
|
||||
controller: scrollController,
|
||||
itemCount: list.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return followItem(item: list[index]);
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return HttpError(
|
||||
errMsg: data['msg'],
|
||||
fn: () => _followController.queryFollowings('init'),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 骨架屏
|
||||
return SizedBox();
|
||||
}
|
||||
},
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
23
lib/pages/follow/widgets/follow_item.dart
Normal file
23
lib/pages/follow/widgets/follow_item.dart
Normal file
@ -0,0 +1,23 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||
|
||||
Widget followItem({item}) {
|
||||
return ListTile(
|
||||
onTap: () {},
|
||||
leading: NetworkImgLayer(
|
||||
width: 38,
|
||||
height: 38,
|
||||
type: 'avatar',
|
||||
src: item.face,
|
||||
),
|
||||
title: Text(item.uname),
|
||||
subtitle: Text(
|
||||
item.sign,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
dense: true,
|
||||
trailing: const SizedBox(width: 6),
|
||||
);
|
||||
}
|
@ -3,6 +3,7 @@ import 'package:pilipala/pages/dynamics/deatil/index.dart';
|
||||
import 'package:pilipala/pages/dynamics/index.dart';
|
||||
import 'package:pilipala/pages/fav/index.dart';
|
||||
import 'package:pilipala/pages/favDetail/index.dart';
|
||||
import 'package:pilipala/pages/follow/index.dart';
|
||||
import 'package:pilipala/pages/history/index.dart';
|
||||
import 'package:pilipala/pages/home/index.dart';
|
||||
import 'package:pilipala/pages/hot/index.dart';
|
||||
@ -52,6 +53,8 @@ class Routes {
|
||||
// 动态
|
||||
GetPage(name: '/dynamics', page: () => const DynamicsPage()),
|
||||
// 动态详情
|
||||
GetPage(name: '/dynamicDetail', page: () => const DynamicDetailPage())
|
||||
GetPage(name: '/dynamicDetail', page: () => const DynamicDetailPage()),
|
||||
// 关注
|
||||
GetPage(name: '/follow', page: () => const FollowPage()),
|
||||
];
|
||||
}
|
||||
|
Reference in New Issue
Block a user