opt: medialist page

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-02 16:31:50 +08:00
parent 9bbd934f8e
commit 2abf01362c
6 changed files with 154 additions and 150 deletions

View File

@@ -13,6 +13,7 @@ class PBadge extends StatelessWidget {
final String? semanticsLabel; final String? semanticsLabel;
final bool bold; final bool bold;
final double? textScaleFactor; final double? textScaleFactor;
final EdgeInsets? padding;
const PBadge({ const PBadge({
super.key, super.key,
@@ -28,6 +29,7 @@ class PBadge extends StatelessWidget {
this.semanticsLabel, this.semanticsLabel,
this.bold = true, this.bold = true,
this.textScaleFactor, this.textScaleFactor,
this.padding,
}); });
@override @override
@@ -54,7 +56,7 @@ class PBadge extends StatelessWidget {
color = t.onError; color = t.onError;
} }
EdgeInsets paddingStyle = late EdgeInsets paddingStyle =
const EdgeInsets.symmetric(vertical: 2, horizontal: 3); const EdgeInsets.symmetric(vertical: 2, horizontal: 3);
double fontSize = 11; double fontSize = 11;
BorderRadius br = BorderRadius.circular(4); BorderRadius br = BorderRadius.circular(4);
@@ -66,7 +68,7 @@ class PBadge extends StatelessWidget {
} }
Widget content = Container( Widget content = Container(
padding: paddingStyle, padding: padding ?? paddingStyle,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: br, borderRadius: br,
color: bgColor, color: bgColor,

View File

@@ -107,7 +107,6 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel>
late bool _isInit = true; late bool _isInit = true;
late final Color primary = Theme.of(context).colorScheme.primary; late final Color primary = Theme.of(context).colorScheme.primary;
final height = 120 / StyleString.aspectRatio + 10;
void listener() { void listener() {
_currentTabIndex.value = _tabController.index; _currentTabIndex.value = _tabController.index;
@@ -248,9 +247,9 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel>
Widget _buildBody(int index, episodes) { Widget _buildBody(int index, episodes) {
return KeepAliveWrapper( return KeepAliveWrapper(
builder: (context) => ScrollablePositionedList.builder( builder: (context) => ScrollablePositionedList.separated(
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: 5, top: 7,
bottom: MediaQuery.of(context).padding.bottom + 80, bottom: MediaQuery.of(context).padding.bottom + 80,
), ),
reverse: _isReversed[index], reverse: _isReversed[index],
@@ -306,6 +305,7 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel>
); );
}, },
itemScrollController: _itemScrollController[index], itemScrollController: _itemScrollController[index],
separatorBuilder: (context, index) => const SizedBox(height: 2),
), ),
); );
} }
@@ -356,7 +356,7 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel>
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
child: SizedBox( child: SizedBox(
height: height, height: 98,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
if (episode.badge != null && episode.badge == "会员") { if (episode.badge != null && episode.badge == "会员") {

View File

@@ -70,6 +70,11 @@ class FavPgcItem extends StatelessWidget {
right: 4, right: 4,
top: 4, top: 4,
text: item.badge, text: item.badge,
fs: 10,
padding: const EdgeInsets.symmetric(
horizontal: 2,
vertical: 1,
),
), ),
Positioned.fill( Positioned.fill(
child: IgnorePointer( child: IgnorePointer(

View File

@@ -1,4 +1,3 @@
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
@@ -79,7 +78,6 @@ class _MemberFavoriteState extends State<MemberFavorite>
} }
_buildItem(Datum data, bool isFirst) { _buildItem(Datum data, bool isFirst) {
final height = 120 / StyleString.aspectRatio + 10;
return Theme( return Theme(
data: Theme.of(context).copyWith( data: Theme.of(context).copyWith(
dividerColor: Colors.transparent, dividerColor: Colors.transparent,
@@ -108,7 +106,7 @@ class _MemberFavoriteState extends State<MemberFavorite>
children: [ children: [
...(data.mediaListResponse?.list as List<FavList>).map( ...(data.mediaListResponse?.list as List<FavList>).map(
(item) => SizedBox( (item) => SizedBox(
height: height, height: 98,
child: MemberFavItem( child: MemberFavItem(
item: item, item: item,
callback: (res) { callback: (res) {

View File

@@ -90,7 +90,7 @@ class _MemberHomeState extends State<MemberHome>
), ),
SliverToBoxAdapter( SliverToBoxAdapter(
child: SizedBox( child: SizedBox(
height: 120 / StyleString.aspectRatio + 10, height: 98,
child: MemberFavItem( child: MemberFavItem(
item: loadingState.response.favourite2.item.first, item: loadingState.response.favourite2.item.first,
), ),

View File

@@ -1,9 +1,9 @@
import 'package:PiliPlus/common/widgets/dialog.dart'; import 'package:PiliPlus/common/widgets/dialog.dart';
import 'package:PiliPlus/common/widgets/icon_button.dart'; import 'package:PiliPlus/common/widgets/icon_button.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/common/widgets/stat/stat.dart'; import 'package:PiliPlus/common/widgets/stat/stat.dart';
import 'package:PiliPlus/pages/common/common_collapse_slide_page.dart'; import 'package:PiliPlus/pages/common/common_collapse_slide_page.dart';
import 'package:PiliPlus/pages/common/common_slide_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -46,7 +46,8 @@ class MediaListPanel extends CommonCollapseSlidePage {
State<MediaListPanel> createState() => _MediaListPanelState(); State<MediaListPanel> createState() => _MediaListPanelState();
} }
class _MediaListPanelState extends CommonSlidePageState<MediaListPanel> { class _MediaListPanelState
extends CommonCollapseSlidePageState<MediaListPanel> {
final _scrollController = ItemScrollController(); final _scrollController = ItemScrollController();
late RxBool desc; late RxBool desc;
@@ -97,6 +98,10 @@ class _MediaListPanelState extends CommonSlidePageState<MediaListPanel> {
const SizedBox(width: 14), const SizedBox(width: 14),
], ],
), ),
Divider(
height: 1,
color: Theme.of(context).colorScheme.outline.withOpacity(0.1),
),
Expanded( Expanded(
child: enableSlide ? slideList() : buildList, child: enableSlide ? slideList() : buildList,
), ),
@@ -119,11 +124,12 @@ class _MediaListPanelState extends CommonSlidePageState<MediaListPanel> {
() { () {
final showDelBtn = final showDelBtn =
widget.onDelete != null && widget.mediaList.length > 1; widget.onDelete != null && widget.mediaList.length > 1;
return ScrollablePositionedList.builder( return ScrollablePositionedList.separated(
itemScrollController: _scrollController, itemScrollController: _scrollController,
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
itemCount: widget.mediaList.length, itemCount: widget.mediaList.length,
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: 7,
bottom: MediaQuery.paddingOf(context).bottom + 80, bottom: MediaQuery.paddingOf(context).bottom + 80,
), ),
itemBuilder: ((context, index) { itemBuilder: ((context, index) {
@@ -133,158 +139,151 @@ class _MediaListPanelState extends CommonSlidePageState<MediaListPanel> {
widget.mediaList.length < widget.count!)) { widget.mediaList.length < widget.count!)) {
widget.loadMoreMedia(); widget.loadMoreMedia();
} }
return InkWell( return SizedBox(
onTap: () async { height: 98,
if (item.type != 2) { child: InkWell(
SmartDialog.showToast('不支持播放该类型视频'); onTap: () async {
return; if (item.type != 2) {
} SmartDialog.showToast('不支持播放该类型视频');
Get.back(); return;
String bvid = item.bvid!; }
int? aid = item.id; Get.back();
String cover = item.cover ?? ''; String bvid = item.bvid!;
final int cid = int? aid = item.id;
item.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid); String cover = item.cover ?? '';
widget.changeMediaList?.call(bvid, cid, aid, cover); final int cid =
}, item.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
child: Stack( widget.changeMediaList?.call(bvid, cid, aid, cover);
children: [ },
Padding( onLongPress: () {
padding: const EdgeInsets.symmetric( imageSaveDialog(
horizontal: 12, context: context,
vertical: 5, title: item.title,
), cover: item.cover,
child: LayoutBuilder( );
builder: (context, boxConstraints) { },
const double width = 120; child: Stack(
return Container( children: [
constraints: const BoxConstraints(minHeight: 88), Padding(
height: width / StyleString.aspectRatio, padding: const EdgeInsets.symmetric(
child: Row( horizontal: 12,
mainAxisAlignment: MainAxisAlignment.start, vertical: 5,
crossAxisAlignment: CrossAxisAlignment.start, ),
children: <Widget>[ child: Row(
AspectRatio( mainAxisAlignment: MainAxisAlignment.start,
aspectRatio: StyleString.aspectRatio, crossAxisAlignment: CrossAxisAlignment.start,
child: LayoutBuilder( children: [
builder: (BuildContext context, AspectRatio(
BoxConstraints boxConstraints) { aspectRatio: StyleString.aspectRatio,
final double maxWidth = child: LayoutBuilder(
boxConstraints.maxWidth; builder: (context, boxConstraints) {
final double maxHeight = return Stack(
boxConstraints.maxHeight;
return Stack(
children: [
NetworkImgLayer(
src: item.cover ?? '',
width: maxWidth,
height: maxHeight,
),
PBadge(
text: Utils.timeFormat(
item.duration!),
right: 6.0,
bottom: 6.0,
type: 'gray',
),
],
);
},
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Text( NetworkImgLayer(
item.title as String, src: item.cover,
textAlign: TextAlign.start, width: boxConstraints.maxWidth,
maxLines: 2, height: boxConstraints.maxHeight,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight:
item.bvid == widget.getBvId()
? FontWeight.bold
: null,
color: item.bvid == widget.getBvId()
? Theme.of(context)
.colorScheme
.primary
: null,
),
), ),
const Spacer(), PBadge(
Text( text: Utils.timeFormat(item.duration!),
item.upper?.name as String, right: 6.0,
style: TextStyle( bottom: 6.0,
fontSize: Theme.of(context) type: 'gray',
.textTheme ),
.labelMedium! ],
.fontSize, );
color: Theme.of(context) },
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.title!,
textAlign: TextAlign.start,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: item.bvid == widget.getBvId()
? FontWeight.bold
: null,
color: item.bvid == widget.getBvId()
? Theme.of(context)
.colorScheme .colorScheme
.outline, .primary
), : null,
),
),
const Spacer(),
Text(
item.upper!.name!,
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.labelMedium!
.fontSize,
color:
Theme.of(context).colorScheme.outline,
),
),
const SizedBox(height: 2),
Row(
children: [
StatView(
context: context,
theme: 'gray',
value: Utils.numFormat(
item.cntInfo!['play']!),
), ),
const SizedBox(height: 2), const SizedBox(width: 8),
Row( StatDanMu(
children: [ context: context,
StatView( theme: 'gray',
context: context, value: Utils.numFormat(
theme: 'gray', item.cntInfo!['danmaku']!),
value: Utils.numFormat(
item.cntInfo!['play']!),
),
const SizedBox(width: 8),
StatDanMu(
context: context,
theme: 'gray',
value: Utils.numFormat(
item.cntInfo!['danmaku']!),
),
],
), ),
], ],
), ),
), ],
], ),
), ),
); ],
}, ),
), ),
), if (showDelBtn && item.bvid != widget.getBvId())
if (showDelBtn && item.bvid != widget.getBvId()) Positioned(
Positioned( right: 12,
right: 12, bottom: 0,
bottom: 0, child: InkWell(
child: InkWell( customBorder: const CircleBorder(),
customBorder: const CircleBorder(), onTap: () {
onTap: () { showConfirmDialog(
showConfirmDialog( context: context,
context: context, title: '确定移除该视频?',
title: '确定移除该视频?', onConfirm: () => widget.onDelete!(index),
onConfirm: () => widget.onDelete!(index), );
); },
}, onLongPress: () => widget.onDelete!(index),
onLongPress: () => widget.onDelete!(index), child: Padding(
child: Padding( padding: const EdgeInsets.all(9),
padding: const EdgeInsets.all(9), child: Icon(
child: Icon( Icons.clear,
Icons.clear, size: 18,
size: 18, color: Theme.of(context)
color: Theme.of(context) .colorScheme
.colorScheme .onSurfaceVariant,
.onSurfaceVariant, ),
), ),
), ),
), ),
), ],
], ),
), ),
); );
}), }),
separatorBuilder: (context, index) => const SizedBox(height: 2),
); );
}, },
); );