From f1414057e0a10803f00dc9aa8c8ea531e8a2633d Mon Sep 17 00:00:00 2001 From: Rongjian Zhang Date: Sun, 3 Feb 2019 23:10:10 +0800 Subject: [PATCH] feat: add repo item, extract list group widget --- lib/screens/notifications.dart | 29 +---- lib/screens/user.dart | 201 +++++++++++++++++------------ lib/widgets/list_group.dart | 39 ++++++ lib/widgets/notification_item.dart | 83 ++++++------ lib/widgets/refresh_scaffold.dart | 13 +- lib/widgets/repo_item.dart | 43 ++++++ 6 files changed, 250 insertions(+), 158 deletions(-) create mode 100644 lib/widgets/list_group.dart create mode 100644 lib/widgets/repo_item.dart diff --git a/lib/screens/notifications.dart b/lib/screens/notifications.dart index 9eb0847..4ed7c1c 100644 --- a/lib/screens/notifications.dart +++ b/lib/screens/notifications.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart' hide Notification; import 'package:flutter/cupertino.dart' hide Notification; import '../providers/settings.dart'; import '../providers/notification.dart'; -// import '../screens/screens.dart'; import '../widgets/notification_item.dart'; import '../widgets/loading.dart'; +import '../widgets/list_group.dart'; import '../utils/utils.dart'; class NotificationGroup { @@ -39,28 +39,13 @@ class NotificationScreenState extends State { var group = groups[index]; - return Padding( - padding: EdgeInsets.all(8), - child: Container( - decoration: BoxDecoration(border: Border.all(color: Colors.black12)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.all(4), - color: Colors.black12, - child: Text( - group.fullName, - style: TextStyle(color: Colors.black, fontSize: 15), - ), - ), - Column( - children: group.items - .map((item) => NotificationItem(item: item)) - .toList()) - ], - ), + return ListGroup( + title: Text( + group.fullName, + style: TextStyle(color: Colors.black, fontSize: 15), ), + items: group.items, + itemBuilder: (item) => NotificationItem(item: item), ); } diff --git a/lib/screens/user.dart b/lib/screens/user.dart index b38b9b8..d148481 100644 --- a/lib/screens/user.dart +++ b/lib/screens/user.dart @@ -3,6 +3,8 @@ import 'package:flutter/cupertino.dart'; import '../widgets/refresh_scaffold.dart'; import '../widgets/avatar.dart'; import '../widgets/link.dart'; +import '../widgets/list_group.dart'; +import '../widgets/repo_item.dart'; import '../utils/utils.dart'; Future queryUser(String login) async { @@ -29,9 +31,17 @@ Future queryUser(String login) async { login } name + description stargazers { totalCount } + forks { + totalCount + } + primaryLanguage { + color + name + } } } pinnedRepositories(first: 6) { @@ -40,6 +50,17 @@ Future queryUser(String login) async { login } name + description + stargazers { + totalCount + } + forks { + totalCount + } + primaryLanguage { + color + name + } } } } @@ -49,7 +70,7 @@ Future queryUser(String login) async { } final GlobalKey _refreshIndicatorKey = - new GlobalKey(); + GlobalKey(); class UserScreen extends StatefulWidget { final String login; @@ -60,7 +81,7 @@ class UserScreen extends StatefulWidget { } class _UserScreenState extends State { - var payload; + Map payload = {}; @override Widget build(BuildContext context) { @@ -71,97 +92,105 @@ class _UserScreenState extends State { payload = _payload; }); }, - title: widget.login, - body: Column( - children: [ - Container( - padding: EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black12))), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Avatar( - login: widget.login, - url: payload['avatarUrl'], - size: 28, - ), - Padding(padding: EdgeInsets.only(left: 10)), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(payload['name'], style: TextStyle(height: 1.2)), - Padding(padding: EdgeInsets.only(top: 10)), - Row(children: [ - Icon( - Octicons.mail, - color: Colors.black54, - size: 16, - ), - Padding(padding: EdgeInsets.only(left: 4)), - Text( - payload['email'], - style: TextStyle(color: Colors.black54, fontSize: 16), - ) - ]) - ], + title: Text(widget.login), + bodyBuilder: () { + return Column( + children: [ + Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black12))), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Avatar( + login: widget.login, + url: payload['avatarUrl'], + size: 28, ), - ) - ], + Padding(padding: EdgeInsets.only(left: 10)), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(payload['name'], style: TextStyle(height: 1.2)), + Padding(padding: EdgeInsets.only(top: 10)), + Row(children: [ + Icon( + Octicons.mail, + color: Colors.black54, + size: 16, + ), + Padding(padding: EdgeInsets.only(left: 4)), + Text( + payload['email'], + style: + TextStyle(color: Colors.black54, fontSize: 16), + ) + ]) + ], + ), + ) + ], + ), ), - ), - Container( - padding: EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black12))), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Link( - child: Column( - children: [ - Text(payload['repositories']['totalCount'].toString()), - Text('Repos') - ], + Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black12))), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Link( + child: Column( + children: [ + Text(payload['repositories']['totalCount'].toString()), + Text('Repos') + ], + ), + onTap: () {}, ), - onTap: () {}, - ), - Link( - child: Column( - children: [ - Text(payload['starredRepositories']['totalCount'] - .toString()), - Text('Stars') - ], + Link( + child: Column( + children: [ + Text(payload['starredRepositories']['totalCount'] + .toString()), + Text('Stars') + ], + ), + onTap: () {}, ), - onTap: () {}, - ), - Link( - child: Column( - children: [ - Text(payload['followers']['totalCount'].toString()), - Text('Followers'), - ], + Link( + child: Column( + children: [ + Text(payload['followers']['totalCount'].toString()), + Text('Followers'), + ], + ), + onTap: () { + // print(1); + }, ), - onTap: () { - // print(1); - }, - ), - Link( - child: Column( - children: [ - Text(payload['following']['totalCount'].toString()), - Text('Following') - ], + Link( + child: Column( + children: [ + Text(payload['following']['totalCount'].toString()), + Text('Following') + ], + ), + onTap: () {}, ), - onTap: () {}, - ), - ], + ], + ), ), - ), - ], - ), + ListGroup( + title: Text('Repos'), + items: payload['repositories']['nodes'], + itemBuilder: (item) => RepoItem(item), + ) + ], + ); + }, ); } } diff --git a/lib/widgets/list_group.dart b/lib/widgets/list_group.dart new file mode 100644 index 0000000..fc27816 --- /dev/null +++ b/lib/widgets/list_group.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +class ListGroup extends StatelessWidget { + final Widget title; + final List items; + final Widget Function(T item) itemBuilder; + + ListGroup({this.title, this.items, this.itemBuilder}); + + Widget _buildItem(T item) { + return Container( + decoration: BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black12)), + ), + child: itemBuilder(item), + ); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.all(10), + child: Container( + decoration: BoxDecoration(border: Border.all(color: Colors.black12)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container( + padding: EdgeInsets.all(4), + color: Colors.black12, + child: title, + ), + Column(children: items.map(_buildItem).toList()) + ], + ), + ), + ); + } +} diff --git a/lib/widgets/notification_item.dart b/lib/widgets/notification_item.dart index 48d9d31..2e8a2a3 100644 --- a/lib/widgets/notification_item.dart +++ b/lib/widgets/notification_item.dart @@ -45,55 +45,50 @@ class NotificationItem extends StatelessWidget { CupertinoPageRoute(builder: (context) => _buildRoute(item)), ); }, - child: Container( - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black12)), - ), - child: Row( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 8), - child: Icon( - _buildIconData(item.subject.type), - color: Colors.black45, - ), + child: Row( + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 8), + child: Icon( + _buildIconData(item.subject.type), + color: Colors.black45, ), - Expanded( - child: Row( - children: [ - Expanded( - child: Container( - padding: EdgeInsets.symmetric(vertical: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item.subject.title, - style: TextStyle(fontSize: 15), - maxLines: 3, - overflow: TextOverflow.ellipsis, + ), + Expanded( + child: Row( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.symmetric(vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item.subject.title, + style: TextStyle(fontSize: 15), + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + Padding(padding: EdgeInsets.only(top: 8)), + Text( + TimeAgo.format(item.updatedAt), + style: TextStyle( + fontSize: 12, + color: Colors.black87, ), - Padding(padding: EdgeInsets.only(top: 8)), - Text( - TimeAgo.format(item.updatedAt), - style: TextStyle( - fontSize: 12, - color: Colors.black87, - ), - ) - ], - ), + ) + ], ), ), - Container( - padding: EdgeInsets.symmetric(horizontal: 8), - child: Icon(Octicons.check, color: Colors.black45), - ), - ], - ), + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 8), + child: Icon(Octicons.check, color: Colors.black45), + ), + ], ), - ], - ), + ), + ], ), ); } diff --git a/lib/widgets/refresh_scaffold.dart b/lib/widgets/refresh_scaffold.dart index a9b1057..5808517 100644 --- a/lib/widgets/refresh_scaffold.dart +++ b/lib/widgets/refresh_scaffold.dart @@ -5,15 +5,16 @@ import '../providers/settings.dart'; import 'loading.dart'; typedef RefreshCallback = Future Function(); +typedef BodyBuilder = Widget Function(); class RefreshScaffold extends StatefulWidget { - final String title; - final Widget body; + final Widget title; + final BodyBuilder bodyBuilder; final RefreshCallback onRefresh; RefreshScaffold({ @required this.title, - @required this.body, + @required this.bodyBuilder, @required this.onRefresh, }); @@ -50,7 +51,7 @@ class _RefreshScaffoldState extends State { if (loading) { return Loading(more: false); } else { - return widget.body; + return widget.bodyBuilder(); } } @@ -59,7 +60,7 @@ class _RefreshScaffoldState extends State { switch (SettingsProvider.of(context).layout) { case LayoutMap.cupertino: return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar(middle: Text(widget.title)), + navigationBar: CupertinoNavigationBar(middle: widget.title), child: SafeArea( child: CustomScrollView( slivers: [ @@ -71,7 +72,7 @@ class _RefreshScaffoldState extends State { ); default: return Scaffold( - appBar: AppBar(title: Text(widget.title)), + appBar: AppBar(title: widget.title), body: RefreshIndicator( onRefresh: widget.onRefresh, child: _buildBody(context), diff --git a/lib/widgets/repo_item.dart b/lib/widgets/repo_item.dart new file mode 100644 index 0000000..aabce57 --- /dev/null +++ b/lib/widgets/repo_item.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import '../utils/utils.dart'; +import '../screens/repo.dart'; +import 'link.dart'; + +class RepoItem extends StatelessWidget { + final Map item; + + RepoItem(this.item); + + @override + Widget build(BuildContext context) { + return Link( + onTap: () {}, + child: Padding( + padding: EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(item['name'], style: TextStyle(fontWeight: FontWeight.w600)), + Padding(padding: EdgeInsets.only(top: 4)), + Text(item['description']), + Padding(padding: EdgeInsets.only(top: 4)), + DefaultTextStyle( + style: TextStyle(color: Colors.black54), + child: Row( + children: [ + Icon(Octicons.star, size: 16, color: Colors.black54), + Text(item['stargazers']['totalCount'].toString()), + Padding(padding: EdgeInsets.only(left: 8)), + Icon(Octicons.repo_forked, size: 16, color: Colors.black54), + Text(item['forks']['totalCount'].toString()), + Padding(padding: EdgeInsets.only(left: 8)), + Text(item['primaryLanguage']['name']) + ], + ), + ) + ], + ), + ), + ); + } +}