feat: repo screen

This commit is contained in:
Rongjian Zhang 2019-02-04 21:38:29 +08:00
parent 7a18277ac2
commit 56645910e4
10 changed files with 230 additions and 43 deletions

13
lib/screens/issues.dart Normal file
View File

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
class IssuesScreen extends StatefulWidget {
@override
_IssuesScreenState createState() => _IssuesScreenState();
}
class _IssuesScreenState extends State<IssuesScreen> {
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
class PullRequestsScreen extends StatefulWidget {
@override
_PullRequestsScreenState createState() => _PullRequestsScreenState();
}
class _PullRequestsScreenState extends State<PullRequestsScreen> {
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -1,8 +1,59 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import '../widgets/refresh_scaffold.dart';
import '../utils/utils.dart';
import '../widgets/repo_item.dart';
import '../widgets/entry_item.dart';
import '../screens/issues.dart';
import '../screens/pull_requests.dart';
Future fetchReadme(String owner, String name) async {
var data = await getWithCredentials('/repos/$owner/$name/readme');
var bits = base64.decode(data['content'].replaceAll('\n', ''));
var str = utf8.decode(bits);
return str;
}
Future queryRepo(String owner, String name) async {
var data = await query('''
{
repository(owner: "$owner", name: "$name") {
owner {
login
}
name
isPrivate
isFork
description
stargazers {
totalCount
}
forks {
totalCount
}
primaryLanguage {
color
name
}
issues(states: OPEN) {
totalCount
}
pullRequests(states: OPEN) {
totalCount
}
}
}
''');
return data['repository'];
}
class RepoScreen extends StatefulWidget {
final String owner;
final String name;
RepoScreen(this.owner, this.name);
@override
@ -10,10 +61,60 @@ class RepoScreen extends StatefulWidget {
}
class _RepoScreenState extends State<RepoScreen> {
Map<String, dynamic> payload;
String readme;
@override
Widget build(BuildContext context) {
return Container(
child: Text(widget.owner),
return RefreshScaffold(
title: Text(widget.owner + '/' + widget.name),
onRefresh: () async {
List items = await Future.wait([
queryRepo(widget.owner, widget.name),
fetchReadme(widget.owner, widget.name),
]);
setState(() {
payload = items[0];
readme = items[1];
});
},
bodyBuilder: () {
return Column(
children: <Widget>[
RepoItem(payload),
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.black12),
top: BorderSide(color: Colors.black12),
),
),
child: Row(
children: <Widget>[
EntryItem(
count: payload['issues']['totalCount'],
text: 'Issues',
route: CupertinoPageRoute(
builder: (context) => IssuesScreen(),
),
),
EntryItem(
count: payload['pullRequests']['totalCount'],
text: 'Pull Requests',
route: CupertinoPageRoute(
builder: (context) => PullRequestsScreen(),
),
),
],
),
),
Container(
padding: EdgeInsets.all(16),
child: MarkdownBody(data: readme),
),
],
);
},
);
}
}

View File

