diff --git a/lib/pages/bangumi/view.dart b/lib/pages/bangumi/view.dart index e83527638..453f6574e 100644 --- a/lib/pages/bangumi/view.dart +++ b/lib/pages/bangumi/view.dart @@ -196,8 +196,11 @@ class _BangumiPageState extends CommonPageState List _buildRcmd(ThemeData theme) => [ _buildRcmdTitle(theme), SliverPadding( - padding: const EdgeInsets.fromLTRB( - StyleString.safeSpace, 0, StyleString.safeSpace, 0), + padding: EdgeInsets.only( + left: StyleString.safeSpace, + right: StyleString.safeSpace, + bottom: MediaQuery.paddingOf(context).bottom + 80, + ), sliver: Obx( () => _buildRcmdBody(controller.loadingState.value), ), @@ -330,11 +333,15 @@ class _BangumiPageState extends CommonPageState ? Column( children: [ _buildFollowTitle(theme), - SizedBox( - height: Grid.smallCardWidth / 2 / 0.75 + - MediaQuery.textScalerOf(context).scale(50), - child: Obx( - () => _buildFollowBody(controller.followState.value), + MediaQuery.removePadding( + context: context, + removeLeft: context.orientation == Orientation.landscape, + child: SizedBox( + height: Grid.smallCardWidth / 2 / 0.75 + + MediaQuery.textScalerOf(context).scale(50), + child: Obx( + () => _buildFollowBody(controller.followState.value), + ), ), ), ], @@ -415,31 +422,27 @@ class _BangumiPageState extends CommonPageState return switch (loadingState) { Loading() => loadingWidget, Success(:var response) => response?.isNotEmpty == true - ? MediaQuery.removePadding( - context: context, - removeLeft: context.orientation == Orientation.landscape, - child: ListView.builder( - controller: controller.followController, - scrollDirection: Axis.horizontal, - itemCount: response!.length, - itemBuilder: (context, index) { - if (index == response.length - 1) { - controller.queryBangumiFollow(false); - } - return Container( - width: Grid.smallCardWidth / 2, - margin: EdgeInsets.only( - left: StyleString.safeSpace, - right: index == response.length - 1 - ? StyleString.safeSpace - : 0, - ), - child: BangumiCardV( - bangumiItem: response[index], - ), - ); - }, - ), + ? ListView.builder( + controller: controller.followController, + scrollDirection: Axis.horizontal, + itemCount: response!.length, + itemBuilder: (context, index) { + if (index == response.length - 1) { + controller.queryBangumiFollow(false); + } + return Container( + width: Grid.smallCardWidth / 2, + margin: EdgeInsets.only( + left: StyleString.safeSpace, + right: index == response.length - 1 + ? StyleString.safeSpace + : 0, + ), + child: BangumiCardV( + bangumiItem: response[index], + ), + ); + }, ) : Center( child: Text( diff --git a/lib/pages/blacklist/view.dart b/lib/pages/blacklist/view.dart index 1ea97235c..041e355ef 100644 --- a/lib/pages/blacklist/view.dart +++ b/lib/pages/blacklist/view.dart @@ -46,7 +46,12 @@ class _BlackListPageState extends State { physics: const AlwaysScrollableScrollPhysics(), controller: _blackListController.scrollController, slivers: [ - Obx(() => _buildBody(_blackListController.loadingState.value)) + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80), + sliver: Obx( + () => _buildBody(_blackListController.loadingState.value)), + ) ], ), ), diff --git a/lib/pages/common/common_search_page.dart b/lib/pages/common/common_search_page.dart index 188d243e9..e488af865 100644 --- a/lib/pages/common/common_search_page.dart +++ b/lib/pages/common/common_search_page.dart @@ -55,7 +55,12 @@ abstract class CommonSearchPageState physics: const AlwaysScrollableScrollPhysics(), controller: controller.scrollController, slivers: [ - Obx(() => _buildBody(controller.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom + 80, + ), + sliver: Obx(() => _buildBody(controller.loadingState.value)), + ), ], ), ), diff --git a/lib/pages/dynamics_tab/view.dart b/lib/pages/dynamics_tab/view.dart index 71d87b42c..e64efde2e 100644 --- a/lib/pages/dynamics_tab/view.dart +++ b/lib/pages/dynamics_tab/view.dart @@ -124,7 +124,12 @@ class _DynamicsTabPageState physics: const AlwaysScrollableScrollPhysics(), controller: controller.scrollController, slivers: [ - Obx(() => _buildBody(controller.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80, + ), + sliver: Obx(() => _buildBody(controller.loadingState.value)), + ), ], ), ); @@ -134,57 +139,51 @@ class _DynamicsTabPageState return switch (loadingState) { Loading() => DynamicsTabPage.dynSkeleton(dynamicsWaterfallFlow), Success(:var response) => response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 80, - ), - sliver: dynamicsWaterfallFlow - ? SliverWaterfallFlow.extent( - maxCrossAxisExtent: Grid.smallCardWidth * 2, - crossAxisSpacing: StyleString.cardSpace / 2, - lastChildLayoutTypeBuilder: (index) { - if (index == response.length - 1) { - controller.onLoadMore(); - } - return index == response.length - ? LastChildLayoutType.foot - : LastChildLayoutType.none; - }, - children: [ - for (int index = 0; index < response!.length; index++) - DynamicPanel( - item: response[index], + ? dynamicsWaterfallFlow + ? SliverWaterfallFlow.extent( + maxCrossAxisExtent: Grid.smallCardWidth * 2, + crossAxisSpacing: StyleString.cardSpace / 2, + lastChildLayoutTypeBuilder: (index) { + if (index == response.length - 1) { + controller.onLoadMore(); + } + return index == response.length + ? LastChildLayoutType.foot + : LastChildLayoutType.none; + }, + children: [ + for (int index = 0; index < response!.length; index++) + DynamicPanel( + item: response[index], + onRemove: (idStr) => controller.onRemove(index, idStr), + onBlock: () => controller.onBlock(index), + ) + ], + ) + : SliverCrossAxisGroup( + slivers: [ + const SliverFillRemaining(), + SliverConstrainedCrossAxis( + maxExtent: Grid.smallCardWidth * 2, + sliver: SliverList.builder( + itemBuilder: (context, index) { + if (index == response.length - 1) { + controller.onLoadMore(); + } + final item = response[index]; + return DynamicPanel( + item: item, onRemove: (idStr) => controller.onRemove(index, idStr), onBlock: () => controller.onBlock(index), - ) - ], - ) - : SliverCrossAxisGroup( - slivers: [ - const SliverFillRemaining(), - SliverConstrainedCrossAxis( - maxExtent: Grid.smallCardWidth * 2, - sliver: SliverList.builder( - itemBuilder: (context, index) { - if (index == response.length - 1) { - controller.onLoadMore(); - } - final item = response[index]; - return DynamicPanel( - item: item, - onRemove: (idStr) => - controller.onRemove(index, idStr), - onBlock: () => controller.onBlock(index), - ); - }, - itemCount: response!.length, - ), - ), - const SliverFillRemaining(), - ], + ); + }, + itemCount: response!.length, + ), ), - ) + const SliverFillRemaining(), + ], + ) : HttpError( onReload: controller.onReload, ), diff --git a/lib/pages/dynamics_topic/view.dart b/lib/pages/dynamics_topic/view.dart index dd3a59471..b77ba5b99 100644 --- a/lib/pages/dynamics_topic/view.dart +++ b/lib/pages/dynamics_topic/view.dart @@ -109,7 +109,12 @@ class _DynTopicPageState extends State { } return const SliverToBoxAdapter(); }), - Obx(() => _buildBody(_controller.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80, + ), + sliver: Obx(() => _buildBody(_controller.loadingState.value)), + ), ], ), ), @@ -302,56 +307,51 @@ class _DynTopicPageState extends State { return switch (loadingState) { Loading() => DynamicsTabPage.dynSkeleton(dynamicsWaterfallFlow), Success(:var response) => response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 80, - ), - sliver: dynamicsWaterfallFlow - ? SliverWaterfallFlow.extent( - maxCrossAxisExtent: Grid.smallCardWidth * 2, - crossAxisSpacing: StyleString.cardSpace / 2, - lastChildLayoutTypeBuilder: (index) { - if (index == response.length - 1) { - _controller.onLoadMore(); - } - return index == response.length - ? LastChildLayoutType.foot - : LastChildLayoutType.none; - }, - children: [ - for (var item in response!) - if (item.dynamicCardItem != null) - DynamicPanel(item: item.dynamicCardItem!) - else - Text(item.topicType ?? 'err'), - ], - ) - : SliverCrossAxisGroup( - slivers: [ - const SliverFillRemaining(), - SliverConstrainedCrossAxis( - maxExtent: Grid.smallCardWidth * 2, - sliver: SliverList.builder( - itemBuilder: (context, index) { - if (index == response.length - 1) { - _controller.onLoadMore(); - } - final item = response[index]; - if (item.dynamicCardItem != null) { - return DynamicPanel( - item: item.dynamicCardItem!, - ); - } else { - return Text(item.topicType ?? 'err'); - } - }, - itemCount: response!.length, - ), - ), - const SliverFillRemaining(), - ], + ? dynamicsWaterfallFlow + ? SliverWaterfallFlow.extent( + maxCrossAxisExtent: Grid.smallCardWidth * 2, + crossAxisSpacing: StyleString.cardSpace / 2, + lastChildLayoutTypeBuilder: (index) { + if (index == response.length - 1) { + _controller.onLoadMore(); + } + return index == response.length + ? LastChildLayoutType.foot + : LastChildLayoutType.none; + }, + children: [ + for (var item in response!) + if (item.dynamicCardItem != null) + DynamicPanel(item: item.dynamicCardItem!) + else + Text(item.topicType ?? 'err'), + ], + ) + : SliverCrossAxisGroup( + slivers: [ + const SliverFillRemaining(), + SliverConstrainedCrossAxis( + maxExtent: Grid.smallCardWidth * 2, + sliver: SliverList.builder( + itemBuilder: (context, index) { + if (index == response.length - 1) { + _controller.onLoadMore(); + } + final item = response[index]; + if (item.dynamicCardItem != null) { + return DynamicPanel( + item: item.dynamicCardItem!, + ); + } else { + return Text(item.topicType ?? 'err'); + } + }, + itemCount: response!.length, + ), ), - ) + const SliverFillRemaining(), + ], + ) : HttpError( onReload: _controller.onReload, ), diff --git a/lib/pages/fan/view.dart b/lib/pages/fan/view.dart index 75e5fc8d6..d0a506608 100644 --- a/lib/pages/fan/view.dart +++ b/lib/pages/fan/view.dart @@ -61,7 +61,12 @@ class _FansPageState extends State { physics: const AlwaysScrollableScrollPhysics(), controller: _fansController.scrollController, slivers: [ - Obx(() => _buildBody(_fansController.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80), + sliver: + Obx(() => _buildBody(_fansController.loadingState.value)), + ), ], ), ), @@ -84,74 +89,70 @@ class _FansPageState extends State { ), ), Success(:var response) => response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 80), - sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: Grid.smallCardWidth * 2, - mainAxisExtent: 66, - ), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - if (index == response.length - 1) { - _fansController.onLoadMore(); - } - final item = response[index]; - String heroTag = Utils.makeHeroTag(item.mid); - return ListTile( - onTap: () { - if (widget.onSelect != null) { - widget.onSelect!(UserModel( - mid: item.mid!, - name: item.uname!, - avatar: item.face!, - )); - return; - } - Get.toNamed( - '/member?mid=${item.mid}', - arguments: {'face': item.face, 'heroTag': heroTag}, - ); - }, - onLongPress: widget.onSelect != null - ? null - : isOwner - ? () { - showConfirmDialog( - context: context, - title: '确定移除 ${item.uname} ?', - onConfirm: () { - _fansController.onRemoveFan( - index, item.mid!); - }, - ); - } - : null, - leading: Hero( - tag: heroTag, - child: NetworkImgLayer( - width: 45, - height: 45, - type: ImageType.avatar, - src: item.face, - ), + ? SliverGrid( + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: Grid.smallCardWidth * 2, + mainAxisExtent: 66, + ), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + if (index == response.length - 1) { + _fansController.onLoadMore(); + } + final item = response[index]; + String heroTag = Utils.makeHeroTag(item.mid); + return ListTile( + onTap: () { + if (widget.onSelect != null) { + widget.onSelect!(UserModel( + mid: item.mid!, + name: item.uname!, + avatar: item.face!, + )); + return; + } + Get.toNamed( + '/member?mid=${item.mid}', + arguments: {'face': item.face, 'heroTag': heroTag}, + ); + }, + onLongPress: widget.onSelect != null + ? null + : isOwner + ? () { + showConfirmDialog( + context: context, + title: '确定移除 ${item.uname} ?', + onConfirm: () { + _fansController.onRemoveFan( + index, item.mid!); + }, + ); + } + : null, + leading: Hero( + tag: heroTag, + child: NetworkImgLayer( + width: 45, + height: 45, + type: ImageType.avatar, + src: item.face, ), - title: Text( - item.uname!, - style: const TextStyle(fontSize: 14), - ), - subtitle: Text( - item.sign ?? '', - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - dense: true, - trailing: const SizedBox(width: 6), - ); - }, - childCount: response!.length, - ), + ), + title: Text( + item.uname!, + style: const TextStyle(fontSize: 14), + ), + subtitle: Text( + item.sign ?? '', + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + dense: true, + trailing: const SizedBox(width: 6), + ); + }, + childCount: response!.length, ), ) : HttpError( diff --git a/lib/pages/fav/note/child_view.dart b/lib/pages/fav/note/child_view.dart index dd65082e4..773a620f7 100644 --- a/lib/pages/fav/note/child_view.dart +++ b/lib/pages/fav/note/child_view.dart @@ -37,7 +37,12 @@ class _FavNoteChildPageState extends State onRefresh: _favNoteController.onRefresh, child: CustomScrollView( slivers: [ - Obx(() => _buildBody(_favNoteController.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80), + sliver: Obx( + () => _buildBody(_favNoteController.loadingState.value)), + ), ], ), ), @@ -139,26 +144,22 @@ class _FavNoteChildPageState extends State ), ), Success(:var response) => response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 80), - sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context), - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == response.length - 1) { - _favNoteController.onLoadMore(); - } - return FavNoteItem( - item: response[index], - ctr: _favNoteController, - onSelect: () { - _favNoteController.onSelect(index); - }, - ); - }, - childCount: response!.length, - ), + ? SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context), + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == response.length - 1) { + _favNoteController.onLoadMore(); + } + return FavNoteItem( + item: response[index], + ctr: _favNoteController, + onSelect: () { + _favNoteController.onSelect(index); + }, + ); + }, + childCount: response!.length, ), ) : HttpError(onReload: _favNoteController.onReload), diff --git a/lib/pages/fav/pgc/child_view.dart b/lib/pages/fav/pgc/child_view.dart index 511479544..bd48d31c4 100644 --- a/lib/pages/fav/pgc/child_view.dart +++ b/lib/pages/fav/pgc/child_view.dart @@ -44,7 +44,12 @@ class _FavPgcChildPageState extends State onRefresh: _favPgcController.onRefresh, child: CustomScrollView( slivers: [ - Obx(() => _buildBody(_favPgcController.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80), + sliver: Obx( + () => _buildBody(_favPgcController.loadingState.value)), + ), ], ), ), @@ -162,48 +167,44 @@ class _FavPgcChildPageState extends State ), ), Success(:var response) => response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 80), - sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context), - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == response.length - 1) { - _favPgcController.onLoadMore(); - } - final item = response[index]; - return FavPgcItem( - item: item, - ctr: _favPgcController, - onSelect: () { - _favPgcController.onSelect(index); - }, - onUpdateStatus: () { - showPgcFollowDialog( - context: context, - type: widget.type == 0 ? '追番' : '追剧', - followStatus: widget.followStatus, - onUpdateStatus: (followStatus) { - if (followStatus == -1) { - _favPgcController.bangumiDel( - index, - item.seasonId, - ); - } else { - _favPgcController.onUpdate( - index, - followStatus, - item.seasonId, - ); - } - }, - ); - }, - ); - }, - childCount: response!.length, - ), + ? SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context), + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == response.length - 1) { + _favPgcController.onLoadMore(); + } + final item = response[index]; + return FavPgcItem( + item: item, + ctr: _favPgcController, + onSelect: () { + _favPgcController.onSelect(index); + }, + onUpdateStatus: () { + showPgcFollowDialog( + context: context, + type: widget.type == 0 ? '追番' : '追剧', + followStatus: widget.followStatus, + onUpdateStatus: (followStatus) { + if (followStatus == -1) { + _favPgcController.bangumiDel( + index, + item.seasonId, + ); + } else { + _favPgcController.onUpdate( + index, + followStatus, + item.seasonId, + ); + } + }, + ); + }, + ); + }, + childCount: response!.length, ), ) : HttpError(onReload: _favPgcController.onReload), diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index 3b7f9928b..8c8080d1f 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -70,8 +70,13 @@ class _FavDetailPageState extends State { controller: _favDetailController.scrollController, slivers: [ _buildHeader(theme), - Obx(() => _buildBody( - theme, _favDetailController.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom + 85, + ), + sliver: Obx(() => _buildBody( + theme, _favDetailController.loadingState.value)), + ), ], ), ), @@ -365,123 +370,116 @@ class _FavDetailPageState extends State { ), ), Success(:var response) => response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 85, - ), - sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context), - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == response.length) { - _favDetailController.onLoadMore(); - return Container( - height: 60, - alignment: Alignment.center, - child: Text( - _favDetailController.isEnd ? '没有更多了' : '加载中...', - style: TextStyle( - color: theme.colorScheme.outline, - fontSize: 13, - ), + ? SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context), + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == response.length) { + _favDetailController.onLoadMore(); + return Container( + height: 60, + alignment: Alignment.center, + child: Text( + _favDetailController.isEnd ? '没有更多了' : '加载中...', + style: TextStyle( + color: theme.colorScheme.outline, + fontSize: 13, ), - ); - } - FavDetailItemData item = response[index]; - return Stack( - clipBehavior: Clip.none, - children: [ - Positioned.fill( - child: FavVideoCardH( - videoItem: item, - onDelFav: _favDetailController.isOwner.value - ? () => _favDetailController.onCancelFav( - index, - item.id!, - item.type!, - ) - : null, - onViewFav: () { - PageUtils.toVideoPage( - 'bvid=${item.bvid}&cid=${item.cid}', - arguments: { - 'videoItem': item, - 'heroTag': Utils.makeHeroTag(item.bvid), - 'sourceType': 'fav', - 'mediaId': _favDetailController.item.value.id, - 'oid': item.id, - 'favTitle': - _favDetailController.item.value.title, - 'count': _favDetailController - .item.value.mediaCount, - 'desc': true, - 'isContinuePlaying': index != 0, - 'isOwner': _favDetailController.isOwner.value, - }, - ); - }, - onTap: _favDetailController.enableMultiSelect.value - ? () { + ), + ); + } + FavDetailItemData item = response[index]; + return Stack( + clipBehavior: Clip.none, + children: [ + Positioned.fill( + child: FavVideoCardH( + videoItem: item, + onDelFav: _favDetailController.isOwner.value + ? () => _favDetailController.onCancelFav( + index, + item.id!, + item.type!, + ) + : null, + onViewFav: () { + PageUtils.toVideoPage( + 'bvid=${item.bvid}&cid=${item.cid}', + arguments: { + 'videoItem': item, + 'heroTag': Utils.makeHeroTag(item.bvid), + 'sourceType': 'fav', + 'mediaId': _favDetailController.item.value.id, + 'oid': item.id, + 'favTitle': + _favDetailController.item.value.title, + 'count': + _favDetailController.item.value.mediaCount, + 'desc': true, + 'isContinuePlaying': index != 0, + 'isOwner': _favDetailController.isOwner.value, + }, + ); + }, + onTap: _favDetailController.enableMultiSelect.value + ? () { + _favDetailController.onSelect(index); + } + : null, + onLongPress: _favDetailController.isOwner.value + ? () { + if (_favDetailController + .enableMultiSelect.value.not) { + _favDetailController + .enableMultiSelect.value = true; _favDetailController.onSelect(index); } - : null, - onLongPress: _favDetailController.isOwner.value - ? () { - if (_favDetailController - .enableMultiSelect.value.not) { - _favDetailController - .enableMultiSelect.value = true; - _favDetailController.onSelect(index); - } - } - : null, - ), + } + : null, ), - Positioned( - top: 5, - left: 12, - bottom: 5, - child: IgnorePointer( - child: LayoutBuilder( - builder: (context, constraints) => - AnimatedOpacity( - opacity: item.checked == true ? 1 : 0, - duration: const Duration(milliseconds: 200), - child: Container( - alignment: Alignment.center, - height: constraints.maxHeight, - width: constraints.maxHeight * - StyleString.aspectRatio, - decoration: BoxDecoration( - borderRadius: StyleString.mdRadius, - color: Colors.black.withValues(alpha: 0.6), - ), - child: SizedBox( - width: 34, - height: 34, - child: AnimatedScale( - scale: item.checked == true ? 1 : 0, - duration: - const Duration(milliseconds: 250), - curve: Curves.easeInOut, - child: IconButton( - style: ButtonStyle( - padding: WidgetStateProperty.all( - EdgeInsets.zero), - backgroundColor: - WidgetStateProperty.resolveWith( - (states) { - return theme.colorScheme.surface - .withValues(alpha: 0.8); - }, - ), - ), - onPressed: null, - icon: Icon( - Icons.done_all_outlined, - color: theme.colorScheme.primary, + ), + Positioned( + top: 5, + left: 12, + bottom: 5, + child: IgnorePointer( + child: LayoutBuilder( + builder: (context, constraints) => AnimatedOpacity( + opacity: item.checked == true ? 1 : 0, + duration: const Duration(milliseconds: 200), + child: Container( + alignment: Alignment.center, + height: constraints.maxHeight, + width: constraints.maxHeight * + StyleString.aspectRatio, + decoration: BoxDecoration( + borderRadius: StyleString.mdRadius, + color: Colors.black.withValues(alpha: 0.6), + ), + child: SizedBox( + width: 34, + height: 34, + child: AnimatedScale( + scale: item.checked == true ? 1 : 0, + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + child: IconButton( + style: ButtonStyle( + padding: WidgetStateProperty.all( + EdgeInsets.zero), + backgroundColor: + WidgetStateProperty.resolveWith( + (states) { + return theme.colorScheme.surface + .withValues(alpha: 0.8); + }, ), ), + onPressed: null, + icon: Icon( + Icons.done_all_outlined, + color: theme.colorScheme.primary, + ), ), ), ), @@ -489,11 +487,11 @@ class _FavDetailPageState extends State { ), ), ), - ], - ); - }, - childCount: response!.length + 1, - ), + ), + ], + ); + }, + childCount: response!.length + 1, ), ) : HttpError( diff --git a/lib/pages/fav_search/view.dart b/lib/pages/fav_search/view.dart index dbf42fbcb..fb2ecfacd 100644 --- a/lib/pages/fav_search/view.dart +++ b/lib/pages/fav_search/view.dart @@ -25,49 +25,44 @@ class _FavSearchPageState extends CommonSearchPageState list) { - return SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 80, - ), - sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), - delegate: SliverChildBuilderDelegate( - childCount: list.length, - (context, index) { - if (index == list.length - 1) { - controller.onLoadMore(); - } - final item = list[index]; - return FavVideoCardH( - videoItem: item, - onDelFav: controller.isOwner == true - ? () { - controller.onCancelFav( - index, - item.id!, - item.type, - ); - } - : null, - onViewFav: () { - PageUtils.toVideoPage( - 'bvid=${item.bvid}&cid=${item.cid}', - arguments: { - 'videoItem': item, - 'heroTag': Utils.makeHeroTag(item.bvid), - 'sourceType': 'fav', - 'mediaId': controller.mediaId, - 'oid': item.id, - 'favTitle': controller.title, - 'count': controller.count, - 'desc': true, - 'isContinuePlaying': true, - }, - ); - }, - ); - }, - ), + return SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), + delegate: SliverChildBuilderDelegate( + childCount: list.length, + (context, index) { + if (index == list.length - 1) { + controller.onLoadMore(); + } + final item = list[index]; + return FavVideoCardH( + videoItem: item, + onDelFav: controller.isOwner == true + ? () { + controller.onCancelFav( + index, + item.id!, + item.type, + ); + } + : null, + onViewFav: () { + PageUtils.toVideoPage( + 'bvid=${item.bvid}&cid=${item.cid}', + arguments: { + 'videoItem': item, + 'heroTag': Utils.makeHeroTag(item.bvid), + 'sourceType': 'fav', + 'mediaId': controller.mediaId, + 'oid': item.id, + 'favTitle': controller.title, + 'count': controller.count, + 'desc': true, + 'isContinuePlaying': true, + }, + ); + }, + ); + }, ), ); } diff --git a/lib/pages/follow_search/view.dart b/lib/pages/follow_search/view.dart index 115dfff84..15dba147d 100644 --- a/lib/pages/follow_search/view.dart +++ b/lib/pages/follow_search/view.dart @@ -30,26 +30,21 @@ class _FollowSearchPageState extends CommonSearchPageState list) { - return SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 80, - ), - sliver: SliverList.builder( - itemCount: list.length, - itemBuilder: ((context, index) { - if (index == list.length - 1) { - controller.onLoadMore(); - } - return FollowItem( - item: list[index], - onSelect: widget.mid != null && widget.isFromSelect != false - ? (userModel) { - Get.back(result: userModel); - } - : null, - ); - }), - ), + return SliverList.builder( + itemCount: list.length, + itemBuilder: ((context, index) { + if (index == list.length - 1) { + controller.onLoadMore(); + } + return FollowItem( + item: list[index], + onSelect: widget.mid != null && widget.isFromSelect != false + ? (userModel) { + Get.back(result: userModel); + } + : null, + ); + }), ); } } diff --git a/lib/pages/history_search/view.dart b/lib/pages/history_search/view.dart index dd7f5f795..8504fb70a 100644 --- a/lib/pages/history_search/view.dart +++ b/lib/pages/history_search/view.dart @@ -24,29 +24,24 @@ class _HistorySearchPageState @override Widget buildList(List list) { - return SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 80, - ), - sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), - delegate: SliverChildBuilderDelegate( - childCount: list.length, - (context, index) { - if (index == list.length - 1) { - controller.onLoadMore(); - } - final item = list[index]; - return HistoryItem( - videoItem: item, - ctr: controller, - onChoose: null, - onDelete: (kid, business) { - controller.onDelHistory(index, kid, business); - }, - ); - }, - ), + return SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), + delegate: SliverChildBuilderDelegate( + childCount: list.length, + (context, index) { + if (index == list.length - 1) { + controller.onLoadMore(); + } + final item = list[index]; + return HistoryItem( + videoItem: item, + ctr: controller, + onChoose: null, + onDelete: (kid, business) { + controller.onDelHistory(index, kid, business); + }, + ); + }, ), ); } diff --git a/lib/pages/later_search/view.dart b/lib/pages/later_search/view.dart index 86cb88f14..3c8ad2282 100644 --- a/lib/pages/later_search/view.dart +++ b/lib/pages/later_search/view.dart @@ -26,64 +26,59 @@ class _LaterSearchPageState @override Widget buildList(List list) { - return SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 80, - ), - sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), - delegate: SliverChildBuilderDelegate( - childCount: list.length, - (context, index) { - if (index == list.length - 1) { - controller.onLoadMore(); - } - final item = list[index]; - return Stack( - clipBehavior: Clip.none, - children: [ - VideoCardH( - videoItem: item, - source: 'later', - onViewLater: (cid) { - PageUtils.toVideoPage( - 'bvid=${item.bvid}&cid=$cid', - arguments: { - 'videoItem': item, - 'oid': item.aid, - 'heroTag': Utils.makeHeroTag(item.bvid), - 'sourceType': 'watchLater', - 'count': controller.count, - 'favTitle': '稍后再看', - 'mediaId': controller.mid, - 'desc': false, - 'isContinuePlaying': index != 0, - }, + return SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), + delegate: SliverChildBuilderDelegate( + childCount: list.length, + (context, index) { + if (index == list.length - 1) { + controller.onLoadMore(); + } + final item = list[index]; + return Stack( + clipBehavior: Clip.none, + children: [ + VideoCardH( + videoItem: item, + source: 'later', + onViewLater: (cid) { + PageUtils.toVideoPage( + 'bvid=${item.bvid}&cid=$cid', + arguments: { + 'videoItem': item, + 'oid': item.aid, + 'heroTag': Utils.makeHeroTag(item.bvid), + 'sourceType': 'watchLater', + 'count': controller.count, + 'favTitle': '稍后再看', + 'mediaId': controller.mid, + 'desc': false, + 'isContinuePlaying': index != 0, + }, + ); + }, + ), + Positioned( + right: 12, + bottom: 0, + child: iconButton( + tooltip: '移除', + context: context, + onPressed: () { + controller.toViewDel( + context, + index, + item.aid, ); }, + icon: Icons.clear, + iconColor: Theme.of(context).colorScheme.onSurfaceVariant, + bgColor: Colors.transparent, ), - Positioned( - right: 12, - bottom: 0, - child: iconButton( - tooltip: '移除', - context: context, - onPressed: () { - controller.toViewDel( - context, - index, - item.aid, - ); - }, - icon: Icons.clear, - iconColor: Theme.of(context).colorScheme.onSurfaceVariant, - bgColor: Colors.transparent, - ), - ), - ], - ); - }, - ), + ), + ], + ); + }, ), ); } diff --git a/lib/pages/member_favorite/view.dart b/lib/pages/member_favorite/view.dart index 9376528eb..2866bff88 100644 --- a/lib/pages/member_favorite/view.dart +++ b/lib/pages/member_favorite/view.dart @@ -41,7 +41,14 @@ class _MemberFavoriteState extends State return refreshIndicator( onRefresh: _controller.onRefresh, child: CustomScrollView( - slivers: [Obx(() => _buildBody(theme, _controller.loadingState.value))], + slivers: [ + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80), + sliver: + Obx(() => _buildBody(theme, _controller.loadingState.value)), + ), + ], ), ); } @@ -68,11 +75,6 @@ class _MemberFavoriteState extends State child: Obx( () => _buildItem(theme, _controller.second.value, false)), ), - SliverToBoxAdapter( - child: SizedBox( - height: 80 + MediaQuery.of(context).padding.bottom, - ), - ), ], ) : HttpError( diff --git a/lib/pages/member_video/view.dart b/lib/pages/member_video/view.dart index c945d83f6..b819d2b8d 100644 --- a/lib/pages/member_video/view.dart +++ b/lib/pages/member_video/view.dart @@ -219,7 +219,7 @@ class _MemberVideoState extends State } final SpaceArchiveItem item = response[index]; return VideoCardHMemberVideo( - key: ValueKey('${item.param}'), + // key: ValueKey('${item.param}'), videoItem: item, fromViewAid: _controller.fromViewAid, ); diff --git a/lib/pages/search_trending/view.dart b/lib/pages/search_trending/view.dart index bbe05986c..10edf8f0e 100644 --- a/lib/pages/search_trending/view.dart +++ b/lib/pages/search_trending/view.dart @@ -121,8 +121,12 @@ class _SearchTrendingPageState extends State { filterQuality: FilterQuality.low, ), ), - Obx(() => - _buildBody(theme, _controller.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 100), + sliver: Obx(() => + _buildBody(theme, _controller.loadingState.value)), + ), ], ), ), @@ -138,77 +142,73 @@ class _SearchTrendingPageState extends State { return switch (loadingState) { Loading() => const SliverToBoxAdapter(child: LinearProgressIndicator()), Success(:var response) => response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 100), - sliver: SliverList.separated( - itemCount: response!.length, - itemBuilder: (context, index) { - final item = response[index]; - return ListTile( - dense: true, - onTap: () { - Get.toNamed( - '/searchResult', - parameters: { - 'keyword': item.keyword!, - }, - ); - }, - leading: index < _controller.topCount - ? const Icon( - size: 17, - Icons.vertical_align_top_outlined, - color: Color(0xFFd1403e), - ) - : Text( - '${index + 1 - _controller.topCount}', - style: TextStyle( - fontWeight: FontWeight.bold, - color: switch (index - _controller.topCount) { - 0 => const Color(0xFFfdad13), - 1 => const Color(0xFF8aace1), - 2 => const Color(0xFFdfa777), - _ => theme.colorScheme.outline, - }, - fontSize: 17, - fontStyle: FontStyle.italic, - ), - ), - title: Row( - children: [ - Flexible( - child: Text( - item.keyword!, - maxLines: 1, - overflow: TextOverflow.ellipsis, - strutStyle: const StrutStyle(height: 1, leading: 0), - style: const TextStyle(height: 1, fontSize: 15), + ? SliverList.separated( + itemCount: response!.length, + itemBuilder: (context, index) { + final item = response[index]; + return ListTile( + dense: true, + onTap: () { + Get.toNamed( + '/searchResult', + parameters: { + 'keyword': item.keyword!, + }, + ); + }, + leading: index < _controller.topCount + ? const Icon( + size: 17, + Icons.vertical_align_top_outlined, + color: Color(0xFFd1403e), + ) + : Text( + '${index + 1 - _controller.topCount}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: switch (index - _controller.topCount) { + 0 => const Color(0xFFfdad13), + 1 => const Color(0xFF8aace1), + 2 => const Color(0xFFdfa777), + _ => theme.colorScheme.outline, + }, + fontSize: 17, + fontStyle: FontStyle.italic, ), ), - if (item.icon?.isNotEmpty == true) ...[ - const SizedBox(width: 4), - CachedNetworkImage( - imageUrl: Utils.thumbnailImgUrl(item.icon!), - height: 16, - ), - ] else if (item.showLiveIcon == true) ...[ - const SizedBox(width: 4), - Image.asset( - 'assets/images/live/live.gif', - width: 51, - height: 16, - ), - ], + title: Row( + children: [ + Flexible( + child: Text( + item.keyword!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + strutStyle: const StrutStyle(height: 1, leading: 0), + style: const TextStyle(height: 1, fontSize: 15), + ), + ), + if (item.icon?.isNotEmpty == true) ...[ + const SizedBox(width: 4), + CachedNetworkImage( + imageUrl: Utils.thumbnailImgUrl(item.icon!), + height: 16, + ), + ] else if (item.showLiveIcon == true) ...[ + const SizedBox(width: 4), + Image.asset( + 'assets/images/live/live.gif', + width: 51, + height: 16, + ), ], - ), - ); - }, - separatorBuilder: (context, index) => Divider( - height: 1, - indent: 48, - color: theme.colorScheme.outline.withValues(alpha: 0.1), - ), + ], + ), + ); + }, + separatorBuilder: (context, index) => Divider( + height: 1, + indent: 48, + color: theme.colorScheme.outline.withValues(alpha: 0.1), ), ) : HttpError( diff --git a/lib/pages/settings_search/view.dart b/lib/pages/settings_search/view.dart index e27ad13a4..4e6faed2c 100644 --- a/lib/pages/settings_search/view.dart +++ b/lib/pages/settings_search/view.dart @@ -82,20 +82,20 @@ class _SettingsSearchPageState extends State { bottom: false, child: CustomScrollView( slivers: [ - Obx( - () => _list.isEmpty - ? const HttpError() - : SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 80, - ), - sliver: SliverWaterfallFlow.extent( + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80, + ), + sliver: Obx( + () => _list.isEmpty + ? const HttpError() + : SliverWaterfallFlow.extent( maxCrossAxisExtent: Grid.smallCardWidth * 2, children: [ ..._list.map((item) => item.widget), ], ), - ), + ), ), ], ), diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index afcf2ca35..ad4b30a7d 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -40,7 +40,13 @@ class _SubDetailPageState extends State { slivers: [ _buildAppBar(theme), _buildCount(theme), - Obx(() => _buildBody(_subDetailController.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80, + ), + sliver: Obx( + () => _buildBody(_subDetailController.loadingState.value)), + ), ], ), ), @@ -58,23 +64,18 @@ class _SubDetailPageState extends State { ), ), Success(:var response) => response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 80, - ), - sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context), - delegate: SliverChildBuilderDelegate( - childCount: response!.length, - (context, index) { - if (index == response.length - 1) { - _subDetailController.onLoadMore(); - } - return SubVideoCardH( - videoItem: response[index], - ); - }, - ), + ? SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context), + delegate: SliverChildBuilderDelegate( + childCount: response!.length, + (context, index) { + if (index == response.length - 1) { + _subDetailController.onLoadMore(); + } + return SubVideoCardH( + videoItem: response[index], + ); + }, ), ) : HttpError( diff --git a/lib/pages/video/medialist/view.dart b/lib/pages/video/medialist/view.dart index d7a9d5daf..a1dae0f94 100644 --- a/lib/pages/video/medialist/view.dart +++ b/lib/pages/video/medialist/view.dart @@ -155,7 +155,7 @@ class _MediaListPanelState widget.loadMoreMedia(); } return SizedBox( - key: ValueKey('${item.aid}'), + // key: ValueKey('${item.aid}'), height: 98, child: InkWell( onTap: () async { diff --git a/lib/pages/video/member/controller.dart b/lib/pages/video/member/controller.dart index ef759b62e..4dfe927df 100644 --- a/lib/pages/video/member/controller.dart +++ b/lib/pages/video/member/controller.dart @@ -4,16 +4,16 @@ import 'package:PiliPlus/models/common/member/contribute_type.dart'; import 'package:PiliPlus/models/member/info.dart'; import 'package:PiliPlus/models/space_archive/data.dart'; import 'package:PiliPlus/models/space_archive/item.dart'; -import 'package:PiliPlus/pages/common/common_data_controller.dart'; +import 'package:PiliPlus/pages/common/common_list_controller.dart'; +import 'package:PiliPlus/utils/extension.dart'; import 'package:get/get.dart'; -class HorizontalMemberPageController extends CommonDataController { - HorizontalMemberPageController({this.mid, required this.lastAid}); +class HorizontalMemberPageController + extends CommonListController { + HorizontalMemberPageController({this.mid, required this.currAid}); dynamic mid; - int currentPage = 0; - Rx> userState = LoadingState.loading().obs; RxMap userStat = {}.obs; @@ -54,27 +54,29 @@ class HorizontalMemberPageController extends CommonDataController { bool customHandleResponse(bool isRefresh, Success response) { SpaceArchiveData data = response.response; count.value = data.count ?? -1; - if (currentPage == 0 || isLoadPrevious) { - hasPrev = data.hasPrev ?? false; - } - if (currentPage == 0 || !isLoadPrevious) { - hasNext = data.hasNext ?? false; - } - if (currentPage != 0 && loadingState.value is Success) { - data.item ??= []; + if (isRefresh) { if (isLoadPrevious) { - data.item!.addAll((loadingState.value as Success).response); + hasPrev = data.hasPrev ?? false; } else { - data.item!.insertAll(0, (loadingState.value as Success).response); + hasNext = data.hasNext ?? false; } } + if (isLoadPrevious && loadingState.value is Success) { + data.item ??= []; + data.item!.addAll((loadingState.value as Success).response); + } else if (!isRefresh && loadingState.value is Success) { + data.item ??= []; + data.item!.insertAll(0, (loadingState.value as Success).response); + } firstAid = data.item?.firstOrNull?.param; lastAid = data.item?.lastOrNull?.param; loadingState.value = Success(data.item); isLoadPrevious = false; + page++; return true; } + String? currAid; String? firstAid; String? lastAid; RxString order = 'pubdate'.obs; @@ -84,27 +86,45 @@ class HorizontalMemberPageController extends CommonDataController { bool hasNext = true; @override - Future customGetData() => MemberHttp.spaceArchive( + Future> customGetData() => + MemberHttp.spaceArchive( type: ContributeType.video, mid: mid, - aid: isLoadPrevious ? firstAid : lastAid, + aid: page == 1 + ? currAid + : isLoadPrevious + ? firstAid + : lastAid, order: order.value, - sort: isLoadPrevious ? 'asc' : null, + sort: page != 1 && isLoadPrevious ? 'asc' : null, pn: null, next: null, seasonId: null, seriesId: null, - includeCursor: currentPage == 0 ? true : null, + includeCursor: page == 1 ? true : null, ); @override Future onRefresh() { - currentPage = 0; - hasPrev = true; - hasNext = true; + if (!hasPrev) { + return Future.value(); + } + isLoadPrevious = true; return queryData(); } + @override + Future onReload() { + firstAid = null; + lastAid = null; + hasNext = true; + hasPrev = true; + isEnd = false; + page = 1; + scrollController.jumpToTop(); + return super.onReload(); + } + void queryBySort() { order.value = order.value == 'pubdate' ? 'click' : 'pubdate'; onReload(); diff --git a/lib/pages/video/member/view.dart b/lib/pages/video/member/view.dart index 5352a56d9..157887785 100644 --- a/lib/pages/video/member/view.dart +++ b/lib/pages/video/member/view.dart @@ -1,8 +1,10 @@ +import 'package:PiliPlus/common/skeleton/video_card_h.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; +import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; -import 'package:PiliPlus/common/widgets/scroll_physics.dart'; +import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/video_card/video_card_h_member_video.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart'; @@ -49,31 +51,12 @@ class _HorizontalMemberPageState extends State { _controller = Get.put( HorizontalMemberPageController( mid: widget.mid, - lastAid: widget.videoDetailController.oid.value.toString(), + currAid: widget.videoDetailController.oid.value.toString(), ), tag: widget.videoDetailController.heroTag, ); _bvid = widget.videoDetailController.bvid; _ownerMid = Accounts.main.mid; - if (_controller.hasPrev) { - _controller.scrollController.addListener(listener); - } - } - - void listener() { - if (_controller.scrollController.position.pixels == 0) { - if (_controller.hasPrev) { - _controller - ..isLoadPrevious = true - ..onLoadMore(); - } - } - } - - @override - void dispose() { - _controller.scrollController.removeListener(listener); - super.dispose(); } @override @@ -104,10 +87,22 @@ class _HorizontalMemberPageState extends State { ], ), _buildUserInfo(theme, response), - const SizedBox(height: 5), Expanded( - child: Obx( - () => _buildVideoList(theme, _controller.loadingState.value)), + child: refreshIndicator( + onRefresh: _controller.onRefresh, + child: CustomScrollView( + controller: _controller.scrollController, + // physics: PositionRetainedScrollPhysics( + // shouldRetain: _controller.hasPrev, + // parent: const ClampingScrollPhysics(), + // ), + slivers: [ + _buildSliverHeader(theme), + Obx(() => + _buildVideoList(theme, _controller.loadingState.value)), + ], + ), + ), ), ], ), @@ -176,33 +171,34 @@ class _HorizontalMemberPageState extends State { ); } - Widget _buildVideoList(ThemeData theme, LoadingState loadingState) { + Widget _buildVideoList( + ThemeData theme, LoadingState?> loadingState) { return switch (loadingState) { - Loading() => loadingWidget, - Success(:var response) => Material( - color: Colors.transparent, - child: CustomScrollView( - controller: _controller.scrollController, - physics: PositionRetainedScrollPhysics( - shouldRetain: _controller.hasPrev, - parent: const ClampingScrollPhysics(), - ), - slivers: [ - _buildSliverHeader(theme), - SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 80, - ), - sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context), - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == response.length - 1 && _controller.hasNext) { - _controller.onLoadMore(); - } - final SpaceArchiveItem videoItem = response[index]; - return VideoCardHMemberVideo( - key: ValueKey('${videoItem.param}'), + Loading() => SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context), + delegate: SliverChildBuilderDelegate( + childCount: 10, + (context, index) { + return const VideoCardHSkeleton(); + }, + ), + ), + Success(:var response) => response?.isNotEmpty == true + ? SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom + 80, + ), + sliver: SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context), + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == response.length - 1 && _controller.hasNext) { + _controller.onLoadMore(); + } + final SpaceArchiveItem videoItem = response[index]; + return Material( + color: Colors.transparent, + child: VideoCardHMemberVideo( videoItem: videoItem, bvid: _bvid, onTap: () { @@ -219,17 +215,15 @@ class _HorizontalMemberPageState extends State { setState(() {}); } }, - ); - }, - childCount: response.length, - ), + ), + ); + }, + childCount: response!.length, ), ), - ], - ), - ), - Error(:var errMsg) => scrollErrorWidget( - controller: _controller.scrollController, + ) + : HttpError(onReload: _controller.onReload), + Error(:var errMsg) => HttpError( errMsg: errMsg, onReload: _controller.onReload, ), diff --git a/lib/pages/video/note/view.dart b/lib/pages/video/note/view.dart index 620e22006..6e7b081d6 100644 --- a/lib/pages/video/note/view.dart +++ b/lib/pages/video/note/view.dart @@ -10,7 +10,7 @@ import 'package:PiliPlus/pages/video/note/controller.dart'; import 'package:PiliPlus/pages/webview/view.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/extension.dart'; -import 'package:PiliPlus/utils/storage.dart'; +import 'package:PiliPlus/utils/storage.dart' show Accounts; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -84,52 +84,73 @@ class _NoteListPageState extends CommonSlidePageState { const SizedBox(width: 16), ], ), - body: enableSlide - ? slideList(theme, - Obx(() => _buildBody(theme, _controller.loadingState.value))) - : Obx(() => _buildBody(theme, _controller.loadingState.value)), - bottomNavigationBar: Container( - padding: EdgeInsets.only( - left: 12, - right: 12, - top: 6, - bottom: MediaQuery.paddingOf(context).bottom + 6, - ), - width: double.infinity, - decoration: BoxDecoration( - color: theme.colorScheme.onInverseSurface, - border: Border( - top: BorderSide( - width: 0.5, - color: theme.colorScheme.outline.withValues(alpha: 0.1), - ), - ), - ), - child: FilledButton.tonal( - style: FilledButton.styleFrom( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - padding: EdgeInsets.zero, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(6)), - ), - ), - onPressed: () { - if (!Accounts.main.isLogin) { - SmartDialog.showToast('账号未登录'); - return; - } - _key.currentState?.showBottomSheet( - (context) => WebviewPage( - oid: widget.oid, - title: widget.title, - url: - 'https://www.bilibili.com/h5/note-app?oid=${widget.oid}&pagefrom=ugcvideo&is_stein_gate=${widget.isStein ? 1 : 0}', + body: enableSlide ? slideList(theme) : buildList(theme), + ), + ); + } + + @override + Widget buildList(ThemeData theme) { + return refreshIndicator( + onRefresh: _controller.onRefresh, + child: Column( + children: [ + Expanded( + child: CustomScrollView( + controller: _controller.scrollController, + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverPadding( + padding: const EdgeInsets.only(bottom: 80), + sliver: Obx( + () => _buildBody(theme, _controller.loadingState.value)), ), - ); - }, - child: const Text('开始记笔记'), + ], + ), ), - ), + Container( + padding: EdgeInsets.only( + left: 12, + right: 12, + top: 6, + bottom: MediaQuery.paddingOf(context).bottom + 6, + ), + width: double.infinity, + decoration: BoxDecoration( + color: theme.colorScheme.onInverseSurface, + border: Border( + top: BorderSide( + width: 0.5, + color: theme.colorScheme.outline.withValues(alpha: 0.1), + ), + ), + ), + child: FilledButton.tonal( + style: FilledButton.styleFrom( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + padding: EdgeInsets.zero, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6)), + ), + ), + onPressed: () { + if (!Accounts.main.isLogin) { + SmartDialog.showToast('账号未登录'); + return; + } + _key.currentState?.showBottomSheet( + (context) => WebviewPage( + oid: widget.oid, + title: widget.title, + url: + 'https://www.bilibili.com/h5/note-app?oid=${widget.oid}&pagefrom=ugcvideo&is_stein_gate=${widget.isStein ? 1 : 0}', + ), + ); + }, + child: const Text('开始记笔记'), + ), + ), + ], ), ); } @@ -137,59 +158,37 @@ class _NoteListPageState extends CommonSlidePageState { Widget _buildBody( ThemeData theme, LoadingState?> loadingState) { return switch (loadingState) { - Loading() => CustomScrollView( - physics: const NeverScrollableScrollPhysics(), - slivers: [ - SliverList.builder( - itemBuilder: (context, index) { - return const VideoReplySkeleton(); - }, - itemCount: 8, - ) - ], + Loading() => SliverToBoxAdapter( + child: ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return const VideoReplySkeleton(); + }, + itemCount: 8, + ), ), Success(:var response) => response?.isNotEmpty == true - ? refreshIndicator( - onRefresh: _controller.onRefresh, - child: CustomScrollView( - controller: _controller.scrollController, - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - SliverList.separated( - itemBuilder: (context, index) { - if (index == response.length - 1) { - _controller.onLoadMore(); - } - return _itemWidget(context, theme, response[index]); - }, - itemCount: response!.length, - separatorBuilder: (context, index) => Divider( - height: 1, - color: theme.colorScheme.outline.withValues(alpha: 0.1), - ), - ), - SliverToBoxAdapter( - child: SizedBox( - height: MediaQuery.paddingOf(context).bottom + 80, - ), - ), - ], + ? SliverList.separated( + itemBuilder: (context, index) { + if (index == response.length - 1) { + _controller.onLoadMore(); + } + return _itemWidget(context, theme, response[index]); + }, + itemCount: response!.length, + separatorBuilder: (context, index) => Divider( + height: 1, + color: theme.colorScheme.outline.withValues(alpha: 0.1), ), ) - : errWidget(), - Error(:var errMsg) => errWidget(errMsg), + : HttpError(onReload: _controller.onReload), + Error(:var errMsg) => HttpError( + errMsg: errMsg, + onReload: _controller.onReload, + ), }; } - - Widget errWidget([errMsg]) => CustomScrollView( - controller: _controller.scrollController, - slivers: [ - HttpError( - errMsg: errMsg, - onReload: _controller.onReload, - ) - ], - ); } Widget _itemWidget(BuildContext context, ThemeData theme, dynamic item) { diff --git a/lib/pages/video/reply_reply/view.dart b/lib/pages/video/reply_reply/view.dart index 989f4e213..84479f748 100644 --- a/lib/pages/video/reply_reply/view.dart +++ b/lib/pages/video/reply_reply/view.dart @@ -387,17 +387,13 @@ class _VideoReplyReplyPanelState ThemeData theme, LoadingState?> loadingState, int index) { return switch (loadingState) { Loading() => IgnorePointer( - child: CustomScrollView( + child: ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - slivers: [ - SliverList.builder( - itemBuilder: (context, index) { - return const VideoReplySkeleton(); - }, - itemCount: 8, - ) - ], + itemBuilder: (context, index) { + return const VideoReplySkeleton(); + }, + itemCount: 8, ), ), Success(:var response) => () { diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart index bceb59bd2..5e9201217 100644 --- a/lib/pages/whisper_detail/view.dart +++ b/lib/pages/whisper_detail/view.dart @@ -123,8 +123,11 @@ class _WhisperDetailPageState hidePanel(); }, behavior: HitTestBehavior.opaque, - child: Obx(() => - _buildBody(_whisperDetailController.loadingState.value)), + child: refreshIndicator( + onRefresh: _whisperDetailController.onRefresh, + child: Obx(() => + _buildBody(_whisperDetailController.loadingState.value)), + ), ), ), if (_whisperDetailController.mid != null) ...[ @@ -142,66 +145,63 @@ class _WhisperDetailPageState return switch (loadingState) { Loading() => loadingWidget, Success(:var response) => response?.isNotEmpty == true - ? refreshIndicator( - onRefresh: _whisperDetailController.onRefresh, - child: ListView.separated( - shrinkWrap: true, - reverse: true, - itemCount: response!.length, - padding: const EdgeInsets.all(12), - physics: const AlwaysScrollableScrollPhysics( - parent: ClampingScrollPhysics(), - ), - controller: _whisperDetailController.scrollController, - itemBuilder: (context, int index) { - if (index == response.length - 1) { - _whisperDetailController.onLoadMore(); - } - final item = response[index]; - return ChatItem( - item: item, - eInfos: _whisperDetailController.eInfos, - onLongPress: item.senderUid == - _whisperDetailController.ownerMid - ? () { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - clipBehavior: Clip.hardEdge, - contentPadding: - const EdgeInsets.symmetric(vertical: 12), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - onTap: () { - Get.back(); - _whisperDetailController.sendMsg( - message: '${item.msgKey}', - onClearText: editController.clear, - msgType: 5, - index: index, - ); - }, - dense: true, - title: const Text( - '撤回', - style: TextStyle(fontSize: 14), - ), - ), - ], - ), - ); - }, - ); - } - : null, - ); - }, - separatorBuilder: (BuildContext context, int index) => - const SizedBox(height: 12), + ? ListView.separated( + shrinkWrap: true, + reverse: true, + itemCount: response!.length, + padding: const EdgeInsets.all(12), + physics: const AlwaysScrollableScrollPhysics( + parent: ClampingScrollPhysics(), ), + controller: _whisperDetailController.scrollController, + itemBuilder: (context, int index) { + if (index == response.length - 1) { + _whisperDetailController.onLoadMore(); + } + final item = response[index]; + return ChatItem( + item: item, + eInfos: _whisperDetailController.eInfos, + onLongPress: item.senderUid == + _whisperDetailController.ownerMid + ? () { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + clipBehavior: Clip.hardEdge, + contentPadding: + const EdgeInsets.symmetric(vertical: 12), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + onTap: () { + Get.back(); + _whisperDetailController.sendMsg( + message: '${item.msgKey}', + onClearText: editController.clear, + msgType: 5, + index: index, + ); + }, + dense: true, + title: const Text( + '撤回', + style: TextStyle(fontSize: 14), + ), + ), + ], + ), + ); + }, + ); + } + : null, + ); + }, + separatorBuilder: (BuildContext context, int index) => + const SizedBox(height: 12), ) : scrollErrorWidget( onReload: _whisperDetailController.onReload,