diff --git a/lib/common/widgets/http_error.dart b/lib/common/widgets/http_error.dart index cbc6659b..0381319e 100644 --- a/lib/common/widgets/http_error.dart +++ b/lib/common/widgets/http_error.dart @@ -2,12 +2,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; class HttpError extends StatelessWidget { - const HttpError( - {required this.errMsg, required this.fn, this.btnText, super.key}); + const HttpError({ + required this.errMsg, + required this.fn, + this.btnText, + this.isShowBtn = true, + super.key, + }); final String? errMsg; final Function()? fn; final String? btnText; + final bool isShowBtn; @override Widget build(BuildContext context) { @@ -29,20 +35,22 @@ class HttpError extends StatelessWidget { style: Theme.of(context).textTheme.titleSmall, ), const SizedBox(height: 20), - FilledButton.tonal( - onPressed: () { - fn!(); - }, - style: ButtonStyle( - backgroundColor: MaterialStateProperty.resolveWith((states) { - return Theme.of(context).colorScheme.primary.withAlpha(20); - }), + if (isShowBtn) + FilledButton.tonal( + onPressed: () { + fn!(); + }, + style: ButtonStyle( + backgroundColor: MaterialStateProperty.resolveWith((states) { + return Theme.of(context).colorScheme.primary.withAlpha(20); + }), + ), + child: Text( + btnText ?? '点击重试', + style: + TextStyle(color: Theme.of(context).colorScheme.primary), + ), ), - child: Text( - btnText ?? '点击重试', - style: TextStyle(color: Theme.of(context).colorScheme.primary), - ), - ), ], ), ), diff --git a/lib/http/search.dart b/lib/http/search.dart index 075defc7..403e6a37 100644 --- a/lib/http/search.dart +++ b/lib/http/search.dart @@ -88,7 +88,11 @@ class SearchHttp { if (tids != null && tids != -1) 'tids': tids, }; var res = await Request().get(Api.searchByType, data: reqData); - if (res.data['code'] == 0 && res.data['data']['numPages'] > 0) { + if (res.data['code'] == 0) { + if (res.data['data']['numPages'] == 0) { + // 我想返回数据,使得可以通过data.list 取值,结果为[] + return {'status': true, 'data': Data()}; + } Object data; try { switch (searchType) { @@ -125,9 +129,7 @@ class SearchHttp { return { 'status': false, 'data': [], - 'msg': res.data['data'] != null && res.data['data']['numPages'] == 0 - ? '没有相关数据' - : res.data['message'], + 'msg': res.data['message'], }; } } @@ -206,3 +208,9 @@ class SearchHttp { } } } + +class Data { + List list; + + Data({this.list = const []}); +} diff --git a/lib/models/search/result.dart b/lib/models/search/result.dart index 81917b72..b903c873 100644 --- a/lib/models/search/result.dart +++ b/lib/models/search/result.dart @@ -5,10 +5,12 @@ class SearchVideoModel { SearchVideoModel({this.list}); List? list; SearchVideoModel.fromJson(Map json) { - list = json['result'] - .where((e) => e['available'] == true) - .map((e) => SearchVideoItemModel.fromJson(e)) - .toList(); + list = json['result'] == null + ? [] + : json['result'] + .where((e) => e['available'] == true) + .map((e) => SearchVideoItemModel.fromJson(e)) + .toList(); } } diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart index a25389bd..e485fe41 100644 --- a/lib/pages/home/view.dart +++ b/lib/pages/home/view.dart @@ -357,25 +357,29 @@ class CustomChip extends StatelessWidget { Widget build(BuildContext context) { final ColorScheme colorTheme = Theme.of(context).colorScheme; final Color secondaryContainer = colorTheme.secondaryContainer; + final Color onPrimary = colorTheme.onPrimary; + final Color primary = colorTheme.primary; final TextStyle chipTextStyle = selected - ? const TextStyle(fontWeight: FontWeight.bold, fontSize: 13) - : const TextStyle(fontSize: 13); - final ColorScheme colorScheme = Theme.of(context).colorScheme; + ? TextStyle(fontSize: 13, color: onPrimary) + : TextStyle(fontSize: 13, color: colorTheme.onSecondaryContainer); const VisualDensity visualDensity = VisualDensity(horizontal: -4.0, vertical: -2.0); return InputChip( - side: BorderSide( - color: selected - ? colorScheme.onSecondaryContainer.withOpacity(0.2) - : Colors.transparent, - ), + side: BorderSide.none, backgroundColor: secondaryContainer, - selectedColor: secondaryContainer, - color: MaterialStateProperty.resolveWith( - (Set states) => secondaryContainer.withAlpha(200)), - padding: const EdgeInsets.fromLTRB(7, 1, 7, 1), + color: MaterialStateProperty.resolveWith((states) { + if (states.contains(MaterialState.selected) || + states.contains(MaterialState.hovered)) { + return primary; + } + return colorTheme.secondaryContainer; + }), + padding: const EdgeInsets.fromLTRB(6, 1, 6, 1), label: Text(label, style: chipTextStyle), onPressed: () => onTap(), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), selected: selected, showCheckmark: false, visualDensity: visualDensity, diff --git a/lib/pages/search_panel/controller.dart b/lib/pages/search_panel/controller.dart index 35113198..dc0b2bac 100644 --- a/lib/pages/search_panel/controller.dart +++ b/lib/pages/search_panel/controller.dart @@ -30,9 +30,9 @@ class SearchPanelController extends GetxController { ); if (result['status']) { if (type == 'onRefresh') { - resultList.value = result['data'].list; + resultList.value = result['data'].list ?? []; } else { - resultList.addAll(result['data'].list); + resultList.addAll(result['data'].list ?? []); } page.value++; onPushDetail(keyword, resultList); diff --git a/lib/pages/search_panel/widgets/video_panel.dart b/lib/pages/search_panel/widgets/video_panel.dart index 15745bde..f43e2eec 100644 --- a/lib/pages/search_panel/widgets/video_panel.dart +++ b/lib/pages/search_panel/widgets/video_panel.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/video_card_h.dart'; import 'package:pilipala/models/common/search_type.dart'; import 'package:pilipala/pages/search/widgets/search_text.dart'; @@ -25,25 +26,35 @@ class SearchVideoPanel extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.only(top: 36), - child: ListView.builder( - controller: ctr!.scrollController, - addAutomaticKeepAlives: false, - addRepaintBoundaries: false, - itemCount: list!.length, - itemBuilder: (context, index) { - var i = list![index]; - return Padding( - padding: index == 0 - ? const EdgeInsets.only(top: 2) - : EdgeInsets.zero, - child: VideoCardH( - videoItem: i, - showPubdate: true, - source: 'search', + child: list!.isNotEmpty + ? ListView.builder( + controller: ctr!.scrollController, + addAutomaticKeepAlives: false, + addRepaintBoundaries: false, + itemCount: list!.length, + itemBuilder: (context, index) { + var i = list![index]; + return Padding( + padding: index == 0 + ? const EdgeInsets.only(top: 2) + : EdgeInsets.zero, + child: VideoCardH( + videoItem: i, + showPubdate: true, + source: 'search', + ), + ); + }, + ) + : CustomScrollView( + slivers: [ + HttpError( + errMsg: '没有数据', + isShowBtn: false, + fn: () => {}, + ) + ], ), - ); - }, - ), ), // 分类筛选 Container( diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 38c62d7e..ea85a5b9 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -109,6 +109,7 @@ class VideoDetailController extends GetxController ].obs; RxDouble sheetHeight = 0.0.obs; RxString archiveSourceType = 'dash'.obs; + ScrollController? replyScrillController; @override void onInit() { @@ -551,4 +552,15 @@ class VideoDetailController extends GetxController cover.value = videoItem['pic'] = pic; } } + + void onControllerCreated(ScrollController controller) { + replyScrillController = controller; + } + + void onTapTabbar(int index) { + if (index == 1 && tabCtr.index == 1) { + replyScrillController?.animateTo(0, + duration: const Duration(milliseconds: 300), curve: Curves.ease); + } + } } diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index 653fe7e0..be1bd331 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -19,12 +19,14 @@ class VideoReplyPanel extends StatefulWidget { final int? oid; final int rpid; final String? replyLevel; + final Function(ScrollController)? onControllerCreated; const VideoReplyPanel({ this.bvid, this.oid, this.rpid = 0, this.replyLevel, + this.onControllerCreated, super.key, }); @@ -68,6 +70,7 @@ class _VideoReplyPanelState extends State _futureBuilderFuture = _videoReplyController.queryReplyList(); scrollController = ScrollController(); + widget.onControllerCreated?.call(scrollController); fabAnimationCtr.forward(); scrollListener(); } diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index ef067d1b..02a0bbe1 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -387,6 +387,7 @@ class _VideoDetailPageState extends State dividerColor: Colors.transparent, tabs: vdCtr.tabs.map((String name) => Tab(text: name)).toList(), + onTap: (index) => vdCtr.onTapTabbar(index), ), ), ), @@ -683,6 +684,7 @@ class _VideoDetailPageState extends State () => VideoReplyPanel( bvid: vdCtr.bvid, oid: vdCtr.oid.value, + onControllerCreated: vdCtr.onControllerCreated, ), ) ],