From 18f7cdbd57c7d5767786304ba3362dbf072ddf9d Mon Sep 17 00:00:00 2001 From: MiaoMint <1981324730@qq.com> Date: Mon, 21 Aug 2023 10:55:43 +0800 Subject: [PATCH] feat: new search page --- lib/pages/detail/controller.dart | 2 + lib/pages/search/pages/search_extension.dart | 45 ++----- lib/pages/search/view.dart | 127 +++++++------------ lib/utils/extension.dart | 1 + lib/widgets/search_appbar.dart | 77 +++++++++++ 5 files changed, 134 insertions(+), 118 deletions(-) create mode 100644 lib/widgets/search_appbar.dart diff --git a/lib/pages/detail/controller.dart b/lib/pages/detail/controller.dart index 3809af52..3673e412 100644 --- a/lib/pages/detail/controller.dart +++ b/lib/pages/detail/controller.dart @@ -1,3 +1,5 @@ +// ignore_for_file: use_build_context_synchronously + import 'dart:convert'; import 'package:desktop_webview_window/desktop_webview_window.dart'; diff --git a/lib/pages/search/pages/search_extension.dart b/lib/pages/search/pages/search_extension.dart index 69ea1e2a..aa80d597 100644 --- a/lib/pages/search/pages/search_extension.dart +++ b/lib/pages/search/pages/search_extension.dart @@ -12,6 +12,7 @@ import 'package:miru_app/widgets/extension_item_card.dart'; import 'package:miru_app/widgets/infinite_scroller.dart'; import 'package:miru_app/widgets/messenger.dart'; import 'package:miru_app/widgets/platform_widget.dart'; +import 'package:miru_app/widgets/search_appbar.dart'; class SearchExtensionPage extends fluent.StatefulWidget { const SearchExtensionPage({ @@ -30,7 +31,6 @@ class SearchExtensionPage extends fluent.StatefulWidget { class _SearchExtensionPageState extends fluent.State { late ExtensionRuntime _runtime; late String _keyWord = widget.keyWord ?? ''; - bool _showSearh = false; final List _data = []; int _page = 1; bool _isLoding = true; @@ -64,6 +64,7 @@ class _SearchExtensionPageState extends fluent.State { _data.addAll(data); _page++; } catch (e) { + // ignore: use_build_context_synchronously showPlatformSnackbar( context: context, content: e.toString(), @@ -88,39 +89,15 @@ class _SearchExtensionPageState extends fluent.State { Widget _buildAndroid(BuildContext context) { return Scaffold( - appBar: AppBar( - title: _showSearh || _keyWord.isNotEmpty - ? TextField( - decoration: InputDecoration( - hintText: 'search.hint-text'.i18n, - border: InputBorder.none, - ), - controller: TextEditingController( - text: _keyWord, - ), - onChanged: (value) { - if (value.isEmpty) { - _onSearch(value); - } - }, - onSubmitted: _onSearch, - ) - : Text( - _runtime.extension.name, - ), - actions: [ - IconButton( - icon: Icon(_showSearh ? Icons.close : Icons.search), - onPressed: () { - setState(() { - if (_showSearh) { - _keyWord = ''; - } - _showSearh = !_showSearh; - }); - }, - ), - ], + appBar: SearchAppBar( + title: _runtime.extension.name, + textEditingController: TextEditingController(text: _keyWord), + onChanged: (value) { + if (value.isEmpty) { + _onSearch(value); + } + }, + onSubmitted: _onSearch, ), body: InfiniteScroller( onRefresh: _onRefresh, diff --git a/lib/pages/search/view.dart b/lib/pages/search/view.dart index 1efd9f26..161da6ae 100644 --- a/lib/pages/search/view.dart +++ b/lib/pages/search/view.dart @@ -8,6 +8,7 @@ import 'package:miru_app/pages/search/widgets/search_all_extension.dart'; import 'package:miru_app/router/router.dart'; import 'package:miru_app/utils/i18n.dart'; import 'package:miru_app/widgets/platform_widget.dart'; +import 'package:miru_app/widgets/search_appbar.dart'; class SearchPage extends StatefulWidget { const SearchPage({Key? key}) : super(key: key); @@ -26,14 +27,11 @@ class _SearchPageState extends State { } Widget _buildAndroidSearch(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: TextField( - decoration: InputDecoration( - hintText: 'search.hint-text'.i18n, - border: InputBorder.none, - ), - controller: TextEditingController( + return DefaultTabController( + length: 4, + child: Scaffold( + appBar: SearchAppBar( + textEditingController: TextEditingController( text: c.search.value, ), onChanged: (value) { @@ -44,86 +42,47 @@ class _SearchPageState extends State { onSubmitted: (value) { c.search.value = value; }, - ), - flexibleSpace: Obx( - () => Column( - children: [ - if (c.finishCount != c.searchResultList.length) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: LinearProgressIndicator( - value: (c.finishCount / c.searchResultList.length), - minHeight: 2, + hintText: "search.hint-text".i18n, + title: "common.search".i18n, + flexibleSpace: Obx( + () => Column( + children: [ + if (c.finishCount != c.searchResultList.length) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: LinearProgressIndicator( + value: (c.finishCount / c.searchResultList.length), + minHeight: 2, + ), ), - ), + ], + ), + ), + bottom: TabBar( + tabs: [ + Tab(text: 'search.all'.i18n), + Tab(text: 'extension-type.video'.i18n), + Tab(text: 'extension-type.comic'.i18n), + Tab(text: 'extension-type.novel'.i18n), ], + onTap: (value) { + switch (value) { + case 0: + c.getRuntime(); + break; + case 1: + c.getRuntime(type: ExtensionType.bangumi); + break; + case 2: + c.getRuntime(type: ExtensionType.manga); + break; + case 3: + c.getRuntime(type: ExtensionType.fikushon); + break; + } + }, ), ), - ), - body: NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) { - return [ - SliverAppBar( - flexibleSpace: Obx( - () => SizedBox( - height: 60, - child: ListView( - padding: const EdgeInsets.symmetric(horizontal: 16), - scrollDirection: Axis.horizontal, - children: [ - ChoiceChip( - label: Text('search.all'.i18n), - selected: c.cuurentExtensionType.value == null, - onSelected: (value) { - if (value) { - c.getRuntime(); - } - }, - ), - const SizedBox(width: 8), - ChoiceChip( - label: Text('extension-type.video'.i18n), - selected: c.cuurentExtensionType.value == - ExtensionType.bangumi, - onSelected: (value) { - if (value) { - c.getRuntime(type: ExtensionType.bangumi); - } - }, - ), - const SizedBox(width: 8), - ChoiceChip( - label: Text('extension-type.comic'.i18n), - selected: - c.cuurentExtensionType.value == ExtensionType.manga, - onSelected: (value) { - if (value) { - c.getRuntime(type: ExtensionType.manga); - } - }, - ), - const SizedBox(width: 8), - ChoiceChip( - label: Text('extension-type.novel'.i18n), - selected: c.cuurentExtensionType.value == - ExtensionType.fikushon, - onSelected: (value) { - if (value) { - c.getRuntime( - type: ExtensionType.fikushon, - ); - } - }, - ), - ], - ), - ), - ), - floating: true, - snap: true, - ) - ]; - }, body: Obx( () { // ignore: invalid_use_of_protected_member diff --git a/lib/utils/extension.dart b/lib/utils/extension.dart index 14585d2a..a8a92b8a 100644 --- a/lib/utils/extension.dart +++ b/lib/utils/extension.dart @@ -89,6 +89,7 @@ class ExtensionUtils { // 保存文件 File(savePath).writeAsStringSync(res.data!); } catch (e) { + // ignore: use_build_context_synchronously showPlatformDialog( context: context, title: 'extension-install-error'.i18n, diff --git a/lib/widgets/search_appbar.dart b/lib/widgets/search_appbar.dart new file mode 100644 index 00000000..b133295b --- /dev/null +++ b/lib/widgets/search_appbar.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; + +class SearchAppBar extends StatefulWidget implements PreferredSizeWidget { + SearchAppBar({ + super.key, + required this.title, + required this.textEditingController, + this.actions, + this.bottom, + this.flexibleSpace, + this.toolbarHeight, + this.onSubmitted, + this.onChanged, + this.hintText, + }) : preferredSize = + _PreferredAppBarSize(toolbarHeight, bottom?.preferredSize.height); + final String title; + final List? actions; + final PreferredSizeWidget? bottom; + final Widget? flexibleSpace; + final double? toolbarHeight; + final TextEditingController textEditingController; + final Function(String)? onSubmitted; + final Function(String)? onChanged; + final String? hintText; + + @override + State createState() => _SearchAppBarState(); + + @override + final Size preferredSize; +} + +class _SearchAppBarState extends State { + late bool _showSearch = widget.textEditingController.text.isNotEmpty; + + @override + Widget build(BuildContext context) { + return AppBar( + title: _showSearch + ? TextField( + controller: widget.textEditingController, + decoration: InputDecoration( + hintText: widget.hintText ?? widget.title, + border: InputBorder.none, + ), + autofocus: true, + onChanged: widget.onChanged, + onSubmitted: widget.onSubmitted, + ) + : Text(widget.title), + actions: [ + IconButton( + onPressed: () { + setState(() { + _showSearch = !_showSearch; + if (!_showSearch) widget.onSubmitted?.call(""); + }); + }, + icon: Icon(_showSearch ? Icons.close : Icons.search), + ), + ...widget.actions ?? [], + ], + bottom: widget.bottom, + flexibleSpace: widget.flexibleSpace, + ); + } +} + +class _PreferredAppBarSize extends Size { + _PreferredAppBarSize(this.toolbarHeight, this.bottomHeight) + : super.fromHeight( + (toolbarHeight ?? kToolbarHeight) + (bottomHeight ?? 0)); + + final double? toolbarHeight; + final double? bottomHeight; +}