feat: add trending screen
This commit is contained in:
parent
e6d6835661
commit
c06ef90618
|
@ -9,6 +9,7 @@ import 'screens/me.dart';
|
|||
import 'screens/login.dart';
|
||||
import 'screens/issue.dart';
|
||||
import 'screens/repos.dart';
|
||||
import 'screens/trending.dart';
|
||||
|
||||
class Home extends StatefulWidget {
|
||||
@override
|
||||
|
@ -49,6 +50,10 @@ class _HomeState extends State<Home> {
|
|||
icon: _buildNotificationIcon(context),
|
||||
title: Text('Notification'),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.trending_up),
|
||||
title: Text('Trending'),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.search),
|
||||
title: Text('Search'),
|
||||
|
@ -63,14 +68,17 @@ class _HomeState extends State<Home> {
|
|||
_buildScreen(int index) {
|
||||
// return IssueScreen(number: 29, owner: 'reactjs', name: 'rfcs');
|
||||
// return ReposScreen('pd4d10');
|
||||
// return TrendingScreen();
|
||||
switch (index) {
|
||||
case 0:
|
||||
return NewsScreen();
|
||||
case 1:
|
||||
return NotificationScreen();
|
||||
case 2:
|
||||
return SearchScreen();
|
||||
return TrendingScreen();
|
||||
case 3:
|
||||
return SearchScreen();
|
||||
case 4:
|
||||
return MeScreen();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:html/parser.dart' show parse;
|
||||
import '../scaffolds/refresh.dart';
|
||||
import '../widgets/repo_item.dart';
|
||||
|
||||
// class TrendingRepo {
|
||||
// String owner;
|
||||
// String name;
|
||||
// String description;
|
||||
// String languageName;
|
||||
// String languageColor;
|
||||
// int starCount;
|
||||
// int forkCount;
|
||||
// int stars;
|
||||
// }
|
||||
|
||||
class TrendingScreen extends StatefulWidget {
|
||||
@override
|
||||
_TrendingScreenState createState() => _TrendingScreenState();
|
||||
}
|
||||
|
||||
class _TrendingScreenState extends State<TrendingScreen> {
|
||||
Future<List<dynamic>> _fetchTrendingRepos() async {
|
||||
var res = await http.get('https://github.com/trending');
|
||||
// print(res.body);
|
||||
var document = parse(res.body);
|
||||
var items = document.querySelectorAll('.repo-list>li');
|
||||
|
||||
return items.map((item) {
|
||||
Map<String, String> lang;
|
||||
var colorNode = item.querySelector('.repo-language-color');
|
||||
if (colorNode != null) {
|
||||
lang = {
|
||||
'name': colorNode.nextElementSibling.innerHtml.trim(),
|
||||
'color': RegExp(r'(#\w{6})')
|
||||
.firstMatch(colorNode.attributes['style'])
|
||||
.group(0),
|
||||
};
|
||||
}
|
||||
|
||||
var payload = {
|
||||
'owner': {
|
||||
'login': item
|
||||
.querySelector('h3>a>span')
|
||||
?.innerHtml
|
||||
?.replaceFirst('/', '')
|
||||
?.trim()
|
||||
},
|
||||
'name': item
|
||||
.querySelector('h3>a')
|
||||
?.innerHtml
|
||||
?.replaceFirst(RegExp(r'^[\s\S]*span>'), '')
|
||||
?.trim(),
|
||||
'description': item.children[2].querySelector('p')?.innerHtml?.trim(),
|
||||
'stargazers': {
|
||||
'totalCount': item.children[3]
|
||||
.querySelectorAll('a')[0]
|
||||
?.innerHtml
|
||||
?.replaceFirst(RegExp(r'^[\s\S]*svg>'), '')
|
||||
?.trim()
|
||||
},
|
||||
'forks': {
|
||||
'totalCount': item.children[3]
|
||||
.querySelectorAll('a')[1]
|
||||
?.innerHtml
|
||||
?.replaceFirst(RegExp(r'^[\s\S]*svg>'), '')
|
||||
?.trim(),
|
||||
},
|
||||
'primaryLanguage': lang,
|
||||
'isPrivate': false,
|
||||
'isFork': false // TODO:
|
||||
};
|
||||
// print(payload);
|
||||
return payload;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RefreshScaffold(
|
||||
title: Text('Trending'),
|
||||
onRefresh: _fetchTrendingRepos,
|
||||
bodyBuilder: (payload) {
|
||||
return Column(
|
||||
children: payload.map<Widget>((repo) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(bottom: BorderSide(color: Colors.black12))),
|
||||
child: RepoItem(repo),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,15 +5,15 @@ import '../screens/repo.dart';
|
|||
import 'link.dart';
|
||||
|
||||
class RepoItem extends StatelessWidget {
|
||||
final Map<String, dynamic> item;
|
||||
final Map<String, dynamic> payload;
|
||||
|
||||
RepoItem(this.item);
|
||||
RepoItem(this.payload);
|
||||
|
||||
IconData _buildIconData() {
|
||||
if (item['isPrivate']) {
|
||||
if (payload['isPrivate']) {
|
||||
return Octicons.lock;
|
||||
}
|
||||
if (item['isFork']) {
|
||||
if (payload['isFork']) {
|
||||
return Octicons.repo_forked;
|
||||
}
|
||||
return Octicons.repo;
|
||||
|
@ -22,7 +22,8 @@ class RepoItem extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Link(
|
||||
screenBuilder: (_) => RepoScreen(item['owner']['login'], item['name']),
|
||||
screenBuilder: (_) =>
|
||||
RepoScreen(payload['owner']['login'], payload['name']),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Row(
|
||||
|
@ -33,24 +34,24 @@ class RepoItem extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
item['owner']['login'] + '/' + item['name'],
|
||||
payload['owner']['login'] + '/' + payload['name'],
|
||||
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 15),
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(top: 6)),
|
||||
Text(item['description'] ?? 'No description provided yet'),
|
||||
Text(payload['description'] ?? 'No description provided yet'),
|
||||
Padding(padding: EdgeInsets.only(top: 6)),
|
||||
DefaultTextStyle(
|
||||
style: TextStyle(color: Colors.black54, fontSize: 13),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(Octicons.star, size: 14, color: Colors.black54),
|
||||
Text(item['stargazers']['totalCount'].toString()),
|
||||
Text(payload['stargazers']['totalCount'].toString()),
|
||||
Padding(padding: EdgeInsets.only(left: 16)),
|
||||
Icon(Octicons.repo_forked,
|
||||
size: 14, color: Colors.black54),
|
||||
Text(item['forks']['totalCount'].toString()),
|
||||
Text(payload['forks']['totalCount'].toString()),
|
||||
Padding(padding: EdgeInsets.only(left: 16)),
|
||||
item['primaryLanguage'] == null
|
||||
payload['primaryLanguage'] == null
|
||||
? Container()
|
||||
: Row(children: <Widget>[
|
||||
Container(
|
||||
|
@ -58,12 +59,12 @@ class RepoItem extends StatelessWidget {
|
|||
height: 10,
|
||||
decoration: new BoxDecoration(
|
||||
color: convertColor(
|
||||
item['primaryLanguage']['color']),
|
||||
payload['primaryLanguage']['color']),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(left: 4)),
|
||||
Text(item['primaryLanguage']['name']),
|
||||
Text(payload['primaryLanguage']['name']),
|
||||
]),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -27,6 +27,7 @@ dependencies:
|
|||
nanoid: ^0.0.6
|
||||
share: ^0.6.0
|
||||
flutter_vector_icons: ^0.0.2
|
||||
html: ^0.13.3
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
|
|
Loading…
Reference in New Issue