diff --git a/README.md b/README.md index e1c0234f..4a5d76e4 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ iphone下载地址: #### Flutter 是什么? -2018年6月21日Google发布Flutter首个release预览版,作为Google baba大力推出的一种全新的响应式,跨平台,高性能的移动开发框架。Flutter是一个跨平台的移动UI框架,旨在帮助开发者使用一套代码开发高性能、高保真的Android和iOS应用。 +2018年6月21日Google发布Flutter首个release预览版,作为Google 大力推出的一种全新的响应式,跨平台,高性能的移动开发框架。Flutter是一个跨平台的移动UI框架,旨在帮助开发者使用一套代码开发高性能、高保真的Android和iOS应用。 flutter优点主要包括: - 跨平台 diff --git a/android/build.gradle b/android/build.gradle index d4225c79..e81b1a1d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.1.2' + classpath 'com.android.tools.build:gradle:3.2.0' } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 9372d0f3..03824124 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 23 08:50:38 CEST 2017 +#Thu Jan 10 15:37:36 CST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/assets/images/nothing.png b/assets/images/nothing.png new file mode 100644 index 00000000..1279985f Binary files /dev/null and b/assets/images/nothing.png differ diff --git a/lib/common/list_view_item.dart b/lib/common/list_view_item.dart new file mode 100644 index 00000000..ded59961 --- /dev/null +++ b/lib/common/list_view_item.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; +import '../routers/application.dart'; + +class ListViewItem extends StatelessWidget { + final String itemUrl; + final String itemTitle; + final String data; + + const ListViewItem({Key key, this.itemUrl, this.itemTitle, this.data}) + : super(key: key); + + void _launchURL(String url, BuildContext context) async { + if (url.contains("https") || url.contains("http")) { + if (await canLaunch(url)) { + await launch(url); + } else { + throw 'Could not launch $url'; + } + } else { + Application.router.navigateTo(context, "${url}"); + } + } + + @override + Widget build(BuildContext context) { + return Card( + color: Colors.white, + elevation: 4.0, + margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0), + child: ListTile( + onTap: () { + _launchURL(itemUrl, context); + }, + title: Padding( + child: Text( + itemTitle, + style: TextStyle(color: Colors.black, fontSize: 15.0), + ), + padding: EdgeInsets.only(top: 10.0), + ), + subtitle: Row( + children: [ + Padding( + child: Text(data, + style: TextStyle(color: Colors.black54, fontSize: 10.0)), + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), + ) + ], + ), + trailing: + Icon(Icons.keyboard_arrow_right, color: Colors.grey, size: 30.0), + ), + ); + } +} diff --git a/lib/common/myListView.dart b/lib/common/myListView.dart deleted file mode 100644 index ac50f3d2..00000000 --- a/lib/common/myListView.dart +++ /dev/null @@ -1,70 +0,0 @@ - -import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; - -class MyListView extends StatelessWidget { - -final String currCodeUrl; -final String currTitle; -final String developer; - -const MyListView({ Key key,this.currCodeUrl, this.currTitle, this.developer}): -super(key:key); - - - void _launchURL(String url) async { - if (await canLaunch(url)) { - await launch(url); - } else { - throw 'Could not launch $url'; - } - } - - @override - Widget build(BuildContext context) { - return Card( - //color: Colors.primaries[index % Colors.primaries.length], - color: Colors.white, - elevation: 4.0, - margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0), - child:ListTile( - onTap:(){ - print('codeUrl:${currCodeUrl}'); - _launchURL(currCodeUrl); - }, - // contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 1.0), - // leading: Container( - // padding: EdgeInsets.only(right: 12.0), - // decoration: new BoxDecoration( - // border: new Border( - // right: new BorderSide(width: 1.0, color: Colors.grey))), - // child: Icon(smallParts_icon, color: smallParts_Color), - // ), - title: Padding( - child: Text( - - currTitle, - style: TextStyle(color: Colors.black,fontSize:15.0), - - ), - padding: EdgeInsets.only(top: 10.0), - ), - // subtitle: Text("Intermediate", style: TextStyle(color: Colors.white)), - - subtitle: Row( - - children: [ - Padding( - child: Text( developer, style: TextStyle(color: Colors.black54,fontSize:10.0) - ), - padding:EdgeInsets.only(top: 10.0,bottom: 10.0), - ) - //Icon(Icons.linear_scale, color: smallParts_Color), - - ], - ), - trailing: Icon(Icons.keyboard_arrow_right, color: Colors.grey, size: 30.0) - ) - ); - } -} \ No newline at end of file diff --git a/lib/common/provider.dart b/lib/common/provider.dart index d178c46c..8540d671 100644 --- a/lib/common/provider.dart +++ b/lib/common/provider.dart @@ -14,18 +14,21 @@ class Provider { //Get a location using getDatabasesPath String databasesPath = await getDatabasesPath(); String path = join(databasesPath, 'flutter.db'); - List list; - // try { - // db = await openDatabase(path, readOnly: true); + List tables; + try { + db = await openDatabase(path); + tables = await db + .rawQuery('SELECT name FROM sqlite_master WHERE type = "table"'); + print('${tables.length} 7891'); + } catch (e) { + print("Error $e"); + } - // } catch (e) { - // print("Error $e"); - // } - - if (db == null) { + if (tables.length < 3) { // Delete the database await deleteDatabase(path); - + // 关闭上面打开的db,否则无法执行open + db.close(); ByteData data = await rootBundle.load(join("assets", "app.db")); List bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); diff --git a/lib/common/widget_demo.dart b/lib/common/widget_demo.dart index 9747dd43..3a69dfb3 100644 --- a/lib/common/widget_demo.dart +++ b/lib/common/widget_demo.dart @@ -10,6 +10,8 @@ import '../components/markdown.dart'; import '../model/collection.dart'; import '../widgets/index.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import '../event/event-bus.dart'; +import '../event/event-model.dart'; class WidgetDemo extends StatefulWidget { final List contentList; @@ -84,9 +86,11 @@ class _WidgetDemoState extends State { _router = item.routerName; } }); - setState(() { + if(this.mounted){ + setState(() { _hasCollected = list.length > 0; }); + } }); } @@ -100,6 +104,7 @@ class _WidgetDemoState extends State { _hasCollected = false; }); showInSnackBar('已取消收藏'); + ApplicationEvent.event.fire(CollectionEvent(widget.title,true)); return; } print('删除错误'); @@ -113,6 +118,7 @@ class _WidgetDemoState extends State { setState(() { _hasCollected = true; }); + ApplicationEvent.event.fire(CollectionEvent(widget.title,false)); showInSnackBar('收藏成功'); } }); @@ -167,6 +173,7 @@ class _WidgetDemoState extends State { ), floatingActionButton: FloatingActionButton( onPressed: _getCollection, + mini: true, tooltip: '收藏', child: Icon( Icons.star, diff --git a/lib/components/ListRefresh.dart b/lib/components/ListRefresh.dart index dd6a2466..5d388157 100644 --- a/lib/components/ListRefresh.dart +++ b/lib/components/ListRefresh.dart @@ -9,12 +9,11 @@ import 'package:flutter/material.dart'; import 'dart:math'; - class ListRefresh extends StatefulWidget { final renderItem; final requestApi; - const ListRefresh([this.requestApi,this.renderItem]) : super(); + const ListRefresh([this.requestApi, this.renderItem]) : super(); @override State createState() => listRefresh(); @@ -34,7 +33,8 @@ class listRefresh extends State { _getMoreData(); _scrollController.addListener(() { // 如果下拉的当前位置到scroll的最下面 - if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { _getMoreData(); } }); @@ -43,7 +43,7 @@ class listRefresh extends State { /* * 回弹效果 * */ - backElasticEffect(){ + backElasticEffect() { // double edge = 50.0; // double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels; // if (offsetFromBottom < edge) { // 添加一个动画没有更多数据的时候 ListView 向下移动覆盖正在加载更多数据的标志 @@ -58,18 +58,22 @@ class listRefresh extends State { * list探底,执行的具体事件 * */ Future _getMoreData() async { - if (!isLoading && _hasMore) { // 如果上一次异步请求数据完成 同时有数据可以加载 + if (!isLoading && _hasMore) { + // 如果上一次异步请求数据完成 同时有数据可以加载 setState(() => isLoading = true); //if(_hasMore){ // 还有数据可以拉新 List newEntries = await mokeHttpRequest(); //if (newEntries.isEmpty) { _hasMore = (_pageIndex <= _pageTotal); - setState(() { - items.addAll(newEntries); - isLoading = false; - }); + if (this.mounted) { + setState(() { + items.addAll(newEntries); + isLoading = false; + }); + } backElasticEffect(); - }else if (!isLoading && !_hasMore){ // 这样判断,减少以后的绘制 + } else if (!isLoading && !_hasMore) { + // 这样判断,减少以后的绘制 _pageIndex = 0; backElasticEffect(); } @@ -79,12 +83,12 @@ class listRefresh extends State { * 伪装吐出新数据 * */ Future mokeHttpRequest() async { - if(widget.requestApi is Function){ - final listObj = await widget.requestApi({'pageIndex':_pageIndex}); + if (widget.requestApi is Function) { + final listObj = await widget.requestApi({'pageIndex': _pageIndex}); _pageIndex = listObj['pageIndex']; _pageTotal = listObj['total']; return listObj['list']; - }else { + } else { return Future.delayed(Duration(seconds: 2), () { return []; }); @@ -97,20 +101,23 @@ class listRefresh extends State { * */ Future _handleRefresh() async { List newEntries = await mokeHttpRequest(); - setState(() { - items.clear(); - items.addAll(newEntries); - isLoading = false; - _hasMore = true; - return null; - }); + if (this.mounted) { + setState(() { + items.clear(); + items.addAll(newEntries); + isLoading = false; + _hasMore = true; + return null; + }); + } } /* * 加载中的提示 * */ Widget _buildLoadText() { - return Container(child: Padding( + return Container( + child: Padding( padding: const EdgeInsets.all(18.0), child: Center( child: Text("数据没有更多了!!!"), @@ -122,23 +129,28 @@ class listRefresh extends State { * 上提加载loading的widget,如果数据到达极限,显示没有更多 * */ Widget _buildProgressIndicator() { - if(_hasMore){ + if (_hasMore) { return new Padding( padding: const EdgeInsets.all(8.0), child: new Center( - child:Column( - children: [ - new Opacity( - opacity: isLoading ? 1.0 : 0.0, - child: new CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.blue)), - ), - SizedBox(height:20.0), - Text('稍等片刻更精彩...',style: TextStyle(fontSize: 14.0),) - ],) - //child: - ), + child: Column( + children: [ + new Opacity( + opacity: isLoading ? 1.0 : 0.0, + child: new CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.blue)), + ), + SizedBox(height: 20.0), + Text( + '稍等片刻更精彩...', + style: TextStyle(fontSize: 14.0), + ) + ], + ) + //child: + ), ); - }else { + } else { return _buildLoadText(); } } @@ -152,11 +164,11 @@ class listRefresh extends State { @override Widget build(BuildContext context) { return new RefreshIndicator( - child:ListView.builder( + child: ListView.builder( itemCount: items.length + 1, itemBuilder: (context, index) { - if(index == 0 && index != items.length){ - return Container(height:0); + if (index == 0 && index != items.length) { + return Container(height: 0); } if (index == items.length) { //return _buildLoadText(); @@ -165,7 +177,7 @@ class listRefresh extends State { //print('itemsitemsitemsitems:${items[index].title}'); //return ListTile(title: Text("Index${index}:${items[index].title}")); if (widget.renderItem is Function) { - return widget.renderItem(index,items[index]); + return widget.renderItem(index, items[index]); } //return makeCard(index,items[index]); } @@ -175,4 +187,4 @@ class listRefresh extends State { onRefresh: _handleRefresh, ); } -} \ No newline at end of file +} diff --git a/lib/event/event-bus.dart b/lib/event/event-bus.dart new file mode 100644 index 00000000..ce2123df --- /dev/null +++ b/lib/event/event-bus.dart @@ -0,0 +1,5 @@ +import 'package:event_bus/event_bus.dart'; + +class ApplicationEvent{ + static EventBus event; +} \ No newline at end of file diff --git a/lib/event/event-model.dart b/lib/event/event-model.dart new file mode 100644 index 00000000..ec01444a --- /dev/null +++ b/lib/event/event-model.dart @@ -0,0 +1,6 @@ +class CollectionEvent{ + final String widgetName; + final bool isRemove; + // token uid... + CollectionEvent(this.widgetName,this.isRemove); +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 0eff5e0f..7ec4dc7b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,6 +14,8 @@ import 'model/widget.dart'; import './widgets/index.dart'; import 'package:flutter_rookie_book/components/SearchInput.dart'; + + const int ThemeColor = 0xFFC91B3A; class MyApp extends StatelessWidget { diff --git a/lib/views/FirstPage.dart b/lib/views/FirstPage.dart index 75fb6438..965df920 100644 --- a/lib/views/FirstPage.dart +++ b/lib/views/FirstPage.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_rookie_book/common/myListView.dart'; +import 'package:flutter_rookie_book/common/list_view_item.dart'; //import 'package:flutter_rookie_book/components/CompList.dart'; import 'package:flutter_rookie_book/components/ListRefresh.dart' as listComp; import 'package:flutter_rookie_book/components/Pagination.dart'; @@ -63,7 +63,7 @@ class FirstPageState extends State { var myUsername = '${'👲'}: ${item.username} '; var codeUrl = '${item.detailUrl}'; - return new MyListView(currCodeUrl:codeUrl,currTitle: myTitle,developer: myUsername,); + return new ListViewItem(itemUrl:codeUrl,itemTitle: myTitle,data: myUsername,); } @override diff --git a/lib/views/collection_page.dart b/lib/views/collection_page.dart index 55dc5ea8..8147be20 100644 --- a/lib/views/collection_page.dart +++ b/lib/views/collection_page.dart @@ -6,30 +6,123 @@ */ import 'package:flutter/material.dart'; import '../model/collection.dart'; +import '../routers/application.dart'; +import '../event/event-bus.dart'; +import '../event/event-model.dart'; +import 'package:event_bus/event_bus.dart'; class CollectionPage extends StatefulWidget { _CollectionPageState createState() => _CollectionPageState(); } class _CollectionPageState extends State { + _CollectionPageState() { + final eventBus = new EventBus(); + ApplicationEvent.event = eventBus; + } CollectionControlModel _collectionControl = new CollectionControlModel(); - List _collectionList = []; + List _collectionList; + ScrollController _scrollController = new ScrollController(); @override void initState() { - // TODO: implement initState super.initState(); + _getList(); + ApplicationEvent.event.on().listen((event) { + _getList(); + }); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + void _getList() { + _collectionList = []; + _collectionControl.getAllCollection().then((resultList) { + resultList.forEach((item) { + _collectionList.add(item); + }); + if (this.mounted) { + setState(() { + _collectionList = _collectionList; + }); + } + }); + } + + Widget _renderList(context, index) { + if (index == 0) { + return Container( + height: 40.0, + padding: const EdgeInsets.only(left: 10.0), + child: Row( + children: [ + Icon( + Icons.warning, + size: 22.0, + ), + SizedBox( + width: 5.0, + ), + Text('模拟器重新运行会丢失收藏'), + ], + ), + ); + } + return Container( + padding: const EdgeInsets.all(10.0), + margin: const EdgeInsets.only(bottom: 7.0), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + new BoxShadow( + color: const Color(0xFFd0d0d0), + blurRadius: 1.0, + spreadRadius: 2.0, + offset: Offset(3.0, 2.0), + ), + ], + ), + child: ListTile( + title: Text( + _collectionList[index - 1].name, + style: TextStyle(fontSize: 17.0), + ), + trailing: + Icon(Icons.keyboard_arrow_right, color: Colors.grey, size: 30.0), + onTap: () { + Application.router + .navigateTo(context, "${_collectionList[index - 1].router}"); + }, + ), + ); } @override Widget build(BuildContext context) { - _collectionControl.getAllCollection().then((resultList) { - _collectionList = resultList; - _collectionList.forEach((item){ - print(item.toMap()); - }); - }); - return Container( - child: Text('敬请期待'), + print(_collectionList); + if (_collectionList.length == 0) { + return ListView( + children: [ + Column( + children: [ + Image.asset( + 'assets/images/nothing.png', + fit: BoxFit.contain, + width: MediaQuery.of(context).size.width / 2, + ), + Text('暂无收藏,赶紧去收藏一个吧!'), + ], + ), + ], + ); + } + return ListView.builder( + itemBuilder: _renderList, + itemCount: _collectionList.length + 1, + controller: _scrollController, ); } }