diff --git a/lib/common/widgets/badge.dart b/lib/common/widgets/badge.dart index a27e895e..df4a99dc 100644 --- a/lib/common/widgets/badge.dart +++ b/lib/common/widgets/badge.dart @@ -13,6 +13,7 @@ class PBadge extends StatelessWidget { final String? semanticsLabel; final bool bold; final double? textScaleFactor; + final EdgeInsets? padding; const PBadge({ super.key, @@ -28,6 +29,7 @@ class PBadge extends StatelessWidget { this.semanticsLabel, this.bold = true, this.textScaleFactor, + this.padding, }); @override @@ -54,7 +56,7 @@ class PBadge extends StatelessWidget { color = t.onError; } - EdgeInsets paddingStyle = + late EdgeInsets paddingStyle = const EdgeInsets.symmetric(vertical: 2, horizontal: 3); double fontSize = 11; BorderRadius br = BorderRadius.circular(4); @@ -66,7 +68,7 @@ class PBadge extends StatelessWidget { } Widget content = Container( - padding: paddingStyle, + padding: padding ?? paddingStyle, decoration: BoxDecoration( borderRadius: br, color: bgColor, diff --git a/lib/common/widgets/episode_panel.dart b/lib/common/widgets/episode_panel.dart index 0263766d..089d6ca9 100644 --- a/lib/common/widgets/episode_panel.dart +++ b/lib/common/widgets/episode_panel.dart @@ -107,7 +107,6 @@ class _EpisodePanelState extends CommonSlidePageState late bool _isInit = true; late final Color primary = Theme.of(context).colorScheme.primary; - final height = 120 / StyleString.aspectRatio + 10; void listener() { _currentTabIndex.value = _tabController.index; @@ -248,9 +247,9 @@ class _EpisodePanelState extends CommonSlidePageState Widget _buildBody(int index, episodes) { return KeepAliveWrapper( - builder: (context) => ScrollablePositionedList.builder( + builder: (context) => ScrollablePositionedList.separated( padding: EdgeInsets.only( - top: 5, + top: 7, bottom: MediaQuery.of(context).padding.bottom + 80, ), reverse: _isReversed[index], @@ -306,6 +305,7 @@ class _EpisodePanelState extends CommonSlidePageState ); }, itemScrollController: _itemScrollController[index], + separatorBuilder: (context, index) => const SizedBox(height: 2), ), ); } @@ -356,7 +356,7 @@ class _EpisodePanelState extends CommonSlidePageState return Material( color: Colors.transparent, child: SizedBox( - height: height, + height: 98, child: InkWell( onTap: () { if (episode.badge != null && episode.badge == "会员") { diff --git a/lib/pages/fav/pgc/widget/item.dart b/lib/pages/fav/pgc/widget/item.dart index 318112f7..9235c93c 100644 --- a/lib/pages/fav/pgc/widget/item.dart +++ b/lib/pages/fav/pgc/widget/item.dart @@ -70,6 +70,11 @@ class FavPgcItem extends StatelessWidget { right: 4, top: 4, text: item.badge, + fs: 10, + padding: const EdgeInsets.symmetric( + horizontal: 2, + vertical: 1, + ), ), Positioned.fill( child: IgnorePointer( diff --git a/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart b/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart index 98fb44d2..252e4ff1 100644 --- a/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart +++ b/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -79,7 +78,6 @@ class _MemberFavoriteState extends State } _buildItem(Datum data, bool isFirst) { - final height = 120 / StyleString.aspectRatio + 10; return Theme( data: Theme.of(context).copyWith( dividerColor: Colors.transparent, @@ -108,7 +106,7 @@ class _MemberFavoriteState extends State children: [ ...(data.mediaListResponse?.list as List).map( (item) => SizedBox( - height: height, + height: 98, child: MemberFavItem( item: item, callback: (res) { diff --git a/lib/pages/member/new/content/member_home/member_home.dart b/lib/pages/member/new/content/member_home/member_home.dart index af7c67da..868b109b 100644 --- a/lib/pages/member/new/content/member_home/member_home.dart +++ b/lib/pages/member/new/content/member_home/member_home.dart @@ -90,7 +90,7 @@ class _MemberHomeState extends State ), SliverToBoxAdapter( child: SizedBox( - height: 120 / StyleString.aspectRatio + 10, + height: 98, child: MemberFavItem( item: loadingState.response.favourite2.item.first, ), diff --git a/lib/pages/video/detail/widgets/media_list_panel.dart b/lib/pages/video/detail/widgets/media_list_panel.dart index f958e275..5979e6cb 100644 --- a/lib/pages/video/detail/widgets/media_list_panel.dart +++ b/lib/pages/video/detail/widgets/media_list_panel.dart @@ -1,9 +1,9 @@ import 'package:PiliPlus/common/widgets/dialog.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/stat/stat.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_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -46,7 +46,8 @@ class MediaListPanel extends CommonCollapseSlidePage { State createState() => _MediaListPanelState(); } -class _MediaListPanelState extends CommonSlidePageState { +class _MediaListPanelState + extends CommonCollapseSlidePageState { final _scrollController = ItemScrollController(); late RxBool desc; @@ -97,6 +98,10 @@ class _MediaListPanelState extends CommonSlidePageState { const SizedBox(width: 14), ], ), + Divider( + height: 1, + color: Theme.of(context).colorScheme.outline.withOpacity(0.1), + ), Expanded( child: enableSlide ? slideList() : buildList, ), @@ -119,11 +124,12 @@ class _MediaListPanelState extends CommonSlidePageState { () { final showDelBtn = widget.onDelete != null && widget.mediaList.length > 1; - return ScrollablePositionedList.builder( + return ScrollablePositionedList.separated( itemScrollController: _scrollController, physics: const AlwaysScrollableScrollPhysics(), itemCount: widget.mediaList.length, padding: EdgeInsets.only( + top: 7, bottom: MediaQuery.paddingOf(context).bottom + 80, ), itemBuilder: ((context, index) { @@ -133,158 +139,151 @@ class _MediaListPanelState extends CommonSlidePageState { widget.mediaList.length < widget.count!)) { widget.loadMoreMedia(); } - return InkWell( - onTap: () async { - if (item.type != 2) { - SmartDialog.showToast('不支持播放该类型视频'); - return; - } - Get.back(); - String bvid = item.bvid!; - int? aid = item.id; - String cover = item.cover ?? ''; - final int cid = - item.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid); - widget.changeMediaList?.call(bvid, cid, aid, cover); - }, - child: Stack( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 5, - ), - child: LayoutBuilder( - builder: (context, boxConstraints) { - const double width = 120; - return Container( - constraints: const BoxConstraints(minHeight: 88), - height: width / StyleString.aspectRatio, - 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( - 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, + return SizedBox( + height: 98, + child: InkWell( + onTap: () async { + if (item.type != 2) { + SmartDialog.showToast('不支持播放该类型视频'); + return; + } + Get.back(); + String bvid = item.bvid!; + int? aid = item.id; + String cover = item.cover ?? ''; + final int cid = + item.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid); + widget.changeMediaList?.call(bvid, cid, aid, cover); + }, + onLongPress: () { + imageSaveDialog( + context: context, + title: item.title, + cover: item.cover, + ); + }, + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 5, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + return Stack( children: [ - Text( - item.title as String, - 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 - .primary - : null, - ), + NetworkImgLayer( + src: item.cover, + width: boxConstraints.maxWidth, + height: boxConstraints.maxHeight, ), - const Spacer(), - Text( - item.upper?.name as String, - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelMedium! - .fontSize, - color: Theme.of(context) + 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: [ + 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 - .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), - Row( - children: [ - StatView( - context: context, - theme: 'gray', - value: Utils.numFormat( - item.cntInfo!['play']!), - ), - const SizedBox(width: 8), - StatDanMu( - context: context, - theme: 'gray', - value: Utils.numFormat( - item.cntInfo!['danmaku']!), - ), - ], + const SizedBox(width: 8), + StatDanMu( + context: context, + theme: 'gray', + value: Utils.numFormat( + item.cntInfo!['danmaku']!), ), ], ), - ), - ], + ], + ), ), - ); - }, + ], + ), ), - ), - if (showDelBtn && item.bvid != widget.getBvId()) - Positioned( - right: 12, - bottom: 0, - child: InkWell( - customBorder: const CircleBorder(), - onTap: () { - showConfirmDialog( - context: context, - title: '确定移除该视频?', - onConfirm: () => widget.onDelete!(index), - ); - }, - onLongPress: () => widget.onDelete!(index), - child: Padding( - padding: const EdgeInsets.all(9), - child: Icon( - Icons.clear, - size: 18, - color: Theme.of(context) - .colorScheme - .onSurfaceVariant, + if (showDelBtn && item.bvid != widget.getBvId()) + Positioned( + right: 12, + bottom: 0, + child: InkWell( + customBorder: const CircleBorder(), + onTap: () { + showConfirmDialog( + context: context, + title: '确定移除该视频?', + onConfirm: () => widget.onDelete!(index), + ); + }, + onLongPress: () => widget.onDelete!(index), + child: Padding( + padding: const EdgeInsets.all(9), + child: Icon( + Icons.clear, + size: 18, + color: Theme.of(context) + .colorScheme + .onSurfaceVariant, + ), ), ), ), - ), - ], + ], + ), ), ); }), + separatorBuilder: (context, index) => const SizedBox(height: 2), ); }, );