From bf5ed239716ae9fd29bcae24ecc3741771401f99 Mon Sep 17 00:00:00 2001 From: Shreyas Thirumalai Date: Tue, 28 Apr 2020 22:29:01 +0530 Subject: [PATCH] feat: user organizations, fix: create,delete event (#72) Fixes #58 --- lib/models/github.dart | 12 +++++ lib/models/github.g.dart | 20 ++++++++ lib/router.dart | 3 ++ lib/screens/gh_user.dart | 6 ++- lib/screens/gh_user_organization.dart | 47 +++++++++++++++++ lib/widgets/event_item.dart | 12 +++-- lib/widgets/user_organizations.dart | 72 +++++++++++++++++++++++++++ 7 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 lib/screens/gh_user_organization.dart create mode 100644 lib/widgets/user_organizations.dart diff --git a/lib/models/github.dart b/lib/models/github.dart index 9016d02..1bf525b 100644 --- a/lib/models/github.dart +++ b/lib/models/github.dart @@ -313,3 +313,15 @@ class GithubContributorItem { factory GithubContributorItem.fromJson(Map json) => _$GithubContributorItemFromJson(json); } + +@JsonSerializable(fieldRename: FieldRename.snake) +class GithubUserOrganizationItem { + int id; + String login; + String avatarUrl; + String description; + String url; + GithubUserOrganizationItem(); + factory GithubUserOrganizationItem.fromJson(Map json) => + _$GithubUserOrganizationItemFromJson(json); +} diff --git a/lib/models/github.g.dart b/lib/models/github.g.dart index abf8636..6d19e80 100644 --- a/lib/models/github.g.dart +++ b/lib/models/github.g.dart @@ -440,3 +440,23 @@ Map _$GithubContributorItemToJson( 'html_url': instance.htmlUrl, 'contributions': instance.contributions, }; + +GithubUserOrganizationItem _$GithubUserOrganizationItemFromJson( + Map json) { + return GithubUserOrganizationItem() + ..id = json['id'] as int + ..login = json['login'] as String + ..avatarUrl = json['avatar_url'] as String + ..description = json['description'] as String + ..url = json['url'] as String; +} + +Map _$GithubUserOrganizationItemToJson( + GithubUserOrganizationItem instance) => + { + 'id': instance.id, + 'login': instance.login, + 'avatar_url': instance.avatarUrl, + 'description': instance.description, + 'url': instance.url, + }; diff --git a/lib/router.dart b/lib/router.dart index 645af33..a3b3879 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -36,6 +36,7 @@ import 'package:git_touch/screens/gh_repo.dart'; 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'; class RouterScreen { String path; @@ -90,6 +91,8 @@ class GithubRouter { return GhReposScreen(login); case 'orgrepo': return GhOrgReposScreen(login); + case 'organizations': + return GhUserOrganizationScreen(login); default: return GhUserScreen(login); } diff --git a/lib/screens/gh_user.dart b/lib/screens/gh_user.dart index 5a63f0c..5948f15 100644 --- a/lib/screens/gh_user.dart +++ b/lib/screens/gh_user.dart @@ -62,7 +62,6 @@ class GhUserScreen extends StatelessWidget { final theme = Provider.of(context); final auth = Provider.of(context); final login = p.login; - return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -153,6 +152,11 @@ class GhUserScreen extends StatelessWidget { TableView( hasIcon: true, items: [ + TableViewItem( + leftIconData: Octicons.home, + text: Text('Organizations'), + url: '/$login?tab=organizations', + ), if (isNotNullOrEmpty(p.company)) TableViewItem( leftIconData: Octicons.organization, diff --git a/lib/screens/gh_user_organization.dart b/lib/screens/gh_user_organization.dart new file mode 100644 index 0000000..b6163c0 --- /dev/null +++ b/lib/screens/gh_user_organization.dart @@ -0,0 +1,47 @@ +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/app_bar_title.dart'; +import 'package:git_touch/widgets/user_organizations.dart'; +import 'package:provider/provider.dart'; +import 'package:git_touch/models/auth.dart'; + +class GhUserOrganizationScreen extends StatelessWidget { + final String login; + GhUserOrganizationScreen(this.login); + + Future> _query( + BuildContext context, + [int page = 1]) async { + final auth = Provider.of(context); + final res = + await auth.ghClient.getJSON>( + '/users/$login/orgs?page=$page', + convert: (vs) => + [for (var v in vs) GithubUserOrganizationItem.fromJson(v)], + ); + return ListPayload( + cursor: page + 1, + items: res, + hasMore: res.isNotEmpty, + ); + } + + Widget build(BuildContext context) { + return ListStatefulScaffold( + title: AppBarTitle('Organizations'), + onRefresh: () => _query(context), + onLoadMore: (cursor) => _query(context, cursor), + itemBuilder: (v) { + final String login = v.login; + return UserOrganizationItem( + avatarUrl: v.avatarUrl, + login: v.login, + url: '/$login', + description: v.description, + ); + }, + ); + } +} diff --git a/lib/widgets/event_item.dart b/lib/widgets/event_item.dart index c2bfda9..c66743c 100644 --- a/lib/widgets/event_item.dart +++ b/lib/widgets/event_item.dart @@ -308,8 +308,10 @@ class EventItem extends StatelessWidget { return _buildItem( context: context, spans: [ - TextSpan(text: ' created ${e.payload.refType} '), - TextSpan(text: '${e.payload.ref} at '), + TextSpan(text: ' created a ${e.payload.refType}'), + TextSpan( + text: + '${e.payload.ref == null ? '' : ' ' + e.payload.ref + 'at'} '), _buildRepo(context), ], ); @@ -317,8 +319,10 @@ class EventItem extends StatelessWidget { return _buildItem( context: context, spans: [ - TextSpan(text: ' deleted ${e.payload.refType} '), - TextSpan(text: '${e.payload.ref} at '), + TextSpan(text: ' deleted the ${e.payload.refType}'), + TextSpan( + text: + '${e.payload.ref == null ? '' : ' ' + e.payload.ref + 'at'} '), _buildRepo(context), ], ); diff --git a/lib/widgets/user_organizations.dart b/lib/widgets/user_organizations.dart new file mode 100644 index 0000000..8c6410d --- /dev/null +++ b/lib/widgets/user_organizations.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:git_touch/models/theme.dart'; +import 'package:git_touch/utils/utils.dart'; +import 'package:git_touch/widgets/avatar.dart'; +import 'package:git_touch/widgets/link.dart'; +import 'package:provider/provider.dart'; + +class UserOrganizationItem extends StatelessWidget { + final String login; + final String avatarUrl; + final String url; + final String description; + + UserOrganizationItem({ + @required this.login, + @required this.avatarUrl, + @required this.url, + @required this.description, + }); + + @override + Widget build(BuildContext context) { + final theme = Provider.of(context); + return Link( + url: url, + child: Container( + padding: CommonStyle.padding, + child: Row( + children: [ + Avatar(url: avatarUrl, size: AvatarSize.large), + SizedBox(width: 10), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + login, + style: TextStyle( + color: theme.palette.primary, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + SizedBox(height: 6), + Row( + children: [ + Expanded( + child: Text( + description, + style: TextStyle( + color: theme.palette.secondaryText, + fontSize: 16, + ), + overflow: TextOverflow.visible, + ), + ) + ], + ), + ], + ), + ) + ], + ), + ), + ); + } +}