Reason Pun

增加了一言搜索页面

...@@ -95,18 +95,18 @@ class JsonConvert { ...@@ -95,18 +95,18 @@ class JsonConvert {
95 } 95 }
96 96
97 //list is returned by type 97 //list is returned by type
98 - static M? _getListChildType<M>(List<dynamic> data) { 98 + static M? _getListChildType<M>(List<Map<String, dynamic>> data) {
99 if(<UserEntity>[] is M){ 99 if(<UserEntity>[] is M){
100 - return data.map<UserEntity>((e) => UserEntity.fromJson(e)).toList() as M; 100 + return data.map<UserEntity>((Map<String, dynamic> e) => UserEntity.fromJson(e)).toList() as M;
101 } 101 }
102 if(<CategoryItemEntity>[] is M){ 102 if(<CategoryItemEntity>[] is M){
103 - return data.map<CategoryItemEntity>((e) => CategoryItemEntity.fromJson(e)).toList() as M; 103 + return data.map<CategoryItemEntity>((Map<String, dynamic> e) => CategoryItemEntity.fromJson(e)).toList() as M;
104 } 104 }
105 if(<FriendEntity>[] is M){ 105 if(<FriendEntity>[] is M){
106 - return data.map<FriendEntity>((e) => FriendEntity.fromJson(e)).toList() as M; 106 + return data.map<FriendEntity>((Map<String, dynamic> e) => FriendEntity.fromJson(e)).toList() as M;
107 } 107 }
108 if(<FriendData>[] is M){ 108 if(<FriendData>[] is M){
109 - return data.map<FriendData>((e) => FriendData.fromJson(e)).toList() as M; 109 + return data.map<FriendData>((Map<String, dynamic> e) => FriendData.fromJson(e)).toList() as M;
110 } 110 }
111 111
112 print("${M.toString()} not found"); 112 print("${M.toString()} not found");
...@@ -117,9 +117,8 @@ class JsonConvert { ...@@ -117,9 +117,8 @@ class JsonConvert {
117 static M? fromJsonAsT<M>(dynamic json) { 117 static M? fromJsonAsT<M>(dynamic json) {
118 if(json == null){ 118 if(json == null){
119 return null; 119 return null;
120 - } 120 + } if (json is List) {
121 - if (json is List) { 121 + return _getListChildType<M>(json.map((e) => e as Map<String, dynamic>).toList());
122 - return _getListChildType<M>(json);
123 } else { 122 } else {
124 return _fromJsonSingle<M>(json as Map<String, dynamic>); 123 return _fromJsonSingle<M>(json as Map<String, dynamic>);
125 } 124 }
......
This diff is collapsed. Click to expand it.
1 -
2 -
3 import 'base_page.dart'; 1 import 'base_page.dart';
4 import 'base_page_presenter.dart'; 2 import 'base_page_presenter.dart';
5 import 'base_presenter.dart'; 3 import 'base_presenter.dart';
6 4
7 /// 管理多个Presenter,实现复用。 5 /// 管理多个Presenter,实现复用。
8 class PowerPresenter<IMvpView> extends BasePresenter { 6 class PowerPresenter<IMvpView> extends BasePresenter {
9 -
10 PowerPresenter(BasePageMixin state) { 7 PowerPresenter(BasePageMixin state) {
11 _state = state; 8 _state = state;
12 } 9 }
...@@ -22,7 +19,7 @@ class PowerPresenter<IMvpView> extends BasePresenter { ...@@ -22,7 +19,7 @@ class PowerPresenter<IMvpView> extends BasePresenter {
22 void _requestPresenter(BasePagePresenter presenter) { 19 void _requestPresenter(BasePagePresenter presenter) {
23 presenter.view = _state; 20 presenter.view = _state;
24 } 21 }
25 - 22 +
26 @override 23 @override
27 void deactivate() { 24 void deactivate() {
28 _presenters.forEach(_deactivate); 25 _presenters.forEach(_deactivate);
...@@ -43,10 +40,10 @@ class PowerPresenter<IMvpView> extends BasePresenter { ...@@ -43,10 +40,10 @@ class PowerPresenter<IMvpView> extends BasePresenter {
43 40
44 @override 41 @override
45 void didUpdateWidgets<W>(W oldWidget) { 42 void didUpdateWidgets<W>(W oldWidget) {
46 -
47 void _didUpdateWidgets(BasePagePresenter presenter) { 43 void _didUpdateWidgets(BasePagePresenter presenter) {
48 presenter.didUpdateWidgets<W>(oldWidget); 44 presenter.didUpdateWidgets<W>(oldWidget);
49 } 45 }
46 +
50 _presenters.forEach(_didUpdateWidgets); 47 _presenters.forEach(_didUpdateWidgets);
51 } 48 }
52 49
...@@ -67,5 +64,4 @@ class PowerPresenter<IMvpView> extends BasePresenter { ...@@ -67,5 +64,4 @@ class PowerPresenter<IMvpView> extends BasePresenter {
67 void _initState(BasePagePresenter presenter) { 64 void _initState(BasePagePresenter presenter) {
68 presenter.initState(); 65 presenter.initState();
69 } 66 }
70 -
71 } 67 }
......
1 +import 'package:one_poem/mvp/mvps.dart';
2 +import 'package:one_poem/poem/models/search_entity.dart';
3 +import 'package:one_poem/poem/provider/base_list_provider.dart';
4 +
5 +abstract class PoemSearchIMvpView implements IMvpView {
6 + BaseListProvider<SearchItems> get provider;
7 +}
1 +import 'package:one_poem/generated/json/base/json_field.dart';
2 +import 'package:one_poem/generated/json/search_entity.g.dart';
3 +
4 +@JsonSerializable()
5 +class SearchEntity {
6 +
7 + SearchEntity();
8 +
9 + factory SearchEntity.fromJson(Map<String, dynamic> json) => $SearchEntityFromJson(json);
10 +
11 + Map<String, dynamic> toJson() => $SearchEntityToJson(this);
12 +
13 + @JSONField(name: 'total_count')
14 + int? totalCount;
15 + @JSONField(name: 'incomplete_results')
16 + bool? incompleteResults;
17 + List<SearchItems>? items;
18 +}
19 +
20 +@JsonSerializable()
21 +class SearchItems {
22 +
23 + SearchItems();
24 +
25 + factory SearchItems.fromJson(Map<String, dynamic> json) => $SearchItemsFromJson(json);
26 +
27 + Map<String, dynamic> toJson() => $SearchItemsToJson(this);
28 +
29 + int? id;
30 + @JSONField(name: 'node_id')
31 + String? nodeId;
32 + String? name;
33 + @JSONField(name: 'full_name')
34 + String? fullName;
35 + bool? private;
36 + SearchItemsOwner? owner;
37 + @JSONField(name: 'html_url')
38 + String? htmlUrl;
39 + String? description;
40 + bool? fork;
41 + String? url;
42 + @JSONField(name: 'forks_url')
43 + String? forksUrl;
44 + @JSONField(name: 'keys_url')
45 + String? keysUrl;
46 + @JSONField(name: 'collaborators_url')
47 + String? collaboratorsUrl;
48 + @JSONField(name: 'teams_url')
49 + String? teamsUrl;
50 + @JSONField(name: 'hooks_url')
51 + String? hooksUrl;
52 + @JSONField(name: 'issue_events_url')
53 + String? issueEventsUrl;
54 + @JSONField(name: 'events_url')
55 + String? eventsUrl;
56 + @JSONField(name: 'assignees_url')
57 + String? assigneesUrl;
58 + @JSONField(name: 'branches_url')
59 + String? branchesUrl;
60 + @JSONField(name: 'tags_url')
61 + String? tagsUrl;
62 + @JSONField(name: 'blobs_url')
63 + String? blobsUrl;
64 + @JSONField(name: 'git_tags_url')
65 + String? gitTagsUrl;
66 + @JSONField(name: 'git_refs_url')
67 + String? gitRefsUrl;
68 + @JSONField(name: 'trees_url')
69 + String? treesUrl;
70 + @JSONField(name: 'statuses_url')
71 + String? statusesUrl;
72 + @JSONField(name: 'languages_url')
73 + String? languagesUrl;
74 + @JSONField(name: 'stargazers_url')
75 + String? stargazersUrl;
76 + @JSONField(name: 'contributors_url')
77 + String? contributorsUrl;
78 + @JSONField(name: 'subscribers_url')
79 + String? subscribersUrl;
80 + @JSONField(name: 'subscription_url')
81 + String? subscriptionUrl;
82 + @JSONField(name: 'commits_url')
83 + String? commitsUrl;
84 + @JSONField(name: 'git_commits_url')
85 + String? gitCommitsUrl;
86 + @JSONField(name: 'comments_url')
87 + String? commentsUrl;
88 + @JSONField(name: 'issue_comment_url')
89 + String? issueCommentUrl;
90 + @JSONField(name: 'contents_url')
91 + String? contentsUrl;
92 + @JSONField(name: 'compare_url')
93 + String? compareUrl;
94 + @JSONField(name: 'merges_url')
95 + String? mergesUrl;
96 + @JSONField(name: 'archive_url')
97 + String? archiveUrl;
98 + @JSONField(name: 'downloads_url')
99 + String? downloadsUrl;
100 + @JSONField(name: 'issues_url')
101 + String? issuesUrl;
102 + @JSONField(name: 'pulls_url')
103 + String? pullsUrl;
104 + @JSONField(name: 'milestones_url')
105 + String? milestonesUrl;
106 + @JSONField(name: 'notifications_url')
107 + String? notificationsUrl;
108 + @JSONField(name: 'labels_url')
109 + String? labelsUrl;
110 + @JSONField(name: 'releases_url')
111 + String? releasesUrl;
112 + @JSONField(name: 'deployments_url')
113 + String? deploymentsUrl;
114 + @JSONField(name: 'created_at')
115 + String? createdAt;
116 + @JSONField(name: 'updated_at')
117 + String? updatedAt;
118 + @JSONField(name: 'pushed_at')
119 + String? pushedAt;
120 + @JSONField(name: 'git_url')
121 + String? gitUrl;
122 + @JSONField(name: 'ssh_url')
123 + String? sshUrl;
124 + @JSONField(name: 'clone_url')
125 + String? cloneUrl;
126 + @JSONField(name: 'svn_url')
127 + String? svnUrl;
128 + String? homepage;
129 + int? size;
130 + @JSONField(name: 'stargazers_count')
131 + int? stargazersCount;
132 + @JSONField(name: 'watchers_count')
133 + int? watchersCount;
134 + String? language;
135 + @JSONField(name: 'has_issues')
136 + bool? hasIssues;
137 + @JSONField(name: 'has_projects')
138 + bool? hasProjects;
139 + @JSONField(name: 'has_downloads')
140 + bool? hasDownloads;
141 + @JSONField(name: 'has_wiki')
142 + bool? hasWiki;
143 + @JSONField(name: 'has_pages')
144 + bool? hasPages;
145 + @JSONField(name: 'forks_count')
146 + int? forksCount;
147 + bool? archived;
148 + bool? disabled;
149 + @JSONField(name: 'open_issues_count')
150 + int? openIssuesCount;
151 + SearchItemsLicense? license;
152 + int? forks;
153 + @JSONField(name: 'open_issues')
154 + int? openIssues;
155 + int? watchers;
156 + @JSONField(name: 'default_branch')
157 + String? defaultBranch;
158 + double? score;
159 +}
160 +
161 +@JsonSerializable()
162 +class SearchItemsOwner {
163 +
164 + SearchItemsOwner();
165 +
166 + factory SearchItemsOwner.fromJson(Map<String, dynamic> json) => $SearchItemsOwnerFromJson(json);
167 +
168 + Map<String, dynamic> toJson() => $SearchItemsOwnerToJson(this);
169 +
170 + String? login;
171 + int? id;
172 + @JSONField(name: 'node_id')
173 + String? nodeId;
174 + @JSONField(name: 'avatar_url')
175 + String? avatarUrl;
176 + @JSONField(name: 'gravatar_id')
177 + String? gravatarId;
178 + String? url;
179 + @JSONField(name: 'html_url')
180 + String? htmlUrl;
181 + @JSONField(name: 'followers_url')
182 + String? followersUrl;
183 + @JSONField(name: 'following_url')
184 + String? followingUrl;
185 + @JSONField(name: 'gists_url')
186 + String? gistsUrl;
187 + @JSONField(name: 'starred_url')
188 + String? starredUrl;
189 + @JSONField(name: 'subscriptions_url')
190 + String? subscriptionsUrl;
191 + @JSONField(name: 'organizations_url')
192 + String? organizationsUrl;
193 + @JSONField(name: 'repos_url')
194 + String? reposUrl;
195 + @JSONField(name: 'events_url')
196 + String? eventsUrl;
197 + @JSONField(name: 'received_events_url')
198 + String? receivedEventsUrl;
199 + String? type;
200 + @JSONField(name: 'site_admin')
201 + bool? siteAdmin;
202 +}
203 +
204 +@JsonSerializable()
205 +class SearchItemsLicense {
206 +
207 + SearchItemsLicense();
208 +
209 + factory SearchItemsLicense.fromJson(Map<String, dynamic> json) => $SearchItemsLicenseFromJson(json);
210 +
211 + Map<String, dynamic> toJson() => $SearchItemsLicenseToJson(this);
212 +
213 + String? key;
214 + String? name;
215 + @JSONField(name: 'spdx_id')
216 + String? spdxId;
217 + String? url;
218 + @JSONField(name: 'node_id')
219 + String? nodeId;
220 +}
1 -import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
3 import 'package:one_poem/category/category_router.dart'; 2 import 'package:one_poem/category/category_router.dart';
3 +import 'package:one_poem/poem/poem_router.dart';
4 import 'package:one_poem/routers/fluro_navigator.dart'; 4 import 'package:one_poem/routers/fluro_navigator.dart';
5 import 'package:one_poem/tiktok/controller/tiktok_video_list_controller.dart'; 5 import 'package:one_poem/tiktok/controller/tiktok_video_list_controller.dart';
6 import 'package:one_poem/tiktok/mock/video.dart'; 6 import 'package:one_poem/tiktok/mock/video.dart';
...@@ -134,7 +134,10 @@ class _PoemPageState extends State<PoemPage> with WidgetsBindingObserver { ...@@ -134,7 +134,10 @@ class _PoemPageState extends State<PoemPage> with WidgetsBindingObserver {
134 Icons.search, 134 Icons.search,
135 color: Colors.white, 135 color: Colors.white,
136 ), 136 ),
137 - onPressed: () {}, 137 + onPressed: () {
138 + NavigatorUtils.push(context, PoemRouter.poemSearchPage);
139 + _videoListController.currentPlayer.pause();
140 + },
138 ), 141 ),
139 ), 142 ),
140 leftPage: searchPage, 143 leftPage: searchPage,
......
1 +import 'package:flutter/material.dart';
2 +import 'package:one_poem/mvp/base_page.dart';
3 +import 'package:one_poem/mvp/power_presenter.dart';
4 +import 'package:one_poem/poem/iview/poem_search_iview.dart';
5 +import 'package:one_poem/poem/models/search_entity.dart';
6 +import 'package:one_poem/poem/presenter/poem_search_presenter.dart';
7 +import 'package:one_poem/poem/provider/base_list_provider.dart';
8 +import 'package:one_poem/widgets/my_refresh_list.dart';
9 +import 'package:one_poem/widgets/search_bar.dart';
10 +import 'package:one_poem/widgets/state_layout.dart';
11 +import 'package:provider/provider.dart';
12 +
13 +import 'package:one_poem/extension/int_extension.dart';
14 +
15 +class PoemSearchPage extends StatefulWidget {
16 + const PoemSearchPage({Key? key}) : super(key: key);
17 +
18 + @override
19 + _PoemSearchPageState createState() => _PoemSearchPageState();
20 +}
21 +
22 +class _PoemSearchPageState extends State<PoemSearchPage>
23 + with BasePageMixin<PoemSearchPage, PowerPresenter>
24 + implements PoemSearchIMvpView {
25 + @override
26 + BaseListProvider<SearchItems> provider = BaseListProvider<SearchItems>();
27 +
28 + late String _keyword;
29 + int _page = 1;
30 +
31 + @override
32 + void initState() {
33 + provider.stateType = StateType.empty;
34 + super.initState();
35 + }
36 +
37 + @override
38 + Widget build(BuildContext context) {
39 + return ChangeNotifierProvider<BaseListProvider<SearchItems>>(
40 + create: (_) => provider,
41 + child: Scaffold(
42 + appBar: SearchBar(
43 + hintText: '请输入要查询的内容',
44 + onPressed: (text) {
45 + if (text.isEmpty) {
46 + showToast('搜索关键字不能为空!');
47 + return;
48 + }
49 + _keyword = text;
50 + provider.setStateType(StateType.loading);
51 + _page = 1;
52 + _poemSearchPresenter.search(_keyword, _page, true);
53 + },
54 + ),
55 + body:
56 + Consumer<BaseListProvider<SearchItems>>(builder: (_, provider, __) {
57 + return DeerListView(
58 + key: const Key('poem_search_list'),
59 + itemCount: provider.list.length,
60 + stateType: provider.stateType,
61 + onRefresh: _onRefresh,
62 + loadMore: _loadMore,
63 + itemExtent: 50.0,
64 + hasMore: provider.hasMore,
65 + itemBuilder: (_, index) {
66 + return Container(
67 + padding: EdgeInsets.symmetric(horizontal: 16.px),
68 + alignment: Alignment.centerLeft,
69 + child: Text(provider.list[index].name!),
70 + );
71 + },
72 + );
73 + }),
74 + ),
75 + );
76 + }
77 +
78 + Future<void> _onRefresh() async {
79 + _page = 1;
80 + await _poemSearchPresenter.search(_keyword, _page, false);
81 + }
82 +
83 + Future<void> _loadMore() async {
84 + _page++;
85 + await _poemSearchPresenter.search(_keyword, _page, false);
86 + }
87 +
88 + late PoemSearchPresenter _poemSearchPresenter;
89 + @override
90 + PowerPresenter createPresenter() {
91 + final PowerPresenter powerPresenter = PowerPresenter<dynamic>(this);
92 + _poemSearchPresenter = PoemSearchPresenter();
93 + powerPresenter.requestPresenter([_poemSearchPresenter]);
94 + return powerPresenter;
95 + }
96 +}
1 import 'package:fluro/fluro.dart'; 1 import 'package:fluro/fluro.dart';
2 import 'package:one_poem/poem/page/poem_record_audio.dart'; 2 import 'package:one_poem/poem/page/poem_record_audio.dart';
3 +import 'package:one_poem/poem/page/poem_search_page.dart';
3 import 'package:one_poem/routers/i_router.dart'; 4 import 'package:one_poem/routers/i_router.dart';
4 import 'page/poem_complete_page.dart'; 5 import 'page/poem_complete_page.dart';
5 import 'page/poem_detail.dart'; 6 import 'page/poem_detail.dart';
...@@ -16,6 +17,7 @@ class PoemRouter implements IRouterProvider { ...@@ -16,6 +17,7 @@ class PoemRouter implements IRouterProvider {
16 static String poemVideoPlayer = '/poem/video/player'; 17 static String poemVideoPlayer = '/poem/video/player';
17 static String poemPublish = '/poem/publish'; 18 static String poemPublish = '/poem/publish';
18 static String poemCompletePage = '/poem/complete'; 19 static String poemCompletePage = '/poem/complete';
20 + static String poemSearchPage = '/poem/search';
19 21
20 @override 22 @override
21 void initRouter(FluroRouter router) { 23 void initRouter(FluroRouter router) {
...@@ -25,6 +27,7 @@ class PoemRouter implements IRouterProvider { ...@@ -25,6 +27,7 @@ class PoemRouter implements IRouterProvider {
25 handlerFunc: (_, __) => const PoemPage(), 27 handlerFunc: (_, __) => const PoemPage(),
26 ), 28 ),
27 ); 29 );
30 +
28 router.define( 31 router.define(
29 poemDetailPage, 32 poemDetailPage,
30 handler: Handler( 33 handler: Handler(
...@@ -95,5 +98,8 @@ class PoemRouter implements IRouterProvider { ...@@ -95,5 +98,8 @@ class PoemRouter implements IRouterProvider {
95 }, 98 },
96 ), 99 ),
97 ); 100 );
101 +
102 + router.define(poemSearchPage,
103 + handler: Handler(handlerFunc: (_, __) => const PoemSearchPage()));
98 } 104 }
99 } 105 }
......
1 +import 'package:one_poem/mvp/base_page_presenter.dart';
2 +import 'package:one_poem/net/dio_utils.dart';
3 +import 'package:one_poem/net/http_api.dart';
4 +import 'package:one_poem/poem/iview/poem_search_iview.dart';
5 +import 'package:one_poem/poem/models/search_entity.dart';
6 +import 'package:one_poem/widgets/state_layout.dart';
7 +
8 +class PoemSearchPresenter extends BasePagePresenter<PoemSearchIMvpView> {
9 +
10 + Future search(String text, int page, bool isShowDialog) {
11 +
12 + final Map<String, String> params = <String, String>{};
13 + params['q'] = text;
14 + params['page'] = page.toString();
15 + params['l'] = 'Dart';
16 + return requestNetwork<SearchEntity>(Method.get,
17 + url: HttpApi.search,
18 + queryParameters: params,
19 + isShow: isShowDialog,
20 + onSuccess: (data) {
21 + if (data != null && data.items != null) {
22 + /// 一页30条数据,等于30条认为有下一页
23 + /// 具体的处理逻辑根据具体的接口情况处理,这部分可以抽离出来
24 + view.provider.hasMore = data.items!.length == 30;
25 + if (page == 1) {
26 + /// 刷新
27 + view.provider.list.clear();
28 + if (data.items!.isEmpty) {
29 + view.provider.setStateType(StateType.order);
30 + } else {
31 + view.provider.addAll(data.items!);
32 + }
33 + } else {
34 + view.provider.addAll(data.items!);
35 + }
36 + } else {
37 + /// 加载失败
38 + view.provider.hasMore = false;
39 + view.provider.setStateType(StateType.network);
40 + }
41 + },
42 + onError: (_, __) {
43 + /// 加载失败
44 + view.provider.hasMore = false;
45 + view.provider.setStateType(StateType.network);
46 + }
47 + );
48 + }
49 +
50 +}
1 +import 'package:flutter/material.dart';
2 +import 'package:one_poem/widgets/state_layout.dart';
3 +
4 +class BaseListProvider<T> extends ChangeNotifier {
5 +
6 + final List<T> _list = <T>[];
7 + List<T> get list => _list;
8 +
9 + bool hasMore = true;
10 +
11 + StateType stateType = StateType.loading;
12 +
13 + void setStateType(StateType stateType) {
14 + this.stateType = stateType;
15 + notifyListeners();
16 + }
17 +
18 + void add(T data) {
19 + _list.add(data);
20 + notifyListeners();
21 + }
22 +
23 + void addAll(List<T> data) {
24 + _list.addAll(data);
25 + notifyListeners();
26 + }
27 +
28 + void insert(int i, T data) {
29 + _list.insert(i, data);
30 + notifyListeners();
31 + }
32 +
33 + void insertAll(int i, List<T> data) {
34 + _list.insertAll(i, data);
35 + notifyListeners();
36 + }
37 +
38 + void remove(T data) {
39 + _list.remove(data);
40 + notifyListeners();
41 + }
42 +
43 + void removeAt(int i) {
44 + _list.removeAt(i);
45 + notifyListeners();
46 + }
47 +
48 + void clear() {
49 + _list.clear();
50 + notifyListeners();
51 + }
52 +
53 + void refresh() {
54 + notifyListeners();
55 + }
56 +}
...@@ -3,19 +3,18 @@ import 'package:flutter/scheduler.dart'; ...@@ -3,19 +3,18 @@ import 'package:flutter/scheduler.dart';
3 import 'package:flutter/services.dart'; 3 import 'package:flutter/services.dart';
4 import 'package:one_poem/res/resources.dart'; 4 import 'package:one_poem/res/resources.dart';
5 import 'package:one_poem/util/theme_utils.dart'; 5 import 'package:one_poem/util/theme_utils.dart';
6 - 6 +import 'package:one_poem/extension/int_extension.dart';
7 import 'load_image.dart'; 7 import 'load_image.dart';
8 import 'my_button.dart'; 8 import 'my_button.dart';
9 9
10 /// 搜索页的AppBar 10 /// 搜索页的AppBar
11 class SearchBar extends StatefulWidget implements PreferredSizeWidget { 11 class SearchBar extends StatefulWidget implements PreferredSizeWidget {
12 -
13 const SearchBar({ 12 const SearchBar({
14 Key? key, 13 Key? key,
15 this.hintText = '', 14 this.hintText = '',
16 this.backImg = 'assets/images/ic_back_black.png', 15 this.backImg = 'assets/images/ic_back_black.png',
17 this.onPressed, 16 this.onPressed,
18 - }): super(key: key); 17 + }) : super(key: key);
19 18
20 final String backImg; 19 final String backImg;
21 final String hintText; 20 final String hintText;
...@@ -25,11 +24,10 @@ class SearchBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -25,11 +24,10 @@ class SearchBar extends StatefulWidget implements PreferredSizeWidget {
25 _SearchBarState createState() => _SearchBarState(); 24 _SearchBarState createState() => _SearchBarState();
26 25
27 @override 26 @override
28 - Size get preferredSize => const Size.fromHeight(48.0); 27 + Size get preferredSize => Size.fromHeight(48.px);
29 } 28 }
30 29
31 class _SearchBarState extends State<SearchBar> { 30 class _SearchBarState extends State<SearchBar> {
32 -
33 final TextEditingController _controller = TextEditingController(); 31 final TextEditingController _controller = TextEditingController();
34 final FocusNode _focus = FocusNode(); 32 final FocusNode _focus = FocusNode();
35 33
...@@ -40,34 +38,26 @@ class _SearchBarState extends State<SearchBar> { ...@@ -40,34 +38,26 @@ class _SearchBarState extends State<SearchBar> {
40 super.dispose(); 38 super.dispose();
41 } 39 }
42 40
43 - // @override
44 - // void initState() {
45 - // WidgetsBinding.instance!.addPostFrameCallback((_) async {
46 - // SystemChannels.textInput.invokeMethod<void>('TextInput.updateConfig', const TextInputConfiguration().toJson());
47 - // SystemChannels.textInput.invokeMethod<void>('TextInput.hide');
48 - // });
49 - // super.initState();
50 - // }
51 -
52 @override 41 @override
53 Widget build(BuildContext context) { 42 Widget build(BuildContext context) {
54 final bool isDark = context.isDark; 43 final bool isDark = context.isDark;
55 - final Color iconColor = isDark ? Colours.dark_text_gray : Colours.text_gray_c; 44 + final Color iconColor =
56 - 45 + isDark ? Colours.dark_text_gray : Colours.text_gray_c;
46 +
57 final Widget back = Semantics( 47 final Widget back = Semantics(
58 label: '返回', 48 label: '返回',
59 child: SizedBox( 49 child: SizedBox(
60 - width: 48.0, 50 + width: 48.px,
61 - height: 48.0, 51 + height: 48.px,
62 child: InkWell( 52 child: InkWell(
63 onTap: () { 53 onTap: () {
64 _focus.unfocus(); 54 _focus.unfocus();
65 Navigator.maybePop(context); 55 Navigator.maybePop(context);
66 }, 56 },
67 - borderRadius: BorderRadius.circular(24.0), 57 + borderRadius: BorderRadius.circular(24.px),
68 child: Padding( 58 child: Padding(
69 key: const Key('search_back'), 59 key: const Key('search_back'),
70 - padding: const EdgeInsets.all(12.0), 60 + padding: EdgeInsets.all(12.px),
71 child: Image.asset( 61 child: Image.asset(
72 widget.backImg, 62 widget.backImg,
73 color: isDark ? Colours.dark_text : Colours.text, 63 color: isDark ? Colours.dark_text : Colours.text,
...@@ -77,43 +67,15 @@ class _SearchBarState extends State<SearchBar> { ...@@ -77,43 +67,15 @@ class _SearchBarState extends State<SearchBar> {
77 ), 67 ),
78 ); 68 );
79 69
80 - /// 使用2.0.0新增CupertinoSearchTextField 实现, 需添加依赖 cupertino_icons: ^1.0.2
81 - // final Widget textField1 = Expanded(child: Container(
82 - // height: 32.0,
83 - // child: CupertinoSearchTextField(
84 - // key: const Key('search_text_field'),
85 - // controller: _controller,
86 - // focusNode: _focus,
87 - // placeholder: widget.hintText,
88 - // placeholderStyle: Theme.of(context).inputDecorationTheme.hintStyle,
89 - // padding: const EdgeInsetsDirectional.fromSTEB(3.8, 0, 5, 0),
90 - // prefixInsets: const EdgeInsetsDirectional.fromSTEB(8, 0, 0, 0),
91 - // suffixInsets: const EdgeInsetsDirectional.fromSTEB(0, 0, 8, 0),
92 - // style: Theme.of(context).textTheme.subtitle1,
93 - // itemSize: 16.0,
94 - // itemColor: iconColor,
95 - // decoration: BoxDecoration(
96 - // color: isDark ? Colours.dark_material_bg : Colours.bg_gray,
97 - // borderRadius: BorderRadius.circular(4.0),
98 - // ),
99 - // onSubmitted: (String val) {
100 - // _focus.unfocus();
101 - // // 点击软键盘的动作按钮时的回调
102 - // widget.onPressed(val);
103 - // },
104 - // )
105 - // ));
106 -
107 final Widget textField = Expanded( 70 final Widget textField = Expanded(
108 child: Container( 71 child: Container(
109 - height: 32.0, 72 + height: 32.px,
110 decoration: BoxDecoration( 73 decoration: BoxDecoration(
111 color: isDark ? Colours.dark_material_bg : Colours.bg_gray, 74 color: isDark ? Colours.dark_material_bg : Colours.bg_gray,
112 - borderRadius: BorderRadius.circular(4.0), 75 + borderRadius: BorderRadius.circular(4.px),
113 ), 76 ),
114 child: TextField( 77 child: TextField(
115 key: const Key('search_text_field'), 78 key: const Key('search_text_field'),
116 -// autofocus: true,
117 controller: _controller, 79 controller: _controller,
118 focusNode: _focus, 80 focusNode: _focus,
119 textInputAction: TextInputAction.search, 81 textInputAction: TextInputAction.search,
...@@ -123,19 +85,24 @@ class _SearchBarState extends State<SearchBar> { ...@@ -123,19 +85,24 @@ class _SearchBarState extends State<SearchBar> {
123 widget.onPressed?.call(val); 85 widget.onPressed?.call(val);
124 }, 86 },
125 decoration: InputDecoration( 87 decoration: InputDecoration(
126 - contentPadding: const EdgeInsets.only(left: -8.0, right: -16.0, bottom: 14.0), 88 + contentPadding:
89 + EdgeInsets.only(left: -8.px, right: -16.px, bottom: 14.px),
127 border: InputBorder.none, 90 border: InputBorder.none,
128 icon: Padding( 91 icon: Padding(
129 - padding: const EdgeInsets.only(top: 8.0, bottom: 8.0, left: 8.0), 92 + padding: EdgeInsets.only(top: 8.px, bottom: 8.px, left: 8.px),
130 - child: LoadAssetImage('poem/order_search', color: iconColor,), 93 + child: LoadAssetImage(
94 + 'poem/poem_search',
95 + color: iconColor,
96 + ),
131 ), 97 ),
132 hintText: widget.hintText, 98 hintText: widget.hintText,
133 suffixIcon: GestureDetector( 99 suffixIcon: GestureDetector(
134 child: Semantics( 100 child: Semantics(
135 label: '清空', 101 label: '清空',
136 child: Padding( 102 child: Padding(
137 - padding: const EdgeInsets.only(left: 16.0, top: 8.0, bottom: 8.0), 103 + padding:
138 - child: LoadAssetImage('poem/order_delete', color: iconColor), 104 + EdgeInsets.only(left: 16.px, top: 8.px, bottom: 8.px),
105 + child: LoadAssetImage('poem/poem_delete', color: iconColor),
139 ), 106 ),
140 ), 107 ),
141 onTap: () { 108 onTap: () {
...@@ -149,20 +116,20 @@ class _SearchBarState extends State<SearchBar> { ...@@ -149,20 +116,20 @@ class _SearchBarState extends State<SearchBar> {
149 ), 116 ),
150 ), 117 ),
151 ); 118 );
152 - 119 +
153 final Widget search = MyButton( 120 final Widget search = MyButton(
154 - minHeight: 32.0, 121 + minHeight: 32.px,
155 - minWidth: 44.0, 122 + minWidth: 44.px,
156 fontSize: Dimens.font_sp14, 123 fontSize: Dimens.font_sp14,
157 - radius: 4.0, 124 + radius: 4.px,
158 - padding: const EdgeInsets.symmetric(horizontal: 8.0), 125 + padding: EdgeInsets.symmetric(horizontal: 8.px),
159 text: '搜索', 126 text: '搜索',
160 - onPressed:() { 127 + onPressed: () {
161 _focus.unfocus(); 128 _focus.unfocus();
162 widget.onPressed?.call(_controller.text); 129 widget.onPressed?.call(_controller.text);
163 }, 130 },
164 ); 131 );
165 - 132 +
166 return AnnotatedRegion<SystemUiOverlayStyle>( 133 return AnnotatedRegion<SystemUiOverlayStyle>(
167 value: isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark, 134 value: isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
168 child: Material( 135 child: Material(
......