diff --git a/lib/pages/search_panel/view.dart b/lib/pages/search_panel/view.dart index 441398d3e..c4d71927c 100644 --- a/lib/pages/search_panel/view.dart +++ b/lib/pages/search_panel/view.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPalaX/common/skeleton/media_bangumi.dart'; import 'package:PiliPalaX/common/skeleton/video_card_h.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/models/common/search_type.dart'; import '../../common/constants.dart'; @@ -75,41 +74,7 @@ class _SearchPanelState extends State } Widget _buildBody(LoadingState loadingState) { - if (loadingState is Success) { - switch (widget.searchType) { - case SearchType.video: - return SearchVideoPanel( - ctr: _searchPanelController, - list: loadingState.response, - ); - case SearchType.media_bangumi: - return searchBangumiPanel( - context, - _searchPanelController, - loadingState.response, - ); - case SearchType.bili_user: - return searchUserPanel( - context, - _searchPanelController, - loadingState.response, - ); - case SearchType.live_room: - return searchLivePanel( - context, - _searchPanelController, - loadingState.response, - ); - case SearchType.article: - return searchArticlePanel( - context, - _searchPanelController, - loadingState.response, - ); - default: - return const SizedBox(); - } - } else if (loadingState is Loading) { + if (loadingState is Loading) { return CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ @@ -141,15 +106,39 @@ class _SearchPanelState extends State ], ); } else { - return CustomScrollView( - physics: const NeverScrollableScrollPhysics(), - slivers: [ - HttpError( - errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', - fn: _searchPanelController.onReload, - ), - ], - ); + switch (widget.searchType) { + case SearchType.video: + return SearchVideoPanel( + ctr: _searchPanelController, + loadingState: loadingState, + ); + case SearchType.media_bangumi: + return searchBangumiPanel( + context, + _searchPanelController, + loadingState, + ); + case SearchType.bili_user: + return searchUserPanel( + context, + _searchPanelController, + loadingState, + ); + case SearchType.live_room: + return searchLivePanel( + context, + _searchPanelController, + loadingState, + ); + case SearchType.article: + return searchArticlePanel( + context, + _searchPanelController, + loadingState, + ); + default: + return const SizedBox(); + } } } } diff --git a/lib/pages/search_panel/widgets/article_panel.dart b/lib/pages/search_panel/widgets/article_panel.dart index 54e3af4de..9b5278b9f 100644 --- a/lib/pages/search_panel/widgets/article_panel.dart +++ b/lib/pages/search_panel/widgets/article_panel.dart @@ -1,3 +1,5 @@ +import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/search/widgets/search_text.dart'; import 'package:PiliPalaX/pages/search_panel/controller.dart'; import 'package:PiliPalaX/pages/video/detail/reply/view.dart' @@ -11,7 +13,7 @@ import 'package:PiliPalaX/utils/utils.dart'; import '../../../utils/grid.dart'; -Widget searchArticlePanel(BuildContext context, searchPanelCtr, list) { +Widget searchArticlePanel(BuildContext context, searchPanelCtr, loadingState) { TextStyle textStyle = TextStyle( fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, color: Theme.of(context).colorScheme.outline); @@ -71,114 +73,141 @@ Widget searchArticlePanel(BuildContext context, searchPanelCtr, list) { ), ), ), - SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return InkWell( - onTap: () { - Get.toNamed('/htmlRender', parameters: { - 'url': 'www.bilibili.com/read/cv${list[index].id}', - 'title': list[index].subTitle, - 'id': 'cv${list[index].id}', - 'dynamicType': 'read' - }); - }, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: StyleString.safeSpace), - child: LayoutBuilder( - builder: (context, boxConstraints) { - final double width = (boxConstraints.maxWidth - - StyleString.cardSpace * - 6 / - MediaQuery.textScalerOf(context).scale(1.0)) / - 2; - return Container( - constraints: const BoxConstraints(minHeight: 88), - height: width / StyleString.aspectRatio, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (list[index].imageUrls != null && - list[index].imageUrls.isNotEmpty) - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return NetworkImgLayer( - width: maxWidth, - height: maxHeight, - src: list[index].imageUrls.first, - ); - }), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.fromLTRB(10, 2, 6, 0), - child: Column( - mainAxisSize: MainAxisSize.min, + loadingState is Success + ? SliverPadding( + padding: EdgeInsets.only( + bottom: StyleString.safeSpace + + MediaQuery.of(context).padding.bottom, + ), + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.safeSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0, + ), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return InkWell( + onTap: () { + Get.toNamed('/htmlRender', parameters: { + 'url': + 'www.bilibili.com/read/cv${loadingState.response[index].id}', + 'title': loadingState.response[index].subTitle, + 'id': 'cv${loadingState.response[index].id}', + 'dynamicType': 'read' + }); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: StyleString.safeSpace), + child: LayoutBuilder( + builder: (context, boxConstraints) { + final double width = (boxConstraints.maxWidth - + StyleString.cardSpace * + 6 / + MediaQuery.textScalerOf(context) + .scale(1.0)) / + 2; + return Container( + constraints: const BoxConstraints(minHeight: 88), + height: width / StyleString.aspectRatio, + child: Row( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - maxLines: 2, - text: TextSpan( - children: [ - for (var i in list[index].title) ...[ - TextSpan( - text: i['text'], - style: TextStyle( - fontWeight: FontWeight.w400, - letterSpacing: 0.3, - color: i['type'] == 'em' - ? Theme.of(context) - .colorScheme - .primary - : Theme.of(context) - .colorScheme - .onSurface, + children: [ + if (loadingState.response[index].imageUrls != + null && + loadingState + .response[index].imageUrls.isNotEmpty) + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = + boxConstraints.maxWidth; + double maxHeight = + boxConstraints.maxHeight; + return NetworkImgLayer( + width: maxWidth, + height: maxHeight, + src: loadingState + .response[index].imageUrls.first, + ); + }), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB( + 10, 2, 6, 0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + RichText( + maxLines: 2, + text: TextSpan( + children: [ + for (var i in loadingState + .response[index].title) ...[ + TextSpan( + text: i['text'], + style: TextStyle( + fontWeight: + FontWeight.w400, + letterSpacing: 0.3, + color: i['type'] == 'em' + ? Theme.of(context) + .colorScheme + .primary + : Theme.of(context) + .colorScheme + .onSurface, + ), + ), + ] + ], ), ), - ] - ], + const Spacer(), + Text( + Utils.dateFormat( + loadingState + .response[index].pubTime, + formatType: 'detail'), + style: textStyle), + Row( + children: [ + Text( + '${loadingState.response[index].view}浏览', + style: textStyle), + Text(' • ', style: textStyle), + Text( + '${loadingState.response[index].reply}评论', + style: textStyle), + ], + ), + ], + ), ), ), - const Spacer(), - Text( - Utils.dateFormat(list[index].pubTime, - formatType: 'detail'), - style: textStyle), - Row( - children: [ - Text('${list[index].view}浏览', - style: textStyle), - Text(' • ', style: textStyle), - Text('${list[index].reply}评论', - style: textStyle), - ], - ), ], ), - ), - ), - ], + ); + }, + ), ), ); }, + childCount: loadingState.response.length, ), ), - ); - }, - childCount: list.length, - ), - ), + ) + : HttpError( + errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', + fn: searchPanelCtr.onReload, + ), ], ); } diff --git a/lib/pages/search_panel/widgets/live_panel.dart b/lib/pages/search_panel/widgets/live_panel.dart index 09a37d47f..6ff7f2cf0 100644 --- a/lib/pages/search_panel/widgets/live_panel.dart +++ b/lib/pages/search_panel/widgets/live_panel.dart @@ -1,3 +1,5 @@ +import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/http/loading_state.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPalaX/common/constants.dart'; @@ -6,26 +8,36 @@ import 'package:PiliPalaX/utils/utils.dart'; import '../../../utils/grid.dart'; -Widget searchLivePanel(BuildContext context, ctr, list) { - return Padding( - padding: const EdgeInsets.only( - left: StyleString.safeSpace, right: StyleString.safeSpace), - child: GridView.builder( - primary: false, - controller: ctr!.scrollController, - gridDelegate: SliverGridDelegateWithExtentAndRatio( - maxCrossAxisExtent: Grid.maxRowWidth, - crossAxisSpacing: StyleString.safeSpace, - mainAxisSpacing: StyleString.safeSpace, - childAspectRatio: StyleString.aspectRatio, - mainAxisExtent: MediaQuery.textScalerOf(context).scale(80), - ), - itemCount: list.length, - itemBuilder: (context, index) { - return LiveItem(liveItem: list![index]); - }, - ), - ); +Widget searchLivePanel(BuildContext context, ctr, loadingState) { + return loadingState is Success + ? GridView.builder( + padding: const EdgeInsets.only( + left: StyleString.safeSpace, + right: StyleString.safeSpace, + bottom: StyleString.safeSpace, + ), + primary: false, + controller: ctr!.scrollController, + gridDelegate: SliverGridDelegateWithExtentAndRatio( + maxCrossAxisExtent: Grid.maxRowWidth, + crossAxisSpacing: StyleString.safeSpace, + mainAxisSpacing: StyleString.safeSpace, + childAspectRatio: StyleString.aspectRatio, + mainAxisExtent: MediaQuery.textScalerOf(context).scale(80), + ), + itemCount: loadingState.response.length, + itemBuilder: (context, index) { + return LiveItem(liveItem: loadingState.response[index]); + }, + ) + : CustomScrollView( + slivers: [ + HttpError( + errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', + fn: ctr.onReload, + ), + ], + ); } class LiveItem extends StatelessWidget { diff --git a/lib/pages/search_panel/widgets/media_bangumi_panel.dart b/lib/pages/search_panel/widgets/media_bangumi_panel.dart index a5194676c..a84cc3623 100644 --- a/lib/pages/search_panel/widgets/media_bangumi_panel.dart +++ b/lib/pages/search_panel/widgets/media_bangumi_panel.dart @@ -1,3 +1,5 @@ +import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/http/loading_state.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -11,164 +13,191 @@ import 'package:PiliPalaX/utils/utils.dart'; import '../../../utils/grid.dart'; -Widget searchBangumiPanel(BuildContext context, ctr, list) { +Widget searchBangumiPanel(BuildContext context, ctr, loadingState) { TextStyle style = TextStyle(fontSize: Theme.of(context).textTheme.labelMedium!.fontSize); return CustomScrollView( controller: ctr.scrollController, slivers: [ - SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - mainAxisExtent: 160, - ), - delegate: SliverChildBuilderDelegate((BuildContext context, int index) { - var i = list![index]; - return InkWell( - onTap: () { - /// TODO 番剧详情页面 - // Get.toNamed('/video?bvid=${i.bvid}&cid=${i.cid}', arguments: { - // 'videoItem': i, - // 'heroTag': Utils.makeHeroTag(i.id), - // 'videoType': SearchType.media_bangumi - // }); - }, - child: Padding( - padding: const EdgeInsets.fromLTRB(StyleString.safeSpace, - StyleString.safeSpace, StyleString.safeSpace, 2), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack( - children: [ - NetworkImgLayer( - width: 111, - height: 148, - src: i.cover, - ), - PBadge( - text: i.mediaType == 1 ? '番剧' : '国创', - top: 6.0, - right: 4.0, - bottom: null, - left: null, - ) - ], - ), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 4), - RichText( - maxLines: 1, - overflow: TextOverflow.ellipsis, - text: TextSpan( - style: TextStyle( - color: Theme.of(context).colorScheme.onSurface), - children: [ - for (var i in i.title) ...[ - TextSpan( - text: i['text'], - style: TextStyle( - fontSize: MediaQuery.textScalerOf(context) - .scale(Theme.of(context) - .textTheme - .titleSmall! - .fontSize!), - fontWeight: FontWeight.bold, - color: i['type'] == 'em' - ? Theme.of(context).colorScheme.primary - : Theme.of(context) - .colorScheme - .onSurface, - ), - ), - ], - ], - ), - ), - const SizedBox(height: 12), - Text('评分:${i.mediaScore['score'].toString()}', - style: style), - Row( - children: [ - Text(i.areas, style: style), - const SizedBox(width: 3), - const Text('·'), - const SizedBox(width: 3), - Text(Utils.dateFormat(i.pubtime).toString(), - style: style), - ], - ), - Row( - children: [ - Text(i.styles, style: style), - const SizedBox(width: 3), - const Text('·'), - const SizedBox(width: 3), - Text(i.indexShow, style: style), - ], - ), - const SizedBox(height: 18), - SizedBox( - height: 32, - child: ElevatedButton( - onPressed: () async { - SmartDialog.showLoading(msg: '获取中...'); - var res = await SearchHttp.bangumiInfo( - seasonId: i.seasonId); - SmartDialog.dismiss().then((value) { - if (res['status']) { - EpisodeItem episode = - res['data'].episodes.first; - int? epId = res['data'] - .userStatus - ?.progress - ?.lastEpId; - if (epId == null) { - epId = episode.epId; - } else { - for (var item in res['data'].episodes) { - if (item.epId == epId) { - episode = item; - break; - } - } - } - String bvid = episode.bvid!; - int cid = episode.cid!; - String pic = episode.cover!; - String heroTag = Utils.makeHeroTag(cid); - Get.toNamed( - '/video?bvid=$bvid&cid=$cid&seasonId=${i.seasonId}&epid=$epId', - arguments: { - 'pic': pic, - 'heroTag': heroTag, - 'videoType': SearchType.media_bangumi, - 'bangumiItem': res['data'], - }, - ); - } else { - SmartDialog.showToast(res['msg']); - } - }); - }, - child: const Text('观看'), - ), - ), - ], - ), - ), - ], + loadingState is Success + ? SliverPadding( + padding: EdgeInsets.only( + bottom: StyleString.safeSpace + + MediaQuery.of(context).padding.bottom, ), + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + mainAxisSpacing: StyleString.safeSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + mainAxisExtent: 160, + ), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + var i = loadingState.response[index]; + return InkWell( + onTap: () { + /// TODO 番剧详情页面 + // Get.toNamed('/video?bvid=${i.bvid}&cid=${i.cid}', arguments: { + // 'videoItem': i, + // 'heroTag': Utils.makeHeroTag(i.id), + // 'videoType': SearchType.media_bangumi + // }); + }, + child: Padding( + padding: const EdgeInsets.fromLTRB( + StyleString.safeSpace, + StyleString.safeSpace, + StyleString.safeSpace, + 2), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + children: [ + NetworkImgLayer( + width: 111, + height: 148, + src: i.cover, + ), + PBadge( + text: i.mediaType == 1 ? '番剧' : '国创', + top: 6.0, + right: 4.0, + bottom: null, + left: null, + ) + ], + ), + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 4), + RichText( + maxLines: 1, + overflow: TextOverflow.ellipsis, + text: TextSpan( + style: TextStyle( + color: Theme.of(context) + .colorScheme + .onSurface), + children: [ + for (var i in i.title) ...[ + TextSpan( + text: i['text'], + style: TextStyle( + fontSize: MediaQuery.textScalerOf( + context) + .scale(Theme.of(context) + .textTheme + .titleSmall! + .fontSize!), + fontWeight: FontWeight.bold, + color: i['type'] == 'em' + ? Theme.of(context) + .colorScheme + .primary + : Theme.of(context) + .colorScheme + .onSurface, + ), + ), + ], + ], + ), + ), + const SizedBox(height: 12), + Text('评分:${i.mediaScore['score'].toString()}', + style: style), + Row( + children: [ + Text(i.areas, style: style), + const SizedBox(width: 3), + const Text('·'), + const SizedBox(width: 3), + Text( + Utils.dateFormat(i.pubtime) + .toString(), + style: style), + ], + ), + Row( + children: [ + Text(i.styles, style: style), + const SizedBox(width: 3), + const Text('·'), + const SizedBox(width: 3), + Text(i.indexShow, style: style), + ], + ), + const SizedBox(height: 18), + SizedBox( + height: 32, + child: ElevatedButton( + onPressed: () async { + SmartDialog.showLoading(msg: '获取中...'); + var res = await SearchHttp.bangumiInfo( + seasonId: i.seasonId); + SmartDialog.dismiss().then((value) { + if (res['status']) { + EpisodeItem episode = + res['data'].episodes.first; + int? epId = res['data'] + .userStatus + ?.progress + ?.lastEpId; + if (epId == null) { + epId = episode.epId; + } else { + for (var item + in res['data'].episodes) { + if (item.epId == epId) { + episode = item; + break; + } + } + } + String bvid = episode.bvid!; + int cid = episode.cid!; + String pic = episode.cover!; + String heroTag = + Utils.makeHeroTag(cid); + Get.toNamed( + '/video?bvid=$bvid&cid=$cid&seasonId=${i.seasonId}&epid=$epId', + arguments: { + 'pic': pic, + 'heroTag': heroTag, + 'videoType': + SearchType.media_bangumi, + 'bangumiItem': res['data'], + }, + ); + } else { + SmartDialog.showToast(res['msg']); + } + }); + }, + child: const Text('观看'), + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + childCount: loadingState.response.length, + ), + ), + ) + : HttpError( + errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', + fn: ctr.onReload, ), - ); - }, childCount: list.length), - ), ], ); } diff --git a/lib/pages/search_panel/widgets/user_panel.dart b/lib/pages/search_panel/widgets/user_panel.dart index 12e31aeb1..3ac3677d7 100644 --- a/lib/pages/search_panel/widgets/user_panel.dart +++ b/lib/pages/search_panel/widgets/user_panel.dart @@ -1,3 +1,5 @@ +import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/search/widgets/search_text.dart'; import 'package:PiliPalaX/pages/search_panel/controller.dart'; import 'package:PiliPalaX/pages/video/detail/reply/view.dart' @@ -11,7 +13,7 @@ import 'package:PiliPalaX/utils/utils.dart'; import '../../../common/constants.dart'; import '../../../utils/grid.dart'; -Widget searchUserPanel(BuildContext context, searchPanelCtr, list) { +Widget searchUserPanel(BuildContext context, searchPanelCtr, loadingState) { TextStyle style = TextStyle( fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, color: Theme.of(context).colorScheme.outline); @@ -71,73 +73,85 @@ Widget searchUserPanel(BuildContext context, searchPanelCtr, list) { ), ), ), - SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - mainAxisExtent: 56), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - var i = list![index]; - String heroTag = Utils.makeHeroTag(i!.mid); - return InkWell( - onTap: () => Get.toNamed('/member?mid=${i.mid}', - arguments: {'heroTag': heroTag, 'face': i.upic}), - child: Row( - children: [ - const SizedBox(width: 15), - Hero( - tag: heroTag, - child: NetworkImgLayer( - width: 42, - height: 42, - src: i.upic, - type: 'avatar', - ), - ), - const SizedBox(width: 10), - Column( - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( + loadingState is Success + ? SliverPadding( + padding: EdgeInsets.only( + bottom: StyleString.safeSpace + + MediaQuery.of(context).padding.bottom, + ), + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + mainAxisSpacing: StyleString.cardSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + mainAxisExtent: 56, + ), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + var i = loadingState.response[index]; + String heroTag = Utils.makeHeroTag(i!.mid); + return InkWell( + onTap: () => Get.toNamed('/member?mid=${i.mid}', + arguments: {'heroTag': heroTag, 'face': i.upic}), + child: Row( children: [ - Text( - i!.uname, - style: const TextStyle( - fontSize: 14, + const SizedBox(width: 15), + Hero( + tag: heroTag, + child: NetworkImgLayer( + width: 42, + height: 42, + src: i.upic, + type: 'avatar', ), ), - const SizedBox(width: 6), - Image.asset( - 'assets/images/lv/lv${i!.level}.png', - height: 11, - semanticLabel: '等级${i.level}', - ), + const SizedBox(width: 10), + Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + children: [ + Text( + i!.uname, + style: const TextStyle( + fontSize: 14, + ), + ), + const SizedBox(width: 6), + Image.asset( + 'assets/images/lv/lv${i!.level}.png', + height: 11, + semanticLabel: '等级${i.level}', + ), + ], + ), + Row( + children: [ + Text('粉丝:${i.fans} ', style: style), + Text(' 视频:${i.videos}', style: style) + ], + ), + if (i.officialVerify['desc'] != '') + Text( + i.officialVerify['desc'], + style: style, + ), + ], + ) ], ), - Row( - children: [ - Text('粉丝:${i.fans} ', style: style), - Text(' 视频:${i.videos}', style: style) - ], - ), - if (i.officialVerify['desc'] != '') - Text( - i.officialVerify['desc'], - style: style, - ), - ], - ) - ], + ); + }, + childCount: loadingState.response.length, + ), ), - ); - }, - childCount: list!.length, - ), - ) + ) + : HttpError( + errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', + fn: searchPanelCtr.onReload, + ) ], ); } diff --git a/lib/pages/search_panel/widgets/video_panel.dart b/lib/pages/search_panel/widgets/video_panel.dart index b774fd398..40cb1f6ca 100644 --- a/lib/pages/search_panel/widgets/video_panel.dart +++ b/lib/pages/search_panel/widgets/video_panel.dart @@ -1,4 +1,8 @@ +import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/search/widgets/search_text.dart'; +import 'package:PiliPalaX/pages/video/detail/reply/view.dart' + show MySliverPersistentHeaderDelegate; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -12,99 +16,114 @@ import '../../../utils/grid.dart'; class SearchVideoPanel extends StatelessWidget { SearchVideoPanel({ required this.ctr, - required this.list, + required this.loadingState, Key? key, }) : super(key: key); final SearchPanelController ctr; - final List list; + final dynamic loadingState; final VideoPanelController controller = Get.put(VideoPanelController()); @override Widget build(BuildContext context) { - return Column( - children: [ - // 分类筛选 - Container( - width: context.width, - height: 34, - padding: const EdgeInsets.only( - left: StyleString.safeSpace, top: 0, right: 12), - child: Row( - children: [ - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Obx( - () => Wrap( - // spacing: , - children: [ - for (var i in controller.filterList) ...[ - CustomFilterChip( - label: i['label'], - type: i['type'], - selectedType: controller.selectedType.value, - callFn: (bool selected) async { - print('selected: $selected'); - controller.selectedType.value = i['type']; - ctr.order.value = - i['type'].toString().split('.').last; - SmartDialog.showLoading(msg: 'loading'); - await ctr.onRefresh(); - SmartDialog.dismiss(); - }, - ), - ] - ], + return CustomScrollView( + controller: ctr.scrollController, + slivers: [ + SliverPersistentHeader( + pinned: false, + floating: true, + delegate: MySliverPersistentHeaderDelegate( + child: Container( + width: context.width, + height: 34, + color: Theme.of(context).colorScheme.surface, + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Obx( + () => Wrap( + // spacing: , + children: [ + for (var i in controller.filterList) ...[ + CustomFilterChip( + label: i['label'], + type: i['type'], + selectedType: controller.selectedType.value, + callFn: (bool selected) async { + print('selected: $selected'); + controller.selectedType.value = i['type']; + ctr.order.value = + i['type'].toString().split('.').last; + SmartDialog.showLoading(msg: 'loading'); + await ctr.onRefresh(); + SmartDialog.dismiss(); + }, + ), + ] + ], + ), + ), ), ), - ), - ), - const VerticalDivider(indent: 7, endIndent: 8), - const SizedBox(width: 3), - SizedBox( - width: 32, - height: 32, - child: IconButton( - tooltip: '筛选', - style: ButtonStyle( - padding: WidgetStateProperty.all(EdgeInsets.zero), + const VerticalDivider(indent: 7, endIndent: 8), + const SizedBox(width: 3), + SizedBox( + width: 32, + height: 32, + child: IconButton( + tooltip: '筛选', + style: ButtonStyle( + padding: WidgetStateProperty.all(EdgeInsets.zero), + ), + onPressed: () => + controller.onShowFilterDialog(context, ctr), + icon: Icon( + Icons.filter_list_outlined, + size: 18, + color: Theme.of(context).colorScheme.primary, + ), + ), ), - onPressed: () => controller.onShowFilterDialog(context, ctr), - icon: Icon( - Icons.filter_list_outlined, - size: 18, - color: Theme.of(context).colorScheme.primary, - ), - ), + ], ), - ], + ), ), ), - Expanded( - child: CustomScrollView( - controller: ctr.scrollController, - slivers: [ - SliverPadding( - padding: const EdgeInsets.all(StyleString.safeSpace), + loadingState is Success + ? SliverPadding( + padding: EdgeInsets.only( + left: StyleString.safeSpace, + right: StyleString.safeSpace, + bottom: StyleString.safeSpace + + MediaQuery.of(context).padding.bottom, + ), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0), + mainAxisSpacing: StyleString.safeSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0, + ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return VideoCardH( - videoItem: list[index], showPubdate: true); + videoItem: loadingState.response[index], + showPubdate: true, + ); }, - childCount: list.length, + childCount: loadingState.response.length, ), - )), - ], - )), + ), + ) + : HttpError( + errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', + fn: ctr.onReload, + ), ], ); }