mod: 个人主页

This commit is contained in:
guozhigq
2023-11-27 00:41:22 +08:00
parent 5d6a935f3d
commit e73e02cf13
38 changed files with 1550 additions and 696 deletions

View File

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/http/member.dart';
import 'package:pilipala/models/member/seasons.dart';
class MemberSeasonsController extends GetxController {
final ScrollController scrollController = ScrollController();
late int mid;
late int seasonId;
int pn = 1;
int ps = 30;
int count = 0;
RxList<MemberArchiveItem> seasonsList = <MemberArchiveItem>[].obs;
late Map page;
@override
void onInit() {
super.onInit();
mid = int.parse(Get.parameters['mid']!);
seasonId = int.parse(Get.parameters['seasonId']!);
}
// 获取专栏详情
Future getSeasonDetail(type) async {
if (type == 'onRefresh') {
pn = 1;
}
var res = await MemberHttp.getSeasonDetail(
mid: mid,
seasonId: seasonId,
pn: pn,
ps: ps,
sortReverse: false,
);
if (res['status']) {
seasonsList.addAll(res['data'].archives);
page = res['data'].page;
pn += 1;
}
return res;
}
// 上拉加载
Future onLoad() async {
getSeasonDetail('onLoad');
}
}

View File

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

View File

@ -0,0 +1,103 @@
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart';
import 'controller.dart';
import 'widgets/item.dart';
class MemberSeasonsPage extends StatefulWidget {
const MemberSeasonsPage({super.key});
@override
State<MemberSeasonsPage> createState() => _MemberSeasonsPageState();
}
class _MemberSeasonsPageState extends State<MemberSeasonsPage> {
final MemberSeasonsController _memberSeasonsController =
Get.put(MemberSeasonsController());
late Future _futureBuilderFuture;
late ScrollController scrollController;
@override
void initState() {
super.initState();
_futureBuilderFuture =
_memberSeasonsController.getSeasonDetail('onRefresh');
scrollController = _memberSeasonsController.scrollController;
scrollController.addListener(
() {
if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 200) {
EasyThrottle.throttle(
'member_archives', const Duration(milliseconds: 500), () {
_memberSeasonsController.onLoad();
});
}
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('他的专栏'),
),
body: Padding(
padding: const EdgeInsets.only(
left: StyleString.safeSpace,
right: StyleString.safeSpace,
),
child: SingleChildScrollView(
controller: _memberSeasonsController.scrollController,
child: FutureBuilder(
future: _futureBuilderFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data != null) {
Map data = snapshot.data as Map;
List list = _memberSeasonsController.seasonsList;
if (data['status']) {
return Obx(
() => list.isNotEmpty
? LayoutBuilder(
builder: (context, boxConstraints) {
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: StyleString.safeSpace,
mainAxisSpacing: StyleString.safeSpace,
childAspectRatio: 0.94,
),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: _memberSeasonsController
.seasonsList.length,
itemBuilder: (context, i) {
return MemberSeasonsItem(
seasonItem: _memberSeasonsController
.seasonsList[i],
);
},
);
},
)
: const SizedBox(),
);
} else {
return const SizedBox();
}
} else {
return const SizedBox();
}
} else {
return const SizedBox();
}
},
),
),
),
);
}
}

View File

@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/badge.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/common/widgets/stat/view.dart';
import 'package:pilipala/http/search.dart';
import 'package:pilipala/utils/utils.dart';
class MemberSeasonsItem extends StatelessWidget {
final dynamic seasonItem;
const MemberSeasonsItem({
Key? key,
required this.seasonItem,
}) : super(key: key);
@override
Widget build(BuildContext context) {
String heroTag = Utils.makeHeroTag(seasonItem.aid);
return Card(
elevation: 0,
clipBehavior: Clip.hardEdge,
margin: EdgeInsets.zero,
child: InkWell(
onTap: () async {
int cid =
await SearchHttp.ab2c(aid: seasonItem.aid, bvid: seasonItem.bvid);
Get.toNamed('/video?bvid=${seasonItem.bvid}&cid=$cid',
arguments: {'videoItem': seasonItem, 'heroTag': heroTag});
},
child: Column(
children: [
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(builder: (context, boxConstraints) {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: seasonItem.pic,
width: maxWidth,
height: maxHeight,
),
),
if (seasonItem.duration != null)
PBadge(
bottom: 6,
right: 6,
type: 'gray',
text: Utils.timeFormat(seasonItem.duration),
)
],
);
}),
),
Padding(
padding: const EdgeInsets.fromLTRB(5, 6, 0, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
seasonItem.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Row(
children: [
StatView(
view: seasonItem.view,
theme: 'gray',
),
const Spacer(),
Text(
Utils.CustomStamp_str(
timestamp: seasonItem.pubdate, date: 'MM-DD'),
style: TextStyle(
fontSize: 11,
color: Theme.of(context).colorScheme.outline,
),
),
const SizedBox(width: 6)
],
),
],
),
),
],
),
),
);
}
}