feat: 粉丝页面

This commit is contained in:
guozhigq
2023-07-11 15:37:47 +08:00
parent 522ce60750
commit a2f65cfe09
10 changed files with 234 additions and 4 deletions

View File

@ -180,4 +180,9 @@ class Api {
// 关注分类
// https://api.bilibili.com/x/relation/tags
static const String followingsClass = '/x/relation/tags';
// 粉丝
// vmid 用户id pn 页码 ps 每页个数最大50 order: desc
// order_type 排序规则 最近访问传空,最常访问传 attention
static const String fans = 'https://api.bilibili.com/x/relation/fans';
}

23
lib/http/fan.dart Normal file
View File

@ -0,0 +1,23 @@
import 'package:pilipala/http/index.dart';
import 'package:pilipala/models/fans/result.dart';
class FanHttp {
static Future fans({int? vmid, int? pn, int? ps, String? orderType}) async {
var res = await Request().get(Api.fans, data: {
'vmid': vmid,
'pn': pn,
'ps': ps,
'order': 'desc',
'order_type': orderType,
});
if (res.data['code'] == 0) {
return {'status': true, 'data': FansDataModel.fromJson(res.data['data'])};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
}

View File

@ -0,0 +1,52 @@
class FansDataModel {
FansDataModel({
this.total,
this.list,
});
int? total;
List<FansItemModel>? list;
FansDataModel.fromJson(Map<String, dynamic> json) {
total = json['total'];
list = json['list']
.map<FansItemModel>((e) => FansItemModel.fromJson(e))
.toList();
}
}
class FansItemModel {
FansItemModel({
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;
FansItemModel.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'];
}
}

View File

@ -0,0 +1,36 @@
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/fan.dart';
import 'package:pilipala/models/fans/result.dart';
import 'package:pilipala/utils/storage.dart';
class FansController extends GetxController {
Box user = GStrorage.user;
int pn = 1;
int total = 0;
RxList<FansItemModel> fansList = [FansItemModel()].obs;
Future queryFans(type) async {
if (type == 'init') {
pn = 1;
}
var res = await FanHttp.fans(
vmid: user.get(UserBoxKey.userMid),
pn: pn,
ps: 20,
orderType: 'attention',
);
if (res['status']) {
if (type == 'init') {
fansList.value = res['data'].list;
total = res['data'].total;
} else if (type == 'onRefresh') {
fansList.insertAll(0, res['data'].list);
} else if (type == 'onLoad') {
fansList.addAll(res['data'].list);
}
pn += 1;
}
return res;
}
}

4
lib/pages/fan/index.dart Normal file
View File

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

84
lib/pages/fan/view.dart Normal file
View 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/fans/result.dart';
import 'controller.dart';
import 'widgets/fan_item.dart';
class FansPage extends StatefulWidget {
const FansPage({super.key});
@override
State<FansPage> createState() => _FansPageState();
}
class _FansPageState extends State<FansPage> {
final FansController _fansController = Get.put(FansController());
final ScrollController scrollController = ScrollController();
Future? _futureBuilderFuture;
bool _isLoadingMore = false;
@override
void initState() {
super.initState();
_futureBuilderFuture = _fansController.queryFans('init');
scrollController.addListener(
() async {
if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 200) {
if (!_isLoadingMore) {
_isLoadingMore = true;
await _fansController.queryFans('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 _fansController.queryFans('init'),
child: FutureBuilder(
future: _futureBuilderFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
var data = snapshot.data;
if (data['status']) {
List<FansItemModel> list = _fansController.fansList;
return Obx(
() => list.length == 1
? SizedBox()
: ListView.builder(
controller: scrollController,
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return fanItem(item: list[index]);
},
),
);
} else {
return HttpError(
errMsg: data['msg'],
fn: () => _fansController.queryFans('init'),
);
}
} else {
// 骨架屏
return SizedBox();
}
},
),
),
);
}
}

View File

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
Widget fanItem({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),
);
}

View File

@ -44,7 +44,7 @@ class _FollowPageState extends State<FollowPage> {
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: false,
title: const Text('关注的用户'),
title: const Text('我的关注'),
),
body: RefreshIndicator(
onRefresh: () async =>

View File

@ -55,7 +55,8 @@ class MinePage extends StatelessWidget {
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data['status']) {
return Obx(() => userInfoBuild(mineController, context));
return Obx(
() => userInfoBuild(mineController, context));
} else {
return userInfoBuild(mineController, context);
}
@ -250,7 +251,7 @@ class MinePage extends StatelessWidget {
),
),
InkWell(
onTap: () {},
onTap: () => Get.toNamed('/follow'),
borderRadius: StyleString.mdRadius,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
@ -280,7 +281,7 @@ class MinePage extends StatelessWidget {
),
),
InkWell(
onTap: () {},
onTap: () => Get.toNamed('/fan'),
borderRadius: StyleString.mdRadius,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,

View File

@ -1,6 +1,7 @@
import 'package:get/get.dart';
import 'package:pilipala/pages/dynamics/deatil/index.dart';
import 'package:pilipala/pages/dynamics/index.dart';
import 'package:pilipala/pages/fan/index.dart';
import 'package:pilipala/pages/fav/index.dart';
import 'package:pilipala/pages/favDetail/index.dart';
import 'package:pilipala/pages/follow/index.dart';
@ -56,5 +57,7 @@ class Routes {
GetPage(name: '/dynamicDetail', page: () => const DynamicDetailPage()),
// 关注
GetPage(name: '/follow', page: () => const FollowPage()),
// 粉丝
GetPage(name: '/fan', page: () => const FansPage()),
];
}