From 553dbad00e5c34a5c8b1d9e4f2645b6f1eff31ac Mon Sep 17 00:00:00 2001 From: ryan Date: Tue, 30 Apr 2019 10:41:24 +0800 Subject: [PATCH 1/4] =?UTF-8?q?Add:=E4=BA=8C=E6=9C=9F=E5=BC=80=E5=8F=91-?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A6=96=E9=A1=B5=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/images/ali_connors.png | Bin 0 -> 19411 bytes flutter_01.png | Bin 0 -> 41772 bytes lib/blocs/industry_api.dart | 73 +++++ lib/blocs/industry_bloc.dart | 33 ++ lib/blocs/industry_event.dart | 17 + lib/blocs/industry_main.dart | 110 +++++++ lib/blocs/industry_model.dart | 72 +++++ lib/blocs/industry_state.dart | 34 ++ lib/blocs/search_api.dart | 35 +++ lib/blocs/search_bloc.dart | 35 +++ lib/blocs/search_event.dart | 18 ++ lib/blocs/search_result.dart | 14 + lib/blocs/search_state.dart | 37 +++ lib/blocs/search_widget.dart | 80 +++++ lib/views/first_page/home.dart | 26 +- lib/views/first_page/main_app_bar.dart | 415 +++++++++++++++++++++++++ lib/views/first_page/main_page.dart | 112 +++++++ pubspec.lock | 129 +++++--- pubspec.yaml | 3 + 19 files changed, 1192 insertions(+), 51 deletions(-) create mode 100644 assets/images/ali_connors.png create mode 100644 flutter_01.png create mode 100644 lib/blocs/industry_api.dart create mode 100644 lib/blocs/industry_bloc.dart create mode 100644 lib/blocs/industry_event.dart create mode 100644 lib/blocs/industry_main.dart create mode 100644 lib/blocs/industry_model.dart create mode 100644 lib/blocs/industry_state.dart create mode 100644 lib/blocs/search_api.dart create mode 100644 lib/blocs/search_bloc.dart create mode 100644 lib/blocs/search_event.dart create mode 100644 lib/blocs/search_result.dart create mode 100644 lib/blocs/search_state.dart create mode 100644 lib/blocs/search_widget.dart create mode 100644 lib/views/first_page/main_app_bar.dart create mode 100644 lib/views/first_page/main_page.dart diff --git a/assets/images/ali_connors.png b/assets/images/ali_connors.png new file mode 100644 index 0000000000000000000000000000000000000000..b7e343229c671d7b929eff8e110616ac78815212 GIT binary patch literal 19411 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 |yzsgrJyA42&=36V+@>cdw@rRVBR%FJ=s2#z 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 H@qho>Q5k2s literal 0 HcmV?d00001 diff --git a/flutter_01.png b/flutter_01.png new file mode 100644 index 0000000000000000000000000000000000000000..16a118fca290609a7d2102cd54458fb6c257742a GIT binary patch literal 41772 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 suggestion(String query) async { +// http.Response response = await http.get( +// "https://www.qidian.com/ajax/Search/AutoComplete?siteid=1&query=$query"); + var response = await dio.get("https://www.qidian.com/ajax/Search/AutoComplete?siteid=1&query=$query", data: {}); + //var response = await dio.get("https://www.so.com/s?ie=utf-8&q=$query"); + print('1=====>${query}'); + print('2=====>${response.data}'); + //var data = Suggestion.fromJson(json.decode(response.body)); + //var data = Suggestion.fromJson(json.decode(response.data)); + var data = Suggestion.fromJson(json.decode(response.data)); + List suggestion = []; + data.suggestions.forEach((k) { + //print('=====>${k.value}'); + suggestion.add(k.value); + }); + + return Future.delayed(Duration(seconds:2), () { + return suggestion; + }); + //return suggestion; + } +} +class Api { + /// 关键字提示(起点) + Future> suggestion(String query) async { +// http.Response response = await http.get( +// "https://www.qidian.com/ajax/Search/AutoComplete?siteid=1&query=$query"); + /// var response = await dio.get("https://www.qidian.com/ajax/Search/AutoComplete?siteid=1&query=$query", data: {}); + var response = await dio.get("https://www.so.com/s?ie=utf-8&q=$query"); + var document = parse(response.data); + var app = document.querySelectorAll('.res-title a'); + print('1=====>${query}'); + print('2=====>${response.data}'); + print('3=====>${app}'); + //var data = Suggestion.fromJson(json.decode(response.body)); + //var data = Suggestion.fromJson(json.decode(response.data)); + List res = []; + app.forEach((f) { + print('f==>${f}'); + res.add( + SearchResult( + title: f.text, + source: f.attributes["data-url"] ?? f.attributes["href"], + ), + ); + }); + + return Future.delayed(Duration(seconds:2), () { + return res; + }); + //return suggestion; + } +} + +Api api = Api(); \ No newline at end of file diff --git a/lib/blocs/industry_bloc.dart b/lib/blocs/industry_bloc.dart new file mode 100644 index 00000000..fd1addb6 --- /dev/null +++ b/lib/blocs/industry_bloc.dart @@ -0,0 +1,33 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 5:19 PM + * email: zhu.yan@alibaba-inc.com + * tartget: + */ +import 'dart:async'; +import 'package:bloc/bloc.dart'; +import './industry_api.dart'; +import './industry_event.dart'; +import './industry_state.dart'; + +class SuggestionBloc extends Bloc { + @override + SuggestionState get initialState => SuggestionUninitialized(); + + @override + Stream mapEventToState(SuggestionEvent event)async* { + //Stream mapEventToState(SuggestionState currentState, SuggestionEvent event,) async* { + if (event is SuggestionFetch) { + print('event==>${event.query}'); + try { + yield SuggestionLoading(); + final res = await api.suggestion(event.query); + yield SuggestionLoaded(res: res); + } catch (_) { + yield SuggestionError(); + } + } + } +} diff --git a/lib/blocs/industry_event.dart b/lib/blocs/industry_event.dart new file mode 100644 index 00000000..c7aad05e --- /dev/null +++ b/lib/blocs/industry_event.dart @@ -0,0 +1,17 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 3:35 PM + * email: zhu.yan@alibaba-inc.com + */ +abstract class SuggestionEvent {} + +class SuggestionFetch extends SuggestionEvent { + final String query; + + SuggestionFetch({this.query}); + + @override + String toString() => 'SuggestionFetch:获取关键字提示事件'; +} \ No newline at end of file diff --git a/lib/blocs/industry_main.dart b/lib/blocs/industry_main.dart new file mode 100644 index 00000000..88dd6d55 --- /dev/null +++ b/lib/blocs/industry_main.dart @@ -0,0 +1,110 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 3:52 PM + * email: zhu.yan@alibaba-inc.com + */ +import 'package:flutter/material.dart'; +//import 'package:bloc/bloc.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import './industry_bloc.dart'; +import './industry_event.dart'; +import './industry_state.dart'; + +//class Industry extends StatelessWidget { +// @override +// Widget build(BuildContext context) { +// return MaterialApp( +// title: '关键字提示', +// home: Scaffold( +// appBar: AppBar( +// title: Text('关键字提示'), +// ), +// body: AppHome(), +// ), +// ); +// } +//} + +class IndustryPage extends StatefulWidget { + @override + _IndustryState createState() => _IndustryState(); +} + +class _IndustryState extends State { + final SuggestionBloc _suggestion = SuggestionBloc(); + + @override + Widget build(BuildContext context) { + return Material( + child: Column( + children: [ + TextField( + autofocus: true, + textAlign: TextAlign.center, + onSubmitted: (text) { + _suggestion.dispatch(SuggestionFetch(query: text)); + }, + ), + Expanded( + child: BlocBuilder( + bloc: _suggestion, + builder: (BuildContext context, SuggestionState state) { + print('-------${state}'); + if (state is SuggestionUninitialized) { + return Center( + child: Text('暂无内容'), + ); + } else if (state is SuggestionLoading) { + return Center( + child: CircularProgressIndicator(), + ); + } else if (state is SuggestionError) { + return Center( + child: Text('出现错误'), + ); + } else if (state is SuggestionLoaded) { +// return ListView.builder( +// itemBuilder: (BuildContext context, int index) { +// //return ListTile(title: Text(state.res[index])); +// return null; +// }, +// itemCount: state.res.length, +// ); + return ListView.builder( + itemBuilder: (BuildContext context, int index) { + return ListTile( + dense: true, + leading: Icon( + Icons.bookmark_border, + size: 32, + ), + title: Text( + state.res[index].title, + overflow: TextOverflow.ellipsis, + ), + subtitle: Text(state.res[index].source), + onTap: () { + // 在这里对选中的结果进行解析,因为我目前是用golang实现的,所以就没贴代码了。 + print(state.res[index].source); + }, + ); + }, + itemCount: state.res.length, + ); + } + }, + ), + ), + ], + ), + ); + } + + @override + void dispose() { + _suggestion.dispose(); + super.dispose(); + } +} \ No newline at end of file diff --git a/lib/blocs/industry_model.dart b/lib/blocs/industry_model.dart new file mode 100644 index 00000000..ea6cb081 --- /dev/null +++ b/lib/blocs/industry_model.dart @@ -0,0 +1,72 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 3:19 PM + * email: zhu.yan@alibaba-inc.com + */ +class Suggestion { + String query; + List suggestions; + int code; + + Suggestion({this.query, this.suggestions, this.code}); + + Suggestion.fromJson(Map json) { + query = json['query']; + if (json['suggestions'] != null) { + suggestions = new List(); + json['suggestions'].forEach((v) { + suggestions.add(new Suggestions.fromJson(v)); + }); + } + code = json['code']; + } + + Map toJson() { + final Map data = new Map(); + data['query'] = this.query; + if (this.suggestions != null) { + data['suggestions'] = this.suggestions.map((v) => v.toJson()).toList(); + } + data['code'] = this.code; + return data; + } +} + +class Suggestions { + Data data; + String value; + + Suggestions({this.data, this.value}); + + Suggestions.fromJson(Map json) { + data = json['data'] != null ? new Data.fromJson(json['data']) : null; + value = json['value']; + } + + Map toJson() { + final Map data = new Map(); + if (this.data != null) { + data['data'] = this.data.toJson(); + } + data['value'] = this.value; + return data; + } +} + +class Data { + String category; + + Data({this.category}); + + Data.fromJson(Map json) { + category = json['category']; + } + + Map toJson() { + final Map data = new Map(); + data['category'] = this.category; + return data; + } +} \ No newline at end of file diff --git a/lib/blocs/industry_state.dart b/lib/blocs/industry_state.dart new file mode 100644 index 00000000..c3061318 --- /dev/null +++ b/lib/blocs/industry_state.dart @@ -0,0 +1,34 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 3:37 PM + * email: zhu.yan@alibaba-inc.com + */ +abstract class SuggestionState {} + +class SuggestionError extends SuggestionState { + @override + String toString() => 'SuggestionError:获取失败'; +} + +class SuggestionUninitialized extends SuggestionState { + @override + String toString() => 'SuggestionUninitialized:未初始化'; +} + +class SuggestionLoading extends SuggestionState { + @override + String toString() => 'SuggestionLoading :正在加载'; +} + +class SuggestionLoaded extends SuggestionState { + final List res; + + SuggestionLoaded({ + this.res, + }); + + @override + String toString() => 'SuggestionLoaded:加载完毕'; +} \ No newline at end of file diff --git a/lib/blocs/search_api.dart b/lib/blocs/search_api.dart new file mode 100644 index 00000000..0548d34e --- /dev/null +++ b/lib/blocs/search_api.dart @@ -0,0 +1,35 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 3:20 PM + * email: zhu.yan@alibaba-inc.com + * tartget: FlatButton 的示例 + */ +import 'dart:async'; +import 'package:dio/dio.dart'; +import 'dart:convert'; +import './search_result.dart'; +import 'package:html/parser.dart' show parse; + +var dio = new Dio(); +class Api { + Future> search(name) async { + print('=========>>>'); + var response = await dio.get("https://www.so.com/s?ie=utf-8&q=$name"); +// var document = parse(response.data); +// var app = document.querySelectorAll('.res-title a'); + List res = []; +// app.forEach((f) { +// res.add( +// SearchResult( +// title: f.text, +// source: f.attributes["data-url"] ?? f.attributes["href"], +// ), +// ); +// }); + return res; + } +} + +Api api = Api(); \ No newline at end of file diff --git a/lib/blocs/search_bloc.dart b/lib/blocs/search_bloc.dart new file mode 100644 index 00000000..08d526c8 --- /dev/null +++ b/lib/blocs/search_bloc.dart @@ -0,0 +1,35 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 7:17 PM + * email: zhu.yan@alibaba-inc.com + * tartget: + */ +import 'dart:async'; +import 'package:bloc/bloc.dart'; + +import './search_event.dart'; +import './search_state.dart'; +import './search_api.dart'; + + +/// 这里导入api类与上面的SearchEvent与SearchState文件 + +class SearchBloc extends Bloc { + @override + SearchState get initialState => SearchUninitialized(); + + @override + Stream mapEventToState(SearchEvent event,) async* { + if (event is SearchFetch) { + try { + yield SearchLoading(); + final res = await api.search(event.query); + yield SearchLoaded(res: res); + } catch (_) { + yield SearchError(); + } + } + } +} \ No newline at end of file diff --git a/lib/blocs/search_event.dart b/lib/blocs/search_event.dart new file mode 100644 index 00000000..0ecc0b44 --- /dev/null +++ b/lib/blocs/search_event.dart @@ -0,0 +1,18 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 7:18 PM + * email: zhu.yan@alibaba-inc.com + * tartget: + */ +abstract class SearchEvent {} + +class SearchFetch extends SearchEvent { + final String query; + + SearchFetch({this.query}); + + @override + String toString() => 'SearchFetch:获取搜索结果事件'; +} \ No newline at end of file diff --git a/lib/blocs/search_result.dart b/lib/blocs/search_result.dart new file mode 100644 index 00000000..8001e49a --- /dev/null +++ b/lib/blocs/search_result.dart @@ -0,0 +1,14 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 7:11 PM + * email: zhu.yan@alibaba-inc.com + * tartget: + */ +class SearchResult { + String title; + String source; + + SearchResult({this.title, this.source}); +} \ No newline at end of file diff --git a/lib/blocs/search_state.dart b/lib/blocs/search_state.dart new file mode 100644 index 00000000..85d85791 --- /dev/null +++ b/lib/blocs/search_state.dart @@ -0,0 +1,37 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 7:13 PM + * email: zhu.yan@alibaba-inc.com + * tartget: + */ +import './search_result.dart'; + +abstract class SearchState {} + +class SearchError extends SearchState { + @override + String toString() => 'SearchError:获取失败'; +} + +class SearchUninitialized extends SearchState { + @override + String toString() => 'SearchUninitialized:未初始化'; +} + +class SearchLoading extends SearchState { + @override + String toString() => 'SearchLoading :正在加载'; +} + +class SearchLoaded extends SearchState { + final List res; + + SearchLoaded({ + this.res, + }); + + @override + String toString() => 'SearchLoaded:加载完毕'; +} \ No newline at end of file diff --git a/lib/blocs/search_widget.dart b/lib/blocs/search_widget.dart new file mode 100644 index 00000000..1e29848a --- /dev/null +++ b/lib/blocs/search_widget.dart @@ -0,0 +1,80 @@ +/** + * Created with Android Studio. + * User: 一晟 + * Date: 2019/4/28 + * Time: 7:19 PM + * email: zhu.yan@alibaba-inc.com + * tartget: + */ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +//import 'package:suiyi/blocs/search/bloc.dart'; +import './search_event.dart'; +import './search_state.dart'; +import './search_bloc.dart'; + + +class SearchWidget extends StatefulWidget { + final SearchDelegate delegate; + final String query; + SearchWidget({this.delegate, this.query}); + @override + _SearchWidgetState createState() => _SearchWidgetState(); +} + +class _SearchWidgetState extends State { + final SearchBloc _search = SearchBloc(); + String old; + @override + void dispose() { + _search.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + print('1:${old}'); + print('2:${widget.query}'); + if (old != widget.query) { + _search.dispatch(SearchFetch(query: widget.query)); + old = widget.query; + } + return BlocBuilder( + bloc: _search, + builder: (BuildContext context, SearchState state) { + print('-------${state}'); + if (state is SearchUninitialized || state is SearchLoading) { + return Center( + child: CircularProgressIndicator(), + ); + } else if (state is SearchError) { + return Center( + child: Text('获取失败'), + ); + } else if (state is SearchLoaded) { + return ListView.builder( + itemBuilder: (BuildContext context, int index) { + return ListTile( + dense: true, + leading: Icon( + Icons.bookmark_border, + size: 32, + ), + title: Text( + state.res[index].title, + overflow: TextOverflow.ellipsis, + ), + subtitle: Text(state.res[index].source), + onTap: () { + // 在这里对选中的结果进行解析,因为我目前是用golang实现的,所以就没贴代码了。 + print(state.res[index].source); + }, + ); + }, + itemCount: state.res.length, + ); + } + }, + ); + } +} \ No newline at end of file diff --git a/lib/views/first_page/home.dart b/lib/views/first_page/home.dart index efb8b1d5..c2185cd3 100644 --- a/lib/views/first_page/home.dart +++ b/lib/views/first_page/home.dart @@ -22,6 +22,13 @@ import 'package:flutter_go/components/search_input.dart'; import 'package:flutter_go/model/search_history.dart'; import 'package:flutter_go/resources/widget_name_to_icon.dart'; +import 'package:flutter_go/blocs/industry_main.dart'; +//import 'package:flutter_go/blocs/search_widget.dart'; + +import 'main_page.dart'; + + + const int ThemeColor = 0xFFC91B3A; class AppPage extends StatefulWidget { @@ -117,16 +124,27 @@ class _MyHomePageState extends State }, (value) {}, () {}); } + renderAppBar(BuildContext context,Widget widget) { + print('renderAppBar=====>>>>>>${controller.index}'); + if(controller.index == 0) { + return null; + } + return AppBar(title: buildSearchInput(context)); + } + @override Widget build(BuildContext context) { var db = Provider.db; return new Scaffold( - appBar: new AppBar(title: buildSearchInput(context)), + appBar: renderAppBar(context,widget), body: new TabBarView(controller: controller, children: [ - new FirstPage(), - new WidgetPage(db), - new CollectionPage(), + //new FirstPage(), + //new IndustryPage(), + //new SearchWidget(), + MainPage(), + WidgetPage(db), + CollectionPage(), FourthPage() ]), bottomNavigationBar: Material( diff --git a/lib/views/first_page/main_app_bar.dart b/lib/views/first_page/main_app_bar.dart new file mode 100644 index 00000000..c85e4cde --- /dev/null +++ b/lib/views/first_page/main_app_bar.dart @@ -0,0 +1,415 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +const double _kLeadingWidth = + kToolbarHeight; // So the leading button is square. + +// Bottom justify the kToolbarHeight child which may overflow the top. +class _ToolbarContainerLayout extends SingleChildLayoutDelegate { + const _ToolbarContainerLayout(); + + @override + BoxConstraints getConstraintsForChild(BoxConstraints constraints) { + return constraints.tighten(height: kToolbarHeight); + } + + @override + Size getSize(BoxConstraints constraints) { + return Size(constraints.maxWidth, kToolbarHeight); + } + + @override + Offset getPositionForChild(Size size, Size childSize) { + return Offset(0.0, size.height - childSize.height); + } + + @override + bool shouldRelayout(_ToolbarContainerLayout oldDelegate) => false; +} + +class MyAppBar extends StatefulWidget implements PreferredSizeWidget { + /// Creates a material design app bar. + /// + /// The arguments [elevation], [primary], [toolbarOpacity], [bottomOpacity] + /// and [automaticallyImplyLeading] must not be null. + /// + /// Typically used in the [Scaffold.appBar] property. + MyAppBar({ + Key key, + this.leading, + this.automaticallyImplyLeading = true, + this.title, + this.actions, + this.flexibleSpace, + this.bottom, + this.elevation = 4.0, + this.backgroundColor, + this.brightness, + this.iconTheme, + this.textTheme, + this.primary = true, + this.centerTitle, + this.titleSpacing = NavigationToolbar.kMiddleSpacing, + this.toolbarOpacity = 1.0, + this.bottomOpacity = 1.0, + }) : assert(automaticallyImplyLeading != null), + assert(elevation != null), + assert(primary != null), + assert(titleSpacing != null), + assert(toolbarOpacity != null), + assert(bottomOpacity != null), + preferredSize = Size.fromHeight( + kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)), + super(key: key); + + /// A widget to display before the [title]. + /// + /// If this is null and [automaticallyImplyLeading] is set to true, the + /// [AppBar] will imply an appropriate widget. For example, if the [AppBar] is + /// in a [Scaffold] that also has a [Drawer], the [Scaffold] will fill this + /// widget with an [IconButton] that opens the drawer (using [Icons.menu]). If + /// there's no [Drawer] and the parent [Navigator] can go back, the [AppBar] + /// will use a [BackButton] that calls [Navigator.maybePop]. + final Widget leading; + + /// Controls whether we should try to imply the leading widget if null. + /// + /// If true and [leading] is null, automatically try to deduce what the leading + /// widget should be. If false and [leading] is null, leading space is given to [title]. + /// If leading widget is not null, this parameter has no effect. + final bool automaticallyImplyLeading; + + /// The primary widget displayed in the appbar. + /// + /// Typically a [Text] widget containing a description of the current contents + /// of the app. + final Widget title; + + /// Widgets to display after the [title] widget. + /// + /// Typically these widgets are [IconButton]s representing common operations. + /// For less common operations, consider using a [PopupMenuButton] as the + /// last action. + /// + /// ## Sample code + /// + /// ```dart + /// Scaffold( + /// appBar: AppBar( + /// title: Text('Hello World'), + /// actions: [ + /// IconButton( + /// icon: Icon(Icons.shopping_cart), + /// tooltip: 'Open shopping cart', + /// onPressed: () { + /// // ... + /// }, + /// ), + /// ], + /// ), + /// ) + /// ``` + final List actions; + + /// This widget is stacked behind the toolbar and the tabbar. It's height will + /// be the same as the app bar's overall height. + /// + /// A flexible space isn't actually flexible unless the [AppBar]'s container + /// changes the [AppBar]'s size. A [SliverAppBar] in a [CustomScrollView] + /// changes the [AppBar]'s height when scrolled. + /// + /// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details. + final Widget flexibleSpace; + + /// This widget appears across the bottom of the app bar. + /// + /// Typically a [TabBar]. Only widgets that implement [PreferredSizeWidget] can + /// be used at the bottom of an app bar. + /// + /// See also: + /// + /// * [PreferredSize], which can be used to give an arbitrary widget a preferred size. + final PreferredSizeWidget bottom; + + /// The z-coordinate at which to place this app bar. This controls the size of + /// the shadow below the app bar. + /// + /// Defaults to 4, the appropriate elevation for app bars. + final double elevation; + + /// The color to use for the app bar's material. Typically this should be set + /// along with [brightness], [iconTheme], [textTheme]. + /// + /// Defaults to [ThemeData.primaryColor]. + final Color backgroundColor; + + /// The brightness of the app bar's material. Typically this is set along + /// with [backgroundColor], [iconTheme], [textTheme]. + /// + /// Defaults to [ThemeData.primaryColorBrightness]. + final Brightness brightness; + + /// The color, opacity, and size to use for app bar icons. Typically this + /// is set along with [backgroundColor], [brightness], [textTheme]. + /// + /// Defaults to [ThemeData.primaryIconTheme]. + final IconThemeData iconTheme; + + /// The typographic styles to use for text in the app bar. Typically this is + /// set along with [brightness] [backgroundColor], [iconTheme]. + /// + /// Defaults to [ThemeData.primaryTextTheme]. + final TextTheme textTheme; + + /// Whether this app bar is being displayed at the top of the screen. + /// + /// If true, the appbar's toolbar elements and [bottom] widget will be + /// padded on top by the height of the system status bar. The layout + /// of the [flexibleSpace] is not affected by the [primary] property. + final bool primary; + + /// Whether the title should be centered. + /// + /// Defaults to being adapted to the current [TargetPlatform]. + final bool centerTitle; + + /// The spacing around [title] content on the horizontal axis. This spacing is + /// applied even if there is no [leading] content or [actions]. If you want + /// [title] to take all the space available, set this value to 0.0. + /// + /// Defaults to [NavigationToolbar.kMiddleSpacing]. + final double titleSpacing; + + /// How opaque the toolbar part of the app bar is. + /// + /// A value of 1.0 is fully opaque, and a value of 0.0 is fully transparent. + /// + /// Typically, this value is not changed from its default value (1.0). It is + /// used by [SliverAppBar] to animate the opacity of the toolbar when the app + /// bar is scrolled. + final double toolbarOpacity; + + /// How opaque the bottom part of the app bar is. + /// + /// A value of 1.0 is fully opaque, and a value of 0.0 is fully transparent. + /// + /// Typically, this value is not changed from its default value (1.0). It is + /// used by [SliverAppBar] to animate the opacity of the toolbar when the app + /// bar is scrolled. + final double bottomOpacity; + + /// A size whose height is the sum of [kToolbarHeight] and the [bottom] widget's + /// preferred height. + /// + /// [Scaffold] uses this this size to set its app bar's height. + @override + final Size preferredSize; + + bool _getEffectiveCenterTitle(ThemeData themeData) { + if (centerTitle != null) return centerTitle; + assert(themeData.platform != null); + switch (themeData.platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + return false; + case TargetPlatform.iOS: + return actions == null || actions.length < 2; + } + return null; + } + + @override + _MyAppBarState createState() => _MyAppBarState(); +} + +class _MyAppBarState extends State { + void _handleDrawerButton() { + Scaffold.of(context).openDrawer(); + } + + void _handleDrawerButtonEnd() { + Scaffold.of(context).openEndDrawer(); + } + + @override + Widget build(BuildContext context) { + assert(!widget.primary || debugCheckHasMediaQuery(context)); + assert(debugCheckHasMaterialLocalizations(context)); + final ThemeData themeData = Theme.of(context); + final ScaffoldState scaffold = Scaffold.of(context, nullOk: true); + final ModalRoute parentRoute = ModalRoute.of(context); + + final bool hasDrawer = scaffold?.hasDrawer ?? false; + final bool hasEndDrawer = scaffold?.hasEndDrawer ?? false; + final bool canPop = parentRoute?.canPop ?? false; + final bool useCloseButton = + parentRoute is PageRoute && parentRoute.fullscreenDialog; + + IconThemeData appBarIconTheme = + widget.iconTheme ?? themeData.primaryIconTheme; + TextStyle centerStyle = + widget.textTheme?.title ?? themeData.primaryTextTheme.title; + TextStyle sideStyle = + widget.textTheme?.body1 ?? themeData.primaryTextTheme.body1; + + if (widget.toolbarOpacity != 1.0) { + final double opacity = + const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn) + .transform(widget.toolbarOpacity); + if (centerStyle?.color != null) + centerStyle = + centerStyle.copyWith(color: centerStyle.color.withOpacity(opacity)); + if (sideStyle?.color != null) + sideStyle = + sideStyle.copyWith(color: sideStyle.color.withOpacity(opacity)); + appBarIconTheme = appBarIconTheme.copyWith( + opacity: opacity * (appBarIconTheme.opacity ?? 1.0)); + } + + Widget leading = widget.leading; + //if (leading == null && widget.automaticallyImplyLeading) { + if (widget.automaticallyImplyLeading) { + if (hasDrawer) { + leading = IconButton( + //icon: const Icon(Icons.menu), + icon: leading ?? const Icon(Icons.menu), + onPressed: _handleDrawerButton, + tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip, + ); + } else { + if (canPop) + leading = useCloseButton ? const CloseButton() : const BackButton(); + } + } + if (leading != null) { + leading = ConstrainedBox( + constraints: const BoxConstraints.tightFor(width: _kLeadingWidth), + child: leading, + ); + } + + Widget title = widget.title; + if (title != null) { + bool namesRoute; + switch (defaultTargetPlatform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + namesRoute = true; + break; + case TargetPlatform.iOS: + break; + } + title = DefaultTextStyle( + style: centerStyle, + softWrap: false, + overflow: TextOverflow.ellipsis, + child: Semantics( + namesRoute: namesRoute, + child: title, + header: true, + ), + ); + } + + Widget actions; + if (widget.actions != null && widget.actions.isNotEmpty) { + actions = Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: widget.actions, + ); + } else if (hasEndDrawer) { + actions = IconButton( + icon: const Icon(Icons.menu), + onPressed: _handleDrawerButtonEnd, + tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip, + ); + } + + final Widget toolbar = NavigationToolbar( + leading: leading, + middle: title, + trailing: actions, + centerMiddle: widget._getEffectiveCenterTitle(themeData), + middleSpacing: widget.titleSpacing, + ); + + // If the toolbar is allocated less than kToolbarHeight make it + // appear to scroll upwards within its shrinking container. + Widget appBar = ClipRect( + child: CustomSingleChildLayout( + delegate: const _ToolbarContainerLayout(), + child: IconTheme.merge( + data: appBarIconTheme, + child: DefaultTextStyle( + style: sideStyle, + child: toolbar, + ), + ), + ), + ); + if (widget.bottom != null) { + appBar = Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: ConstrainedBox( + constraints: const BoxConstraints(maxHeight: kToolbarHeight), + child: appBar, + ), + ), + widget.bottomOpacity == 1.0 + ? widget.bottom + : Opacity( + opacity: + const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn) + .transform(widget.bottomOpacity), + child: widget.bottom, + ), + ], + ); + } + + // The padding applies to the toolbar and tabbar, not the flexible space. + if (widget.primary) { + appBar = SafeArea( + top: true, + child: appBar, + ); + } + + appBar = Align( + alignment: Alignment.topCenter, + child: appBar, + ); + + if (widget.flexibleSpace != null) { + appBar = Stack( + fit: StackFit.passthrough, + children: [ + widget.flexibleSpace, + appBar, + ], + ); + } + final Brightness brightness = + widget.brightness ?? themeData.primaryColorBrightness; + final SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark + ? SystemUiOverlayStyle.light + : SystemUiOverlayStyle.dark; + + return Semantics( + container: true, + explicitChildNodes: true, + child: AnnotatedRegion( + value: overlayStyle, + child: Material( + color: widget.backgroundColor ?? themeData.primaryColor, + elevation: widget.elevation, + child: appBar, + ), + ), + ); + } +} diff --git a/lib/views/first_page/main_page.dart b/lib/views/first_page/main_page.dart new file mode 100644 index 00000000..53613754 --- /dev/null +++ b/lib/views/first_page/main_page.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; +//import 'package:flutter_wanandroid/common/component_index.dart'; +//import 'package:flutter_wanandroid/ui/pages/main_left_page.dart'; +//import 'package:flutter_wanandroid/ui/pages/page_index.dart'; + +import './main_app_bar.dart'; + +class _Page { + final String labelId; + + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page('titleHome'), + _Page('titleHome'), + _Page('titleHome'), + _Page('titleHome'), +]; + +class MainPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + print("MainPagess build......"); + return DefaultTabController( + length: _allPages.length, + child: Scaffold( + appBar: new MyAppBar( + leading: Container( + child: new ClipOval( + child: Image.network( + 'https://hbimg.huabanimg.com/9bfa0fad3b1284d652d370fa0a8155e1222c62c0bf9d-YjG0Vt_fw658', + scale: 15.0, + ), + ) + ), + centerTitle: true, + title: TabLayout(), + actions: [ + IconButton( + icon: Icon(Icons.search), + onPressed: () { + /// NavigatorUtil.pushPage(context, SearchPage(), + ///pageName: "SearchPage"); + // NavigatorUtil.pushPage(context, TestPage()); + // NavigatorUtil.pushPage(context, DemoApp()); + }) + ], + ), + body: TabBarViewLayout(), +// drawer: Drawer( +// child: MainLeftPage(), +// ), + )); + } +} + +class TabLayout extends StatelessWidget { + @override + Widget build(BuildContext context) { + return TabBar( + isScrollable: true, + labelPadding: EdgeInsets.all(12.0), + indicatorSize: TabBarIndicatorSize.label, + tabs: _allPages + .map((_Page page) => + Tab(text: page.labelId)) + .toList(), + ); + } +} + +class TabBarViewLayout extends StatelessWidget { + Widget buildTabView(BuildContext context, _Page page) { + String labelId = page.labelId; +// switch (labelId) { +// case Ids.titleHome: +// //return HomePage(labelId: labelId); +// return ReposPage(labelId: labelId); +// break; +// case Ids.titleRepos: +// return ReposPage(labelId: labelId); +// break; +// case Ids.titleEvents: +// return EventsPage(labelId: labelId); +// break; +// case Ids.titleSystem: +// return SystemPage(labelId: labelId); +// break; +// default: +// return Container(); +// break; +// } + return Container( + child: new ClipOval( + child: Image.network( + 'https://hbimg.huabanimg.com/9bfa0fad3b1284d652d370fa0a8155e1222c62c0bf9d-YjG0Vt_fw658', + scale: 5.0, + ), + ) + ); + } + + @override + Widget build(BuildContext context) { + print("TabBarViewLayout build......."); + return TabBarView( + children: _allPages.map((_Page page) { + return buildTabView(context, page); + }).toList()); + } +} diff --git a/pubspec.lock b/pubspec.lock index 0ce24601..a62c6a84 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,91 +5,105 @@ packages: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.5.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.0" + version: "2.0.8" + bloc: + dependency: "direct main" + description: + name: bloc + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" city_pickers: dependency: "direct main" description: name: city_pickers - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.16" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.14.11" cookie_jar: dependency: transitive description: name: cookie_jar - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.8" + csslib: + dependency: transitive + description: + name: csslib + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.16.0" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.2" dio: dependency: "direct main" description: name: dio - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.17" event_bus: dependency: "direct main" description: name: event_bus - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" firebase_analytics: dependency: "direct main" description: name: firebase_analytics - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1+2" + version: "2.1.1+3" firebase_core: dependency: "direct main" description: name: firebase_core - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.4" fluro: dependency: "direct main" description: name: fluro - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" flutter: @@ -97,11 +111,18 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.11.1" flutter_markdown: dependency: "direct main" description: name: flutter_markdown - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.0" flutter_test: @@ -113,77 +134,91 @@ packages: dependency: "direct main" description: name: flutter_webview_plugin - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.3" + version: "0.3.4" + html: + dependency: "direct main" + description: + name: html + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.14.0+2" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.4.12+1" intl: dependency: "direct main" description: name: intl - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.15.7" lpinyin: dependency: transitive description: name: lpinyin - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.7" markdown: dependency: transitive description: name: markdown - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.2" + version: "2.0.3" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.12.5" + version: "0.12.3+1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.6" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.6.2" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.0" + version: "1.4.0" quiver: dependency: transitive description: name: quiver - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.2" + version: "2.0.1" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.21.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.4.3" sky_engine: @@ -195,79 +230,79 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.5" + version: "1.5.4" sqflite: dependency: "direct main" description: name: sqflite - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.12.2+1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.9.3" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "1.6.8" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.4" + version: "0.2.2" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.6" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.0+3" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.8" sdks: - dart: ">=2.2.0 <3.0.0" + dart: ">=2.1.0 <3.0.0" flutter: ">=0.5.6 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index b97443ed..ec8cb834 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,9 @@ dependencies: firebase_analytics: ^2.0.2+1 #firebase_auth: ^0.8.3 #auth firebase_core: ^0.3.0 # add dependency for Firebase Core + flutter_bloc: ^0.11.1 + bloc: ^0.12.0 + html: ^0.14.0+2 dev_dependencies: flutter_test: From eae10b59edb338f3e49382de160c6a0c27b533b1 Mon Sep 17 00:00:00 2001 From: "xj.deng" Date: Tue, 30 Apr 2019 16:49:06 +0800 Subject: [PATCH 2/4] add version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 4e6e268e..38df10e9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,7 +7,7 @@ description: flutter_go # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # Read more about versioning at semver.org. -#version: 0.0.5firebase_auth +version: 1.0.0 environment: sdk: ">=2.0.0-dev.68.0 <3.0.0" From 6daca18c998ccc48f2876da4f2b90a9152321fab Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 1 May 2019 00:37:46 +0800 Subject: [PATCH 3/4] =?UTF-8?q?Modfiy=EF=BC=9A=20=E6=94=B9=E9=80=A0?= =?UTF-8?q?=E4=B8=9A=E5=86=85=E8=B5=84=E8=AE=AF=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pubspec.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pubspec.yaml b/pubspec.yaml index 4e6e268e..50f294e6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,9 @@ dependencies: firebase_analytics: ^1.1.0 #firebase_auth: ^0.8.3 #auth firebase_core: ^0.3.4 # add dependency for Firebase Core + flutter_bloc: ^0.11.1 + bloc: ^0.12.0 + html: ^0.14.0+2 dev_dependencies: flutter_test: From 979c2c827c3df5f5f9f681f4f5544b7670f37d3e Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 1 May 2019 00:40:48 +0800 Subject: [PATCH 4/4] =?UTF-8?q?Modfiy=EF=BC=9A=20=E6=94=B9=E9=80=A0?= =?UTF-8?q?=E4=B8=9A=E5=86=85=E8=B5=84=E8=AE=AF=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/views/first_page/search_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/first_page/search_page.dart b/lib/views/first_page/search_page.dart index 130b550a..6d519738 100644 --- a/lib/views/first_page/search_page.dart +++ b/lib/views/first_page/search_page.dart @@ -130,7 +130,7 @@ class _SearchBarPageState extends State { void dispose() { print('dispose'); suggestion.dispatch(SuggestionClearFetch()); - controller.dispose(); + //controller.dispose(); super.dispose(); }