diff --git a/lib/ios/home.dart b/lib/ios/home.dart deleted file mode 100644 index 9b3faaa..0000000 --- a/lib/ios/home.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'dart:async'; -// import 'dart:convert'; -import '../utils.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'home/event.dart'; - -class IosHomeTab extends StatefulWidget { - @override - createState() { - return new IosHomeTabState(); - } -} - -class IosHomeTabState extends State { - int page = 1; - List events = []; - - loadFirst() async { - events = await fetchEvents(); - page = 1; - return events; - } - - loadMore() async { - events.addAll(await fetchEvents(page + 1)); - page++; - return events; - } - - @override - Widget build(context) { - return new FutureBuilder( - future: loadFirst(), - builder: (context, snapshot) { - Widget widget; - if (snapshot.hasData) { - // List events = snapshot.data; - widget = new CustomScrollView( - slivers: [ - new CupertinoRefreshControl( - onRefresh: () { - return loadFirst(); - }, - ), - new SliverSafeArea( - // top: true, - sliver: new SliverList( - delegate: new SliverChildBuilderDelegate( - (context, index) { - var event = events[index]; - switch (event.type) { - case 'IssuesEvent': - return new IssuesEvent(event); - case 'PushEvent': - return new PushEvent(event); - case 'PullRequestEvent': - return new PullRequestEvent(event); - case 'WatchEvent': - return new WatchEvent(event); - default: - return new Text('Not implement yet'); - } - }, - childCount: 30, - ), - ), - ), - ], - ); - } else if (snapshot.hasError) { - widget = new Text("${snapshot.error}"); - } else { - widget = new CupertinoActivityIndicator(); - } - - return widget; - }, - ); - } -} diff --git a/lib/ios/home/event.dart b/lib/ios/home/event.dart index f0b564b..33335f9 100644 --- a/lib/ios/home/event.dart +++ b/lib/ios/home/event.dart @@ -1,27 +1,34 @@ import '../../utils.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/gestures.dart'; +import '../issue.dart'; +import '../user.dart'; -class _Avatar extends StatelessWidget { - final String avatar; - _Avatar(this.avatar); - - @override - build(context) { - return new CircleAvatar( - backgroundImage: NetworkImage(avatar), - radius: 24.0, - ); - } -} - -TextSpan _strong(String text) { +TextSpan _strong(String text, [GestureRecognizer recognizer]) { return new TextSpan( text: text, style: new TextStyle( fontWeight: FontWeight.bold, color: new Color(0xff24292e), ), + recognizer: recognizer, + ); +} + +TextSpan _user(Event event, context) { + return _strong( + event.actor, + new TapGestureRecognizer() + ..onTap = () { + Navigator.of(context).push( + new CupertinoPageRoute( + builder: (context) { + return new IosUserPage(event.actor, event.avatar); + }, + ), + ); + }, ); } @@ -30,29 +37,22 @@ class PushEvent extends StatelessWidget { PushEvent(this.event); @override - build(ctx) { - return new Row( - children: [ - new _Avatar(event.avatar), - new Expanded( - child: new RichText( - text: new TextSpan( - style: new TextStyle(color: CupertinoColors.black), - children: [ - _strong(event.actor), - new TextSpan(text: ' pushed to '), - new TextSpan( - text: event.payload['ref'], - style: new TextStyle(color: CupertinoColors.activeBlue), - ), - new TextSpan(text: ' in '), - _strong(event.repo), - new TextSpan(text: '') - ], - ), + build(context) { + return new RichText( + text: new TextSpan( + style: new TextStyle(color: CupertinoColors.black), + children: [ + _user(event, context), + new TextSpan(text: ' pushed to '), + new TextSpan( + text: event.payload['ref'], + style: new TextStyle(color: CupertinoColors.activeBlue), ), - ), - ], + new TextSpan(text: ' in '), + _strong(event.repo), + new TextSpan(text: '') + ], + ), ); } } @@ -62,26 +62,22 @@ class IssuesEvent extends StatelessWidget { IssuesEvent(this.event); @override - build(ctx) { - return new Row( - children: [ - new _Avatar(event.avatar), - new Expanded( - child: new RichText( - text: new TextSpan( - style: new TextStyle(color: CupertinoColors.black), - children: [ - _strong(event.actor), - new TextSpan(text: ' ${event.payload['action']} issue '), - _strong(event.repo), - new TextSpan( - text: '#' + event.payload['issue']['number'].toString()), - new TextSpan(text: event.payload['issue']['title']) - ], - ), + build(context) { + return new RichText( + text: new TextSpan( + style: new TextStyle(color: CupertinoColors.black), + children: [ + _user(event, context), + new TextSpan(text: ' ${event.payload['action']} issue '), + _strong(event.repo), + new TextSpan( + text: '#' + event.payload['issue']['number'].toString(), ), - ), - ], + new TextSpan( + text: event.payload['issue']['title'], + ) + ], + ), ); } } @@ -91,25 +87,18 @@ class PullRequestEvent extends StatelessWidget { PullRequestEvent(this.event); @override - build(ctx) { - return new Row( - children: [ - new _Avatar(event.avatar), - new Expanded( - child: new RichText( - text: new TextSpan( - style: new TextStyle(color: CupertinoColors.black), - children: [ - _strong(event.actor), - new TextSpan(text: ' ${event.payload['action']} pull request '), - _strong(event.repo), - new TextSpan(text: '#' + event.payload['number'].toString()), - new TextSpan(text: event.payload['pull_request']['title']) - ], - ), - ), - ), - ], + build(context) { + return new RichText( + text: new TextSpan( + style: new TextStyle(color: CupertinoColors.black), + children: [ + _user(event, context), + new TextSpan(text: ' ${event.payload['action']} pull request '), + _strong(event.repo), + new TextSpan(text: '#' + event.payload['number'].toString()), + new TextSpan(text: event.payload['pull_request']['title']) + ], + ), ); } } @@ -119,26 +108,18 @@ class IssueCommentEvent extends StatelessWidget { IssueCommentEvent(this.event); @override - build(ctx) { - return new Row( - children: [ - new _Avatar(event.avatar), - new Expanded( - child: new RichText( - text: new TextSpan( - style: new TextStyle(color: CupertinoColors.black), - children: [ - _strong(event.actor), - new TextSpan(text: ' commented on issue '), - _strong(event.repo), - new TextSpan( - text: '#' + event.payload['issue']['number'].toString()), - new TextSpan(text: event.payload['comment']['body']) - ], - ), - ), - ), - ], + build(context) { + return new RichText( + text: new TextSpan( + style: new TextStyle(color: CupertinoColors.black), + children: [ + _user(event, context), + new TextSpan(text: ' commented on issue '), + _strong(event.repo), + new TextSpan(text: '#' + event.payload['issue']['number'].toString()), + new TextSpan(text: event.payload['comment']['body']) + ], + ), ); } } @@ -148,23 +129,16 @@ class WatchEvent extends StatelessWidget { WatchEvent(this.event); @override - build(ctx) { - return new Row( - children: [ - new _Avatar(event.avatar), - new Expanded( - child: new RichText( - text: new TextSpan( - style: new TextStyle(color: CupertinoColors.black), - children: [ - _strong(event.actor), - new TextSpan(text: ' ${event.payload['action']} '), - _strong(event.repo), - ], - ), - ), - ), - ], + build(context) { + return new RichText( + text: new TextSpan( + style: new TextStyle(color: CupertinoColors.black), + children: [ + _user(event, context), + new TextSpan(text: ' ${event.payload['action']} '), + _strong(event.repo), + ], + ), ); } } diff --git a/lib/ios/home/index.dart b/lib/ios/home/index.dart new file mode 100644 index 0000000..332650a --- /dev/null +++ b/lib/ios/home/index.dart @@ -0,0 +1,121 @@ +// import 'dart:async'; +// import 'dart:convert'; +import '../../utils.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'event.dart'; +import '../user.dart'; + +class _Avatar extends StatelessWidget { + final String avatar; + _Avatar(this.avatar); + + @override + build(context) { + return new CircleAvatar( + backgroundImage: NetworkImage(avatar), + radius: 24.0, + ); + } +} + +class _EventItem extends StatelessWidget { + final Event event; + final Widget child; + _EventItem(this.event, this.child); + + @override + build(context) { + // const Padding(padding: const EdgeInsets.only(top: 16.0)), + return new Row( + children: [ + new _Avatar(event.avatar), + new Expanded(child: child), + ], + ); + } +} + +class IosHomeTab extends StatefulWidget { + @override + createState() { + return new IosHomeTabState(); + } +} + +class IosHomeTabState extends State { + int page = 1; + List events = []; + + loadFirst() async { + events = await fetchEvents(); + page = 1; + return events; + } + + loadMore() async { + events.addAll(await fetchEvents(page + 1)); + page++; + return events; + } + + @override + Widget build(context) { + return new CupertinoPageScaffold( + navigationBar: new CupertinoNavigationBar( + middle: new Text('Home'), + ), + child: new FutureBuilder( + future: loadFirst(), + builder: (context, snapshot) { + Widget widget; + if (snapshot.hasData) { + // List events = snapshot.data; + widget = new CustomScrollView( + slivers: [ + new CupertinoRefreshControl( + onRefresh: () { + return loadFirst(); + }, + ), + new SliverSafeArea( + // top: true, + sliver: new SliverList( + delegate: new SliverChildBuilderDelegate( + (context, index) { + var event = events[index]; + var child = (() { + switch (event.type) { + case 'IssuesEvent': + return new IssuesEvent(event); + case 'PushEvent': + return new PushEvent(event); + case 'PullRequestEvent': + return new PullRequestEvent(event); + case 'WatchEvent': + return new WatchEvent(event); + default: + return new Text('Not implement yet'); + } + })(); + return new _EventItem(event, child); + }, + childCount: 30, + ), + ), + ), + ], + ); + } else if (snapshot.hasError) { + widget = new Text("${snapshot.error}"); + } else { + widget = new CupertinoActivityIndicator(); + } + + return widget; + }, + ), + ); + } +} diff --git a/lib/ios/issue.dart b/lib/ios/issue.dart new file mode 100644 index 0000000..a4829eb --- /dev/null +++ b/lib/ios/issue.dart @@ -0,0 +1,11 @@ +// import 'dart:async'; +// import 'dart:convert'; +// import '../utils.dart'; +import 'package:flutter/cupertino.dart'; + +class IosIssue extends StatelessWidget { + @override + Widget build(context) { + return new Text('Issue'); + } +} diff --git a/lib/ios/main.dart b/lib/ios/main.dart index 02a51b1..a31698c 100644 --- a/lib/ios/main.dart +++ b/lib/ios/main.dart @@ -1,12 +1,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'home.dart'; +import 'home/index.dart'; import 'notification.dart'; import 'profile.dart'; +import 'issue.dart'; class IosApp extends StatelessWidget { @override - Widget build(BuildContext context) { + build(context) { return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( @@ -14,6 +15,7 @@ class IosApp extends StatelessWidget { ), home: new IosHomePage(title: 'GitFlux'), routes: { + '/issue': (context) => new IosIssue() // '/notification': (context) => new IosNotificationTab(), // '/profile': (context) => new IosProfileTab(), }, @@ -42,9 +44,6 @@ class _IosHomePageState extends State { @override Widget build(context) { return new CupertinoPageScaffold( - navigationBar: new CupertinoNavigationBar( - middle: new Text(widget.title), - ), child: new CupertinoTabScaffold( tabBar: new CupertinoTabBar( items: const [ diff --git a/lib/ios/user.dart b/lib/ios/user.dart new file mode 100644 index 0000000..4fec886 --- /dev/null +++ b/lib/ios/user.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import '../utils.dart'; + +class IosUserPage extends StatelessWidget { + String login; + String avatar; + IosUserPage(this.login, this.avatar); + + @override + build(context) { + return new CupertinoPageScaffold( + navigationBar: new CupertinoNavigationBar( + leading: new CupertinoButton( + child: const Text('Cancel'), + padding: EdgeInsets.zero, + onPressed: () { + Navigator.of(context).pop(false); + }, + ), + middle: new Text(login), + ), + child: new FutureBuilder( + future: fetchUser(login), + builder: (context, snapshot) { + Widget widget; + if (snapshot.hasData) { + User user = snapshot.data; + return new Text(''); + } else if (snapshot.hasError) { + widget = new Text("${snapshot.error}"); + } else { + widget = new CupertinoActivityIndicator(); + } + return widget; + }, + )); + } +} diff --git a/lib/utils.dart b/lib/utils.dart index 62001a3..76570e7 100644 --- a/lib/utils.dart +++ b/lib/utils.dart @@ -6,20 +6,6 @@ import 'token.dart'; final prefix = 'https://api.github.com'; -// class PushEvent extends Event { -// PushEvent(Map json) : super(json) {} -// } - -// class IssuesEvent extends Event { -// String issueTitle; -// String issueUrl; - -// IssuesEvent(Map json) : super(json) { -// issueTitle = json['issue']['title']; -// issueUrl = json['issue']['url']; -// } -// } - class Event { String type; String actor; @@ -28,23 +14,32 @@ class Event { String repo; Map payload; - Event(Map json) { - id = json['id']; - type = json['type']; - actor = json['actor']['login']; - avatar = json['actor']['avatar_url']; - repo = json['repo']['name']; - payload = json['payload']; + Event(data) { + id = data['id']; + type = data['type']; + actor = data['actor']['login']; + avatar = data['actor']['avatar_url']; + repo = data['repo']['name']; + payload = data['payload']; } +} - // factory Event.fromJson(Map json) { - // switch (json['type']) { - // case 'PushEvent': - // return new PushEvent(json); - // default: - // return null; - // } - // } +class User { + String login; + String avatar; + String name; + int repos; + int followers; + int following; + + User(data) { + login = data['login']; + avatar = data['avatar_url']; + name = data['name']; + repos = data['public_repos']; + followers = data['followers']; + following = data['following']; + } } Future> fetchEvents([int page = 1]) async { @@ -52,9 +47,19 @@ Future> fetchEvents([int page = 1]) async { prefix + '/users/pd4d10/received_events/public?page=$page', headers: {HttpHeaders.AUTHORIZATION: 'token $token'}, ); - List resJson = json.decode(res.body); + List data = json.decode(res.body); - return resJson.map((item) { + return data.map((item) { return new Event(item); }).toList(); } + +Future fetchUser(String login) async { + final res = await http.get( + prefix + '/users/$login', + headers: {HttpHeaders.AUTHORIZATION: 'token $token'}, + ); + Map data = json.decode(res.body); + + return new User(data); +}