mirror of
https://github.com/alibaba/flutter-go.git
synced 2025-07-15 03:04:25 +08:00
merge develop
This commit is contained in:
BIN
assets/images/ali_connors.png
Normal file
BIN
assets/images/ali_connors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
flutter_01.png
Normal file
BIN
flutter_01.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
35
lib/blocs/bak/search_api.dart
Normal file
35
lib/blocs/bak/search_api.dart
Normal file
@ -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<List<SearchResult>> 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<SearchResult> res = [];
|
||||||
|
// app.forEach((f) {
|
||||||
|
// res.add(
|
||||||
|
// SearchResult(
|
||||||
|
// title: f.text,
|
||||||
|
// source: f.attributes["data-url"] ?? f.attributes["href"],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Api api = Api();
|
35
lib/blocs/bak/search_bloc.dart
Normal file
35
lib/blocs/bak/search_bloc.dart
Normal file
@ -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<SearchEvent, SearchState> {
|
||||||
|
@override
|
||||||
|
SearchState get initialState => SearchUninitialized();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<SearchState> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
lib/blocs/bak/search_event.dart
Normal file
18
lib/blocs/bak/search_event.dart
Normal file
@ -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:获取搜索结果事件';
|
||||||
|
}
|
14
lib/blocs/bak/search_result.dart
Normal file
14
lib/blocs/bak/search_result.dart
Normal file
@ -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});
|
||||||
|
}
|
37
lib/blocs/bak/search_state.dart
Normal file
37
lib/blocs/bak/search_state.dart
Normal file
@ -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<SearchResult> res;
|
||||||
|
|
||||||
|
SearchLoaded({
|
||||||
|
this.res,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'SearchLoaded:加载完毕';
|
||||||
|
}
|
80
lib/blocs/bak/search_widget.dart
Normal file
80
lib/blocs/bak/search_widget.dart
Normal file
@ -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<SearchWidget> {
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
71
lib/blocs/industry_api.dart
Normal file
71
lib/blocs/industry_api.dart
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* 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 'package:html/parser.dart' show parse;
|
||||||
|
import './industry_model.dart';
|
||||||
|
import './search_result.dart';
|
||||||
|
|
||||||
|
var dio = new Dio();
|
||||||
|
//class Api2 {
|
||||||
|
// /// 关键字提示(起点)
|
||||||
|
// Future<List<String>> 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<String> 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<List<SearchResult>> 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 flutter");
|
||||||
|
var document = parse(response.data);
|
||||||
|
var app = document.querySelectorAll('.res-title a');
|
||||||
|
///print('1=====>${query}');
|
||||||
|
///print('2=====>${response.data}');
|
||||||
|
////print('3=====>${app}');
|
||||||
|
List<SearchResult> 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();
|
41
lib/blocs/industry_bloc.dart
Normal file
41
lib/blocs/industry_bloc.dart
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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<SuggestionEvent, SuggestionState> {
|
||||||
|
@override
|
||||||
|
SuggestionState get initialState => SuggestionUninitialized();
|
||||||
|
@override
|
||||||
|
Stream<SuggestionState> mapEventToState(SuggestionEvent event)async* {
|
||||||
|
//Stream<SuggestionState> mapEventToState(SuggestionState currentState, SuggestionEvent event,) async* {
|
||||||
|
if (event is SuggestionFetch) {
|
||||||
|
//print('event==>${event}');
|
||||||
|
try {
|
||||||
|
yield SuggestionLoading();
|
||||||
|
final res = await api.suggestion(event.query);
|
||||||
|
print('res====>${res}');
|
||||||
|
yield SuggestionLoaded(res: res);
|
||||||
|
} catch (_) {
|
||||||
|
yield SuggestionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (event is SuggestionClearFetch) {
|
||||||
|
//print('event==>${event}');
|
||||||
|
try {
|
||||||
|
yield SuggestionUninitialized();
|
||||||
|
} catch (_) {
|
||||||
|
yield SuggestionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
lib/blocs/industry_event.dart
Normal file
26
lib/blocs/industry_event.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* 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:获取关键字提示事件';
|
||||||
|
}
|
||||||
|
|
||||||
|
class SuggestionClearFetch extends SuggestionEvent {
|
||||||
|
final String query;
|
||||||
|
|
||||||
|
SuggestionClearFetch({this.query});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'SuggestionClearFetch:清空界面';
|
||||||
|
}
|
79
lib/blocs/industry_main.dart
Normal file
79
lib/blocs/industry_main.dart
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* 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:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import './industry_bloc.dart';
|
||||||
|
import './industry_event.dart';
|
||||||
|
import './industry_state.dart';
|
||||||
|
|
||||||
|
final SuggestionBloc suggestion = SuggestionBloc();
|
||||||
|
|
||||||
|
class IndustryPage extends StatefulWidget {
|
||||||
|
final Function itemTitle;
|
||||||
|
IndustryPage({Key key,this.itemTitle}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_IndustryState createState() => _IndustryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _IndustryState extends State<IndustryPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// TextField(
|
||||||
|
// autofocus: true,
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// onSubmitted: (text) {
|
||||||
|
// print('onSubmitted:${text}');
|
||||||
|
// suggestion.dispatch(SuggestionFetch(query: text));
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
Expanded(
|
||||||
|
child: BlocBuilder(
|
||||||
|
bloc: suggestion,
|
||||||
|
builder: (BuildContext context, SuggestionState state) {
|
||||||
|
print('BlocBuilder----${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) {
|
||||||
|
if (state.res.length == 0) {
|
||||||
|
return Center(
|
||||||
|
child: Text('没有适合的结果,更换查询条件试试'),
|
||||||
|
);
|
||||||
|
}else {
|
||||||
|
if (widget.itemTitle is Function) {
|
||||||
|
return widget.itemTitle(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
//suggestion.dispose();//添加这个第二次进入会失灵
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
72
lib/blocs/industry_model.dart
Normal file
72
lib/blocs/industry_model.dart
Normal file
@ -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> suggestions;
|
||||||
|
int code;
|
||||||
|
|
||||||
|
Suggestion({this.query, this.suggestions, this.code});
|
||||||
|
|
||||||
|
Suggestion.fromJson(Map<String, dynamic> json) {
|
||||||
|
query = json['query'];
|
||||||
|
if (json['suggestions'] != null) {
|
||||||
|
suggestions = new List<Suggestions>();
|
||||||
|
json['suggestions'].forEach((v) {
|
||||||
|
suggestions.add(new Suggestions.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
code = json['code'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
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<String, dynamic> json) {
|
||||||
|
data = json['data'] != null ? new Data.fromJson(json['data']) : null;
|
||||||
|
value = json['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
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<String, dynamic> json) {
|
||||||
|
category = json['category'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['category'] = this.category;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
34
lib/blocs/industry_state.dart
Normal file
34
lib/blocs/industry_state.dart
Normal file
@ -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:加载完毕';
|
||||||
|
}
|
14
lib/blocs/search_result.dart
Normal file
14
lib/blocs/search_result.dart
Normal file
@ -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});
|
||||||
|
}
|
@ -42,6 +42,18 @@ class _BannerState extends State<HomeBanner> {
|
|||||||
timer.cancel();
|
timer.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// pagination 的计数器
|
||||||
|
Widget _numberIndicator(BuildContext context, int index, int itemCount) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black45, borderRadius: BorderRadius.circular(20.0)),
|
||||||
|
margin: EdgeInsets.only(top: 10.0, right: 5.0),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0),
|
||||||
|
child: Text("${++index}/$itemCount",
|
||||||
|
style: TextStyle( color: Colors.white70, fontSize: 12.0, fontWeight:FontWeight.bold )),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -54,6 +66,11 @@ class _BannerState extends State<HomeBanner> {
|
|||||||
onPageChanged: _onPageChanged,
|
onPageChanged: _onPageChanged,
|
||||||
children: _buildItems(),),
|
children: _buildItems(),),
|
||||||
_buildIndicator(), // 下面的小点
|
_buildIndicator(), // 下面的小点
|
||||||
|
Positioned(//方法二
|
||||||
|
top: 0.0,
|
||||||
|
right: 0.0,
|
||||||
|
child: _numberIndicator(context,virtualIndex,widget.bannerStories.length),
|
||||||
|
)
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import 'routers/application.dart';
|
|||||||
|
|
||||||
import 'package:flutter_go/utils/provider.dart';
|
import 'package:flutter_go/utils/provider.dart';
|
||||||
import 'package:flutter_go/utils/shared_preferences.dart';
|
import 'package:flutter_go/utils/shared_preferences.dart';
|
||||||
import 'package:flutter_go/views/first_page/home.dart';
|
import 'package:flutter_go/views/home.dart';
|
||||||
import 'package:flutter_go/model/search_history.dart';
|
import 'package:flutter_go/model/search_history.dart';
|
||||||
import 'package:flutter_go/utils/analytics.dart' as Analytics;
|
import 'package:flutter_go/utils/analytics.dart' as Analytics;
|
||||||
//import 'views/welcome_page/index.dart';
|
//import 'views/welcome_page/index.dart';
|
||||||
|
@ -5,7 +5,7 @@ import 'package:flutter_go/components/category.dart';
|
|||||||
import '../widgets/404.dart';
|
import '../widgets/404.dart';
|
||||||
import 'package:flutter_go/components/full_screen_code_dialog.dart';
|
import 'package:flutter_go/components/full_screen_code_dialog.dart';
|
||||||
import 'package:flutter_go/views/web_page/web_view_page.dart';
|
import 'package:flutter_go/views/web_page/web_view_page.dart';
|
||||||
import 'package:flutter_go/views/first_page/home.dart';
|
import 'package:flutter_go/views/home.dart';
|
||||||
|
|
||||||
// app的首页
|
// app的首页
|
||||||
var homeHandler = new Handler(
|
var homeHandler = new Handler(
|
||||||
|
@ -80,8 +80,8 @@ class FirstPageState extends State<FirstPage> with AutomaticKeepAliveClientMixin
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 每个item的样式
|
||||||
Widget makeCard(index,item){
|
Widget makeCard(index,item){
|
||||||
|
|
||||||
var myTitle = '${item.title}';
|
var myTitle = '${item.title}';
|
||||||
var myUsername = '${'👲'}: ${item.username} ';
|
var myUsername = '${'👲'}: ${item.username} ';
|
||||||
var codeUrl = '${item.detailUrl}';
|
var codeUrl = '${item.detailUrl}';
|
||||||
@ -92,18 +92,18 @@ class FirstPageState extends State<FirstPage> with AutomaticKeepAliveClientMixin
|
|||||||
return
|
return
|
||||||
Column(
|
Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Stack(
|
Stack(
|
||||||
//alignment: const FractionalOffset(0.9, 0.1),//方法一
|
//alignment: const FractionalOffset(0.9, 0.1),//方法一
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Pagination(),
|
Pagination(),
|
||||||
Positioned(//方法二
|
Positioned(//方法二
|
||||||
top: 10.0,
|
top: 10.0,
|
||||||
left: 0.0,
|
left: 0.0,
|
||||||
child: DisclaimerMsg(key:key,pWidget:this)
|
child: DisclaimerMsg(key:key,pWidget:this)
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
SizedBox(height: 1, child:Container(color: Theme.of(context).primaryColor)),
|
SizedBox(height: 1, child:Container(color: Theme.of(context).primaryColor)),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
415
lib/views/first_page/main_app_bar.dart
Normal file
415
lib/views/first_page/main_app_bar.dart
Normal file
@ -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: <Widget>[
|
||||||
|
/// IconButton(
|
||||||
|
/// icon: Icon(Icons.shopping_cart),
|
||||||
|
/// tooltip: 'Open shopping cart',
|
||||||
|
/// onPressed: () {
|
||||||
|
/// // ...
|
||||||
|
/// },
|
||||||
|
/// ),
|
||||||
|
/// ],
|
||||||
|
/// ),
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
final List<Widget> 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<MyAppBar> {
|
||||||
|
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<dynamic> 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<dynamic> && 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: <Widget>[
|
||||||
|
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>[
|
||||||
|
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<SystemUiOverlayStyle>(
|
||||||
|
value: overlayStyle,
|
||||||
|
child: Material(
|
||||||
|
color: widget.backgroundColor ?? themeData.primaryColor,
|
||||||
|
elevation: widget.elevation,
|
||||||
|
child: appBar,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
106
lib/views/first_page/main_page.dart
Normal file
106
lib/views/first_page/main_page.dart
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import './first_page.dart';
|
||||||
|
import './sub_page.dart';
|
||||||
|
import './main_app_bar.dart';
|
||||||
|
import './search_page.dart';
|
||||||
|
|
||||||
|
class _Page {
|
||||||
|
final String labelId;
|
||||||
|
|
||||||
|
_Page(this.labelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<_Page> _allPages = <_Page>[
|
||||||
|
_Page('项目1'),
|
||||||
|
_Page('项目2'),
|
||||||
|
_Page('项目3'),
|
||||||
|
_Page('项目4'),
|
||||||
|
];
|
||||||
|
|
||||||
|
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: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.search),
|
||||||
|
onPressed: () {
|
||||||
|
pushPage(context, SearchPage(), pageName: "SearchPage");
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: TabBarViewLayout(),
|
||||||
|
// drawer: Drawer(
|
||||||
|
// child: MainLeftPage(),
|
||||||
|
// ),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pushPage(BuildContext context, Widget page, {String pageName}) {
|
||||||
|
if (context == null || page == null) return;
|
||||||
|
Navigator.push(context, CupertinoPageRoute<void>(builder: (ctx) => page));
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabLayout extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return TabBar(
|
||||||
|
isScrollable: true,
|
||||||
|
//labelPadding: EdgeInsets.all(12.0),
|
||||||
|
labelPadding: EdgeInsets.only(top: 12.0,left: 12.0,right: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 '项目1':
|
||||||
|
return FirstPage();
|
||||||
|
break;
|
||||||
|
case '项目2':
|
||||||
|
return SubPage();
|
||||||
|
break;
|
||||||
|
case '项目3':
|
||||||
|
return SubPage();
|
||||||
|
break;
|
||||||
|
case '项目4':
|
||||||
|
return SubPage();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return Container();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
print("TabBarViewLayout build.......");
|
||||||
|
return TabBarView(
|
||||||
|
children: _allPages.map((_Page page) {
|
||||||
|
return buildTabView(context, page);
|
||||||
|
}).toList());
|
||||||
|
}
|
||||||
|
}
|
189
lib/views/first_page/search_page.dart
Normal file
189
lib/views/first_page/search_page.dart
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'dart:ui';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter_go/blocs/industry_main.dart' as Industry;
|
||||||
|
import 'package:flutter_go/blocs/industry_event.dart';
|
||||||
|
import 'package:flutter_go/routers/application.dart';
|
||||||
|
import 'package:flutter_go/routers/routers.dart';
|
||||||
|
|
||||||
|
final _industryPage = Industry.IndustryPage(itemTitle: (state){
|
||||||
|
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);
|
||||||
|
final itemTitle = state.res[index].title;
|
||||||
|
final itemUrl = state.res[index].source;
|
||||||
|
Application.router.navigateTo(context, '${Routes.webViewPage}?title=${Uri.encodeComponent(itemTitle)}&url=${Uri.encodeComponent(itemUrl)}');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: state.res.length,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
final suggestion = Industry.suggestion;
|
||||||
|
final searchBarPage = SearchBarPage();
|
||||||
|
|
||||||
|
class SearchPage extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
/// print('suggestion::${Industry.suggestion}');
|
||||||
|
return Scaffold(
|
||||||
|
appBar: PreferredSize(
|
||||||
|
preferredSize: Size(double.infinity, 52), // 44 is the height
|
||||||
|
child: AppBar(title: searchBarPage)
|
||||||
|
),
|
||||||
|
//body: ProgressView(),
|
||||||
|
body: _industryPage,
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
child: const Icon(Icons.search),
|
||||||
|
onPressed: () {
|
||||||
|
//print('searchBarPage=====>${controller.text}');
|
||||||
|
//print('searchBarPage=====>${that.getResultsDebounced}');
|
||||||
|
if(that is _SearchBarPageState && that.getResultsDebounced is Function && controller.text is String ) {
|
||||||
|
that.getResultsDebounced(controller.text);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 加载loading
|
||||||
|
class ProgressView extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 24.0,
|
||||||
|
height: 24.0,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchBarPage extends StatefulWidget{
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _SearchBarPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final TextEditingController controller = TextEditingController();
|
||||||
|
var that;
|
||||||
|
class _SearchBarPageState extends State<SearchBarPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
that = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer _resultsTimer;
|
||||||
|
bool _loading = false;
|
||||||
|
String oldKey;
|
||||||
|
/// 防抖函数
|
||||||
|
Future getResultsDebounced(String text) async {
|
||||||
|
if(oldKey == text){
|
||||||
|
print('请求内容重复');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (text == '' || !mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_loading = true;
|
||||||
|
if (_resultsTimer != null && _resultsTimer.isActive) {
|
||||||
|
_resultsTimer.cancel();
|
||||||
|
}
|
||||||
|
_resultsTimer = new Timer(new Duration(milliseconds: 400), () async {
|
||||||
|
_loading = true;
|
||||||
|
if(mounted){
|
||||||
|
suggestion.dispatch(SuggestionFetch(query: text));
|
||||||
|
}
|
||||||
|
oldKey = text;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void onSearchTextChanged(String text){
|
||||||
|
print('onSearchTextChanged:${text}');
|
||||||
|
//suggestion.dispatch(SuggestionFetch(query: text));
|
||||||
|
getResultsDebounced(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
print('dispose');
|
||||||
|
suggestion.dispatch(SuggestionClearFetch());
|
||||||
|
//controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
//color: Colors.amber,
|
||||||
|
child: Padding(
|
||||||
|
//padding: EdgeInsets.only(top: MediaQueryData.fromWindow(window).padding.top,),
|
||||||
|
padding: EdgeInsets.all(0.0),
|
||||||
|
child: Container(
|
||||||
|
//height: 162.0,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(6.0),
|
||||||
|
child: Card(
|
||||||
|
child: Container(
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
SizedBox(width: 5.0,),
|
||||||
|
Icon(Icons.search, color: Colors.grey,size: 18.0,),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: TextField(
|
||||||
|
controller: controller,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
contentPadding: EdgeInsets.only(top: 0.0),
|
||||||
|
hintText: '搜索全局flutter知识库',
|
||||||
|
hintStyle:TextStyle(fontSize: 12.0),
|
||||||
|
border: InputBorder.none
|
||||||
|
),
|
||||||
|
onChanged: onSearchTextChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.cancel),
|
||||||
|
color: Colors.grey,
|
||||||
|
iconSize: 18.0,
|
||||||
|
onPressed: () {
|
||||||
|
controller.clear();
|
||||||
|
// onSearchTextChanged('');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
125
lib/views/first_page/sub_page.dart
Normal file
125
lib/views/first_page/sub_page.dart
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_go/components/list_view_item.dart';
|
||||||
|
import 'package:flutter_go/components/list_refresh.dart' as listComp;
|
||||||
|
import 'package:flutter_go/components/pagination.dart';
|
||||||
|
import 'package:flutter_go/views/first_page/first_page_item.dart';
|
||||||
|
import 'package:flutter_go/components/disclaimer_msg.dart';
|
||||||
|
import 'package:flutter_go/utils/net_utils.dart';
|
||||||
|
|
||||||
|
// ValueKey<String> key;
|
||||||
|
|
||||||
|
class SubPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
SubPageState createState() => SubPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubPageState extends State<SubPage> with AutomaticKeepAliveClientMixin{
|
||||||
|
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
|
||||||
|
Future<bool> _unKnow;
|
||||||
|
GlobalKey<DisclaimerMsgState> key;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
if (key == null) {
|
||||||
|
key = GlobalKey<DisclaimerMsgState>();
|
||||||
|
// key = const Key('__RIKEY1__');
|
||||||
|
//获取sharePre
|
||||||
|
_unKnow = _prefs.then((SharedPreferences prefs) {
|
||||||
|
return (prefs.getBool('disclaimer::Boolean') ?? false);
|
||||||
|
});
|
||||||
|
|
||||||
|
/// 判断是否需要弹出免责声明,已经勾选过不在显示,就不会主动弹
|
||||||
|
_unKnow.then((bool value) {
|
||||||
|
new Future.delayed(const Duration(seconds: 1),(){
|
||||||
|
if (!value && key.currentState is DisclaimerMsgState && key.currentState.showAlertDialog is Function) {
|
||||||
|
key.currentState.showAlertDialog(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Future<Map> getIndexListData([Map<String, dynamic> params]) async {
|
||||||
|
const juejin_flutter = 'https://timeline-merger-ms.juejin.im/v1/get_tag_entry?src=web&tagId=5a96291f6fb9a0535b535438';
|
||||||
|
var pageIndex = (params is Map) ? params['pageIndex'] : 0;
|
||||||
|
final _param = {'page':pageIndex,'pageSize':20,'sort':'rankIndex'};
|
||||||
|
var responseList = [];
|
||||||
|
var pageTotal = 0;
|
||||||
|
|
||||||
|
try{
|
||||||
|
var response = await NetUtils.get(juejin_flutter, params: _param);
|
||||||
|
responseList = response['d']['entrylist'];
|
||||||
|
pageTotal = response['d']['total'];
|
||||||
|
if (!(pageTotal is int) || pageTotal <= 0) {
|
||||||
|
pageTotal = 0;
|
||||||
|
}
|
||||||
|
}catch(e){
|
||||||
|
|
||||||
|
}
|
||||||
|
pageIndex += 1;
|
||||||
|
List resultList = new List();
|
||||||
|
for (int i = 0; i < responseList.length; i++) {
|
||||||
|
try {
|
||||||
|
FirstPageItem cellData = new FirstPageItem.fromJson(responseList[i]);
|
||||||
|
resultList.add(cellData);
|
||||||
|
} catch (e) {
|
||||||
|
// No specified type, handles all
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, dynamic> result = {"list":resultList, 'total':pageTotal, 'pageIndex':pageIndex};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget makeCard(index,item){
|
||||||
|
|
||||||
|
var myTitle = '${item.title}';
|
||||||
|
var myUsername = '${'👲'}: ${item.username} ';
|
||||||
|
var codeUrl = '${item.detailUrl}';
|
||||||
|
return new ListViewItem(itemUrl:codeUrl,itemTitle: myTitle,data: myUsername,);
|
||||||
|
}
|
||||||
|
|
||||||
|
headerView(){
|
||||||
|
return
|
||||||
|
Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Stack(
|
||||||
|
//alignment: const FractionalOffset(0.9, 0.1),//方法一
|
||||||
|
children: <Widget>[
|
||||||
|
Pagination(),
|
||||||
|
Positioned(//方法二
|
||||||
|
top: 10.0,
|
||||||
|
left: 0.0,
|
||||||
|
child: DisclaimerMsg(key:key,pWidget:this)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
SizedBox(height: 1, child:Container(color: Theme.of(context).primaryColor)),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
|
return new Column(
|
||||||
|
children: <Widget>[
|
||||||
|
new Expanded(
|
||||||
|
child: listComp.ListRefresh(getIndexListData,makeCard)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -89,12 +89,14 @@ class _MyHomePageState extends State<AppPage>
|
|||||||
});
|
});
|
||||||
searchHistoryList
|
searchHistoryList
|
||||||
.add(SearchHistory(name: targetName, targetRouter: targetRouter));
|
.add(SearchHistory(name: targetName, targetRouter: targetRouter));
|
||||||
print("searchHistoryList ${searchHistoryList.toString()}");
|
print("searchHistoryList1 ${searchHistoryList.toString()}");
|
||||||
|
print("searchHistoryList2 ${targetRouter}");
|
||||||
|
print("searchHistoryList3 ${widgetPoint.name}");
|
||||||
Application.router.navigateTo(context, "$targetRouter");
|
Application.router.navigateTo(context, "$targetRouter");
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildSearchInput(BuildContext context) {
|
Widget buildSearchInput(BuildContext context) {
|
||||||
return new SearchInput((value) async {
|
return new SearchInput((value) async {
|
||||||
if (value != '') {
|
if (value != '') {
|
||||||
List<WidgetPoint> list = await widgetControl.search(value);
|
List<WidgetPoint> list = await widgetControl.search(value);
|
||||||
return list
|
return list
|
||||||
@ -103,7 +105,7 @@ class _MyHomePageState extends State<AppPage>
|
|||||||
icon: WidgetName2Icon.icons[item.name] ?? null,
|
icon: WidgetName2Icon.icons[item.name] ?? null,
|
||||||
text: 'widget',
|
text: 'widget',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
onWidgetTap(item, context);
|
onWidgetTap(item, context);
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
@ -113,6 +115,7 @@ class _MyHomePageState extends State<AppPage>
|
|||||||
}, (value) {}, () {});
|
}, (value) {}, () {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return new Scaffold(
|
return new Scaffold(
|
||||||
@ -124,7 +127,7 @@ class _MyHomePageState extends State<AppPage>
|
|||||||
currentIndex: _currentIndex,
|
currentIndex: _currentIndex,
|
||||||
//修改 页面
|
//修改 页面
|
||||||
onTap: _ItemTapped,
|
onTap: _ItemTapped,
|
||||||
//shifting :按钮点击移动效果,超过5个button不支持
|
//shifting :按钮点击移动效果
|
||||||
//fixed:固定
|
//fixed:固定
|
||||||
type: BottomNavigationBarType.fixed,
|
type: BottomNavigationBarType.fixed,
|
||||||
|
|
35
pubspec.lock
35
pubspec.lock
@ -15,6 +15,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.8"
|
version: "2.0.8"
|
||||||
|
bloc:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: bloc
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -50,6 +57,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.8"
|
version: "0.0.8"
|
||||||
|
csslib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: csslib
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -97,6 +111,13 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_bloc:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_bloc
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.11.1"
|
||||||
flutter_markdown:
|
flutter_markdown:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -116,6 +137,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.4"
|
version: "0.3.4"
|
||||||
|
html:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: html
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.14.0+2"
|
||||||
image_picker:
|
image_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -179,6 +207,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
rxdart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: rxdart
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.21.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -7,7 +7,7 @@ description: flutter_go
|
|||||||
# Both the version and the builder number may be overridden in flutter
|
# Both the version and the builder number may be overridden in flutter
|
||||||
# build by specifying --build-name and --build-number, respectively.
|
# build by specifying --build-name and --build-number, respectively.
|
||||||
# Read more about versioning at semver.org.
|
# Read more about versioning at semver.org.
|
||||||
#version: 0.0.5firebase_auth
|
version: 1.0.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||||
@ -35,6 +35,9 @@ dependencies:
|
|||||||
firebase_analytics: ^1.1.0
|
firebase_analytics: ^1.1.0
|
||||||
#firebase_auth: ^0.8.3 #auth
|
#firebase_auth: ^0.8.3 #auth
|
||||||
firebase_core: ^0.3.4 # add dependency for Firebase Core
|
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:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user