@ -2,10 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import '../widgets/refresh_scaffold.dart';
import '../widgets/avatar.dart';
import '../widgets/link.dart';
import '../widgets/entry_item.dart';
import '../widgets/list_group.dart';
import '../widgets/repo_item.dart';
import '../screens/repos.dart';
import '../screens/users.dart';
import '../utils/utils.dart';
var repoChunk = '''
@ -74,25 +75,7 @@ class UserScreen extends StatefulWidget {
}
class _UserScreenState extends State<UserScreen> {
Map<String, dynamic> payload = {};
Widget _buildEntry(int count, String text) {
return Expanded(
flex: 1,
child: Link(
child: Container(
padding: EdgeInsets.symmetric(vertical: 10),
child: Column(
children: <Widget>[
Text(count.toString()),
Text(text, style: TextStyle(fontSize: 13))
],
),
),
onTap: () {},
),
);
}
Map<String, dynamic> payload;
Widget _buildRepos() {
String title;
@ -127,8 +110,6 @@ class _UserScreenState extends State<UserScreen> {
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black12))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
@ -165,18 +146,38 @@ class _UserScreenState extends State<UserScreen> {
),
),
Container(
// padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black12))),
border: Border(
bottom: BorderSide(color: Colors.black12),
top: BorderSide(color: Colors.black12),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildEntry(
payload['repositories']['totalCount'], 'Repositories'),
_buildEntry(
payload['starredRepositories']['totalCount'], 'Stars'),
_buildEntry(payload['followers']['totalCount'], 'Followers'),
_buildEntry(payload['following']['totalCount'], 'Following'),
EntryItem(
count: payload['repositories']['totalCount'],
text: 'Repositories',
route:
CupertinoPageRoute(builder: (context) => ReposScreen()),
),
EntryItem(
count: payload['starredRepositories']['totalCount'],
text: 'Stars',
route:
CupertinoPageRoute(builder: (context) => ReposScreen()),
),
EntryItem(
count: payload['followers']['totalCount'],
text: 'Followers',
route:
CupertinoPageRoute(builder: (context) => UsersScreen()),
),
EntryItem(
count: payload['following']['totalCount'],
text: 'Following',
route:
CupertinoPageRoute(builder: (context) => UsersScreen()),
),
],
),
),

View File

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
class UsersScreen extends StatefulWidget {
@override
_UsersScreenState createState() => _UsersScreenState();
}
class _UsersScreenState extends State<UsersScreen> {
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -11,21 +11,27 @@ var ghClient = createGitHubClient(auth: Authentication.withToken(token));
final prefix = 'https://api.github.com';
final endpoint = '/graphql';
Future<dynamic> getWithCredentials(String url) async {
Future<dynamic> getWithCredentials(String url, {String contentType}) async {
var headers = {HttpHeaders.authorizationHeader: 'token $token'};
if (contentType != null) {
// https://developer.github.com/v3/repos/contents/#custom-media-types
headers[HttpHeaders.contentTypeHeader] = contentType;
}
final res = await http.get(
prefix + url,
headers: {HttpHeaders.authorizationHeader: 'token $token'},
headers: headers,
);
final data = json.decode(res.body);
return data;
}
Future<dynamic> postWithCredentials(String url, String body) async {
final res = await http.post(
prefix + url,
headers: {HttpHeaders.authorizationHeader: 'token $token'},
body: body,
);
Future<dynamic> postWithCredentials(String url, String body,
{String contentType}) async {
var headers = {HttpHeaders.authorizationHeader: 'token $token'};
if (contentType != null) {
headers[HttpHeaders.contentTypeHeader] = contentType;
}
final res = await http.post(prefix + url, headers: headers, body: body);
final data = json.decode(res.body);
return data;
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import '../screens/screens.dart';
export 'github.dart';
export 'octicons.dart';

View File

@ -0,0 +1,31 @@
import 'package:flutter/cupertino.dart';
import 'link.dart';
class EntryItem extends StatelessWidget {
final int count;
final String text;
final CupertinoPageRoute route;
EntryItem({this.count, this.text, this.route});
@override
Widget build(BuildContext context) {
return Expanded(
flex: 1,
child: Link(
child: Container(
padding: EdgeInsets.symmetric(vertical: 10),
child: Column(
children: <Widget>[
Text(count.toString()),
Text(text, style: TextStyle(fontSize: 13))
],
),
),
onTap: () {
Navigator.of(context).push(route);
},
),
);
}
}

View File

@ -26,7 +26,7 @@ class ListGroup<T> extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
padding: EdgeInsets.all(4),
padding: EdgeInsets.all(8),
color: Color(0x10000000),
child: title,
),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import '../utils/utils.dart';
import '../screens/repo.dart';
import 'link.dart';
@ -21,7 +22,14 @@ class RepoItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Link(
onTap: () {},
onTap: () {
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) =>
RepoScreen(item['owner']['login'], item['name']),
),
);
},
child: Padding(
padding: EdgeInsets.all(10),
child: Row(