mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-01 08:38:18 +08:00
40
lib/pages/member_season_series/controller.dart
Normal file
40
lib/pages/member_season_series/controller.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/member.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
|
||||
class SeasonSeriesController extends CommonListController {
|
||||
SeasonSeriesController(this.mid);
|
||||
final int mid;
|
||||
int? count;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
queryData();
|
||||
}
|
||||
|
||||
@override
|
||||
List? getDataList(response) {
|
||||
return ((response['seasons_list'] as List?) ?? []) +
|
||||
((response['series_list'] as List?) ?? []);
|
||||
}
|
||||
|
||||
@override
|
||||
void checkIsEnd(int length) {
|
||||
if (count != null && length >= count!) {
|
||||
isEnd = true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool customHandleResponse(bool isRefresh, Success response) {
|
||||
count = response.response['page']?['total'];
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LoadingState> customGetData() => MemberHttp.seasonSeriesList(
|
||||
mid: mid,
|
||||
pn: currentPage,
|
||||
);
|
||||
}
|
||||
111
lib/pages/member_season_series/view.dart
Normal file
111
lib/pages/member_season_series/view.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/pages/member_season_series/controller.dart';
|
||||
import 'package:PiliPlus/pages/member_season_series/widget/season_series_card.dart';
|
||||
import 'package:PiliPlus/pages/member_video/view.dart';
|
||||
import 'package:PiliPlus/pages/member_contribute/view.dart';
|
||||
import 'package:PiliPlus/utils/grid.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SeasonSeriesPage extends StatefulWidget {
|
||||
const SeasonSeriesPage({
|
||||
super.key,
|
||||
required this.mid,
|
||||
this.heroTag,
|
||||
});
|
||||
|
||||
final int mid;
|
||||
final String? heroTag;
|
||||
|
||||
@override
|
||||
State<SeasonSeriesPage> createState() => _SeasonSeriesPageState();
|
||||
}
|
||||
|
||||
class _SeasonSeriesPageState extends State<SeasonSeriesPage>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
late final _controller = Get.put(
|
||||
SeasonSeriesController(widget.mid),
|
||||
tag: widget.heroTag,
|
||||
);
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
return Obx(() => _buildBody(_controller.loadingState.value));
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<dynamic>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? CustomScrollView(
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
dynamic item = loadingState.response![index];
|
||||
return SeasonSeriesCard(
|
||||
item: item,
|
||||
onTap: () {
|
||||
bool isSeason = item['meta']['season_id'] != null;
|
||||
dynamic id = isSeason
|
||||
? item['meta']['season_id']
|
||||
: item['meta']['series_id'];
|
||||
Get.to(
|
||||
Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(item['meta']['name']),
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: MemberVideo(
|
||||
type: isSeason
|
||||
? ContributeType.season
|
||||
: ContributeType.series,
|
||||
heroTag: widget.heroTag,
|
||||
mid: widget.mid,
|
||||
seasonId: isSeason ? id : null,
|
||||
seriesId: isSeason ? null : id,
|
||||
title: item['meta']['name'],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: loadingState.response!.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: scrollErrorWidget(
|
||||
onReload: () {
|
||||
_controller.onReload();
|
||||
},
|
||||
),
|
||||
Error() => scrollErrorWidget(
|
||||
errMsg: loadingState.errMsg,
|
||||
onReload: () {
|
||||
_controller.onReload();
|
||||
},
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
102
lib/pages/member_season_series/widget/season_series_card.dart
Normal file
102
lib/pages/member_season_series/widget/season_series_card.dart
Normal file
@@ -0,0 +1,102 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/badge.dart';
|
||||
import 'package:PiliPlus/common/widgets/image_save.dart';
|
||||
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SeasonSeriesCard extends StatelessWidget {
|
||||
const SeasonSeriesCard({
|
||||
super.key,
|
||||
required this.item,
|
||||
required this.onTap,
|
||||
});
|
||||
final dynamic item;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onLongPress: () {
|
||||
imageSaveDialog(
|
||||
title: item['meta']['name'],
|
||||
cover: item['meta']['cover'],
|
||||
);
|
||||
},
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: StyleString.safeSpace,
|
||||
vertical: 5,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: StyleString.aspectRatio,
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints boxConstraints) {
|
||||
final double maxWidth = boxConstraints.maxWidth;
|
||||
final double maxHeight = boxConstraints.maxHeight;
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
src: item['meta']['cover'],
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
),
|
||||
PBadge(
|
||||
text:
|
||||
'${item['meta']['season_id'] != null ? '合集' : '列表'}: ${item['meta']['total']}',
|
||||
bottom: 6.0,
|
||||
right: 6.0,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
videoContent(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget videoContent(context) {
|
||||
final theme = Theme.of(context);
|
||||
return Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
item['meta']['name'],
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.bodyMedium!.fontSize,
|
||||
height: 1.42,
|
||||
letterSpacing: 0.3,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const Spacer(),
|
||||
Text(
|
||||
Utils.dateFormat(item['meta']['ptime']),
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
height: 1,
|
||||
color: theme.colorScheme.outline,
|
||||
overflow: TextOverflow.clip,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user