feat: files screen (#75)

Fixes #74
This commit is contained in:
Shreyas Thirumalai
2020-04-30 21:34:24 +05:30
committed by GitHub
parent 0063e99bbc
commit 0749a69986
6 changed files with 196 additions and 1 deletions

View File

@@ -325,3 +325,28 @@ class GithubUserOrganizationItem {
factory GithubUserOrganizationItem.fromJson(Map<String, dynamic> json) =>
_$GithubUserOrganizationItemFromJson(json);
}
@JsonSerializable(fieldRename: FieldRename.snake)
class GithubGistsItem {
int id;
bool isFork;
bool isPublic;
String name;
DateTime updatedAt;
GithubGistsItem();
factory GithubGistsItem.fromJson(Map<String, dynamic> json) =>
_$GithubGistsItemFromJson(json);
}
@JsonSerializable(fieldRename: FieldRename.snake)
class GithubFilesItem {
String filename;
String status;
int additions;
int deletions;
int changes;
String patch;
GithubFilesItem();
factory GithubFilesItem.fromJson(Map<String, dynamic> json) =>
_$GithubFilesItemFromJson(json);
}

View File

@@ -460,3 +460,43 @@ Map<String, dynamic> _$GithubUserOrganizationItemToJson(
'description': instance.description,
'url': instance.url,
};
GithubGistsItem _$GithubGistsItemFromJson(Map<String, dynamic> json) {
return GithubGistsItem()
..id = json['id'] as int
..isFork = json['is_fork'] as bool
..isPublic = json['is_public'] as bool
..name = json['name'] as String
..updatedAt = json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String);
}
Map<String, dynamic> _$GithubGistsItemToJson(GithubGistsItem instance) =>
<String, dynamic>{
'id': instance.id,
'is_fork': instance.isFork,
'is_public': instance.isPublic,
'name': instance.name,
'updated_at': instance.updatedAt?.toIso8601String(),
};
GithubFilesItem _$GithubFilesItemFromJson(Map<String, dynamic> json) {
return GithubFilesItem()
..filename = json['filename'] as String
..status = json['status'] as String
..additions = json['additions'] as int
..deletions = json['deletions'] as int
..changes = json['changes'] as int
..patch = json['patch'] as String;
}
Map<String, dynamic> _$GithubFilesItemToJson(GithubFilesItem instance) =>
<String, dynamic>{
'filename': instance.filename,
'status': instance.status,
'additions': instance.additions,
'deletions': instance.deletions,
'changes': instance.changes,
'patch': instance.patch,
};

View File

@@ -6,6 +6,7 @@ import 'package:git_touch/screens/bb_user.dart';
import 'package:git_touch/screens/code_theme.dart';
import 'package:git_touch/screens/gh_commits.dart';
import 'package:git_touch/screens/gh_contributors.dart';
import 'package:git_touch/screens/gh_files.dart';
import 'package:git_touch/screens/gh_org_repos.dart';
import 'package:git_touch/screens/gl_commit.dart';
import 'package:git_touch/screens/gl_starrers.dart';
@@ -37,6 +38,7 @@ import 'package:git_touch/screens/settings.dart';
import 'package:git_touch/screens/gh_user.dart';
import 'package:git_touch/screens/gh_users.dart';
import 'package:git_touch/screens/gh_user_organization.dart';
import 'package:git_touch/screens/gh_gists.dart';
class RouterScreen {
String path;
@@ -74,6 +76,7 @@ class GithubRouter {
GithubRouter.stargazers,
GithubRouter.watchers,
GithubRouter.contributors,
GithubRouter.files,
];
static final user = RouterScreen('/:login', (_, p) {
final login = p['login'].first;
@@ -93,6 +96,8 @@ class GithubRouter {
return GhOrgReposScreen(login);
case 'organizations':
return GhUserOrganizationScreen(login);
case 'gists':
return GhGistsScreen(login);
default:
return GhUserScreen(login);
}
@@ -121,6 +126,13 @@ class GithubRouter {
(context, p) => GhIssueScreen(
p['owner'].first, p['name'].first, int.parse(p['number'].first),
isPullRequest: true));
static final files = RouterScreen(
'/:owner/:name/pull/:number/files',
(context, p) => GhFilesScreen(
p['owner'].first,
p['name'].first,
int.parse(p['number'].first),
));
static final commits = RouterScreen('/:owner/:name/commits',
(context, p) => GhCommitsScreen(p['owner'].first, p['name'].first));
static final object = RouterScreen('/:owner/:name/blob/:ref', (_, p) {

57
lib/screens/gh_files.dart Normal file
View File

@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:git_touch/models/github.dart';
import 'package:git_touch/scaffolds/list_stateful.dart';
import 'package:git_touch/widgets/action_button.dart';
import 'package:git_touch/widgets/app_bar_title.dart';
import 'package:provider/provider.dart';
import 'package:git_touch/widgets/files_item.dart';
import 'package:git_touch/models/auth.dart';
class GhFilesScreen extends StatelessWidget {
final String owner;
final String name;
final int pullNumber;
GhFilesScreen(this.owner, this.name, this.pullNumber);
Future<ListPayload<GithubFilesItem, int>> _query(BuildContext context,
[int page = 1]) async {
final auth = Provider.of<AuthModel>(context);
final res = await auth.ghClient.getJSON<List, List<GithubFilesItem>>(
'/repos/$owner/$name/pulls/$pullNumber/files?page=$page',
convert: (vs) => [for (var v in vs) GithubFilesItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
}
Widget build(BuildContext context) {
return ListStatefulScaffold<GithubFilesItem, int>(
title: AppBarTitle('Files'),
actionBuilder: () {
return ActionButton(
title: 'Actions',
items: [
...ActionItem.getUrlActions(
'https://github.com/$owner/$name/pull/$pullNumber/files'),
],
);
},
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
itemBuilder: (v) {
return FilesItem(
filename: v.filename,
additions: v.additions,
deletions: v.deletions,
status: v.status,
changes: v.changes,
patch: v.patch,
);
},
);
}
}

View File

@@ -587,7 +587,7 @@ fragment ReactableParts on Reactable {
],
),
),
url: 'https://github.com/$owner/$name/pull/$number/files',
url: '/$owner/$name/pull/$number/files',
),
CommonStyle.border,
],

View File

@@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:flutter_highlight/flutter_highlight.dart';
import 'package:git_touch/models/theme.dart';
import 'package:git_touch/models/code.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:provider/provider.dart';
import 'package:flutter_highlight/theme_map.dart';
class FilesItem extends StatelessWidget {
final String filename;
final String status;
final int changes;
final int additions;
final int deletions;
final String patch;
FilesItem({
@required this.filename,
@required this.status,
@required this.changes,
@required this.deletions,
@required this.additions,
@required this.patch,
});
@override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeModel>(context);
final codeProvider = Provider.of<CodeModel>(context);
return Card(
color: theme.palette.background,
margin: EdgeInsets.all(0),
child: ExpansionTile(
title: Text(
filename,
style: TextStyle(
color: theme.palette.primary,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
children: <Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: HighlightView(
patch,
language: 'diff',
padding: CommonStyle.padding,
theme: themeMap[theme.brightness == Brightness.dark
? codeProvider.themeDark
: codeProvider.theme],
textStyle: TextStyle(
fontSize: codeProvider.fontSize.toDouble(),
fontFamily: codeProvider.fontFamilyUsed),
),
),
],
),
);
}
}