refactor: fix null types

This commit is contained in:
Rongjian Zhang 2021-06-14 14:56:42 +08:00
parent 442d910dbd
commit 5b3bc45db5
24 changed files with 90 additions and 102 deletions

View File

@ -688,18 +688,15 @@ class AuthModel with ChangeNotifier {
// var _timeoutDuration = Duration(seconds: 1); // var _timeoutDuration = Duration(seconds: 1);
GitHub? _ghClient; GitHub? _ghClient;
GitHub? get ghClient { GitHub get ghClient {
if (token == null) return null;
if (_ghClient == null) { if (_ghClient == null) {
_ghClient = GitHub(auth: Authentication.withToken(token)); _ghClient = GitHub(auth: Authentication.withToken(token));
} }
return _ghClient; return _ghClient!;
} }
Client? _gqlClient; Client? _gqlClient;
Client? get gqlClient { Client get gqlClient {
if (token == null) return null;
if (_gqlClient == null) { if (_gqlClient == null) {
_gqlClient = Client( _gqlClient = Client(
link: HttpLink( link: HttpLink(
@ -710,16 +707,13 @@ class AuthModel with ChangeNotifier {
); );
} }
return _gqlClient; return _gqlClient!;
} }
Future<dynamic> query(String query, [String? _token]) async { Future<dynamic> query(String query, [String? _token]) async {
if (_token == null) { if (_token == null) {
_token = token; _token = token;
} }
if (_token == null) {
throw 'token is null';
}
final res = await http final res = await http
.post(Uri.parse(_apiPrefix + '/graphql'), .post(Uri.parse(_apiPrefix + '/graphql'),

View File

@ -43,7 +43,7 @@ class GhCommits extends StatelessWidget {
b.vars.after = cursor; b.vars.after = cursor;
}); });
final OperationResponse<GCommitsData, GCommitsVars?> res = final OperationResponse<GCommitsData, GCommitsVars?> res =
await context.read<AuthModel>().gqlClient!.request(req).first; await context.read<AuthModel>().gqlClient.request(req).first;
final ref = res.data!.repository!.defaultBranchRef ?? final ref = res.data!.repository!.defaultBranchRef ??
res.data!.repository!.ref!; res.data!.repository!.ref!;
final history = (ref.target as GCommitsRefCommit).history; final history = (ref.target as GCommitsRefCommit).history;

View File

@ -20,7 +20,7 @@ class GhComparisonScreen extends StatelessWidget {
return RefreshStatefulScaffold( return RefreshStatefulScaffold(
title: AppBarTitle(AppLocalizations.of(context)!.files), title: AppBarTitle(AppLocalizations.of(context)!.files),
fetch: () async { fetch: () async {
final res = await context.read<AuthModel>().ghClient!.getJSON( final res = await context.read<AuthModel>().ghClient.getJSON(
'/repos/$owner/$name/compare/$before...$head', '/repos/$owner/$name/compare/$before...$head',
convert: (dynamic vs) => GithubComparisonItem.fromJson(vs)); convert: (dynamic vs) => GithubComparisonItem.fromJson(vs));
return res.files; return res.files;

View File

@ -20,7 +20,7 @@ class GhContributorsScreen extends StatelessWidget {
page = page ?? 1; page = page ?? 1;
final res = await context final res = await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.getJSON<List, List<GithubContributorItem>>( .getJSON<List, List<GithubContributorItem>>(
'/repos/$owner/$name/contributors?page=$page', '/repos/$owner/$name/contributors?page=$page',
convert: (vs) => convert: (vs) =>

View File

@ -20,7 +20,7 @@ class GhEventsScreen extends StatelessWidget {
itemBuilder: (payload) => EventItem(payload), itemBuilder: (payload) => EventItem(payload),
fetch: (page) async { fetch: (page) async {
page = page ?? 1; page = page ?? 1;
final events = await context.read<AuthModel>().ghClient!.getJSON( final events = await context.read<AuthModel>().ghClient.getJSON(
'/users/$login/events?page=$page&per_page=$PAGE_SIZE', '/users/$login/events?page=$page&per_page=$PAGE_SIZE',
convert: (dynamic vs) => convert: (dynamic vs) =>
[for (var v in vs) GithubEvent.fromJson(v)]); [for (var v in vs) GithubEvent.fromJson(v)]);

View File

@ -31,7 +31,7 @@ class GhFilesScreen extends StatelessWidget {
page = page ?? 1; page = page ?? 1;
final res = await context final res = await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.getJSON<List, List<GithubFilesItem>>( .getJSON<List, List<GithubFilesItem>>(
'/repos/$owner/$name/pulls/$pullNumber/files?page=$page', '/repos/$owner/$name/pulls/$pullNumber/files?page=$page',
convert: (vs) => [for (var v in vs) GithubFilesItem.fromJson(v)], convert: (vs) => [for (var v in vs) GithubFilesItem.fromJson(v)],

View File

@ -24,7 +24,7 @@ class GhGistsScreen extends StatelessWidget {
..vars.login = login ..vars.login = login
..vars.after = page); ..vars.after = page);
final OperationResponse<GGistsData, GGistsVars?> res = final OperationResponse<GGistsData, GGistsVars?> res =
await context.read<AuthModel>().gqlClient!.request(req).first; await context.read<AuthModel>().gqlClient.request(req).first;
final gists = res.data!.user!.gists; final gists = res.data!.user!.gists;
return ListPayload( return ListPayload(
cursor: gists.pageInfo.endCursor, cursor: gists.pageInfo.endCursor,

View File

@ -26,7 +26,7 @@ class GhGistsFilesScreen extends StatelessWidget {
..vars.login = login ..vars.login = login
..vars.name = id); ..vars.name = id);
final OperationResponse<GGistData, GGistVars?> res = final OperationResponse<GGistData, GGistVars?> res =
await context.read<AuthModel>().gqlClient!.request(req).first; await context.read<AuthModel>().gqlClient.request(req).first;
final gist = res.data!.user!.gist; final gist = res.data!.user!.gist;
return gist; return gist;
}, },

View File

@ -96,7 +96,7 @@ class GhIssueScreen extends StatelessWidget {
b.vars.cursor = cursor; b.vars.cursor = cursor;
}); });
OperationResponse<GIssueData, GIssueVars?> res = OperationResponse<GIssueData, GIssueVars?> res =
await context.read<AuthModel>().gqlClient!.request(req).first; await context.read<AuthModel>().gqlClient.request(req).first;
return res.data!.repository!; return res.data!.repository!;
} }
@ -115,7 +115,7 @@ class GhIssueScreen extends StatelessWidget {
ActionItem( ActionItem(
text: d.closed ? 'Reopen issue' : 'Close issue', text: d.closed ? 'Reopen issue' : 'Close issue',
onTap: (_) async { onTap: (_) async {
await context.read<AuthModel>().ghClient!.issues.edit( await context.read<AuthModel>().ghClient.issues.edit(
github.RepositorySlug(owner, name), github.RepositorySlug(owner, name),
number, number,
github.IssueRequest( github.IssueRequest(

View File

@ -59,7 +59,7 @@ class _GhIssueFormScreenState extends State<GhIssueFormScreen> {
final slug = RepositorySlug(widget.owner, widget.name); final slug = RepositorySlug(widget.owner, widget.name);
final res = await context final res = await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.issues .issues
.create(slug, IssueRequest(title: _title, body: _body)); .create(slug, IssueRequest(title: _title, body: _body));
await theme.push( await theme.push(

View File

@ -33,7 +33,7 @@ class GhIssuesScreen extends StatelessWidget {
b.vars.cursor = cursor; b.vars.cursor = cursor;
}); });
final OperationResponse<GIssuesData, GIssuesVars?> res = final OperationResponse<GIssuesData, GIssuesVars?> res =
await context.read<AuthModel>().gqlClient!.request(req).first; await context.read<AuthModel>().gqlClient.request(req).first;
final issues = res.data!.repository!.issues; final issues = res.data!.repository!.issues;
return ListPayload( return ListPayload(
cursor: issues.pageInfo.endCursor, cursor: issues.pageInfo.endCursor,

View File

@ -24,7 +24,7 @@ class GhNewsScreenState extends State<GhNewsScreen> {
// 1 item is enough since count is not displayed for now. // 1 item is enough since count is not displayed for now.
var items = await context var items = await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.getJSON('/notifications?per_page=1'); .getJSON('/notifications?per_page=1');
if (items is List && items.isNotEmpty) { if (items is List && items.isNotEmpty) {
@ -43,7 +43,7 @@ class GhNewsScreenState extends State<GhNewsScreen> {
final auth = context.read<AuthModel>(); final auth = context.read<AuthModel>();
final login = auth.activeAccount!.login; final login = auth.activeAccount!.login;
final events = await auth.ghClient!.getJSON( final events = await auth.ghClient.getJSON(
'/users/$login/received_events?page=$page&per_page=$PAGE_SIZE', '/users/$login/received_events?page=$page&per_page=$PAGE_SIZE',
convert: (dynamic vs) => [for (var v in vs) GithubEvent.fromJson(v)], convert: (dynamic vs) => [for (var v in vs) GithubEvent.fromJson(v)],
); );

View File

@ -21,7 +21,7 @@ class GhNotificationScreen extends StatefulWidget {
class GhNotificationScreenState extends State<GhNotificationScreen> { class GhNotificationScreenState extends State<GhNotificationScreen> {
Future<Map<String, NotificationGroup>> fetchNotifications(int index) async { Future<Map<String, NotificationGroup>> fetchNotifications(int index) async {
final ns = await context.read<AuthModel>().ghClient!.getJSON( final ns = await context.read<AuthModel>().ghClient.getJSON(
'/notifications?all=${index == 2}&participating=${index == 1}', '/notifications?all=${index == 2}&participating=${index == 1}',
convert: (dynamic vs) => convert: (dynamic vs) =>
[for (var v in vs) GithubNotificationItem.fromJson(v)], [for (var v in vs) GithubNotificationItem.fromJson(v)],
@ -123,7 +123,7 @@ ${item.key}: pullRequest(number: ${item.subject!.number}) {
onTap: () async { onTap: () async {
await context await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.activity .activity
.markRepositoryNotificationsRead( .markRepositoryNotificationsRead(
RepositorySlug.full(group.fullName!)); RepositorySlug.full(group.fullName!));

View File

@ -37,7 +37,7 @@ class GhObjectScreen extends StatelessWidget {
final suffix = path == null ? '' : '/$path'; final suffix = path == null ? '' : '/$path';
final res = await context final res = await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.repositories .repositories
.getContents(RepositorySlug(owner, name), suffix, ref: ref); .getContents(RepositorySlug(owner, name), suffix, ref: ref);
if (res.isDirectory) { if (res.isDirectory) {

View File

@ -25,7 +25,7 @@ class GhOrgReposScreen extends StatelessWidget {
page = page ?? 1; page = page ?? 1;
final rs = await context final rs = await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.getJSON<List, List<Repository>>( .getJSON<List, List<Repository>>(
'/orgs/$owner/repos?sort=updated&page=$page', '/orgs/$owner/repos?sort=updated&page=$page',
convert: (vs) => [for (var v in vs) Repository.fromJson(v)], convert: (vs) => [for (var v in vs) Repository.fromJson(v)],

View File

@ -19,7 +19,7 @@ class GhUserOrganizationScreen extends StatelessWidget {
page = page ?? 1; page = page ?? 1;
final res = await context final res = await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.getJSON<List, List<GithubUserOrganizationItem>>( .getJSON<List, List<GithubUserOrganizationItem>>(
'/users/$login/orgs?page=$page', '/users/$login/orgs?page=$page',
convert: (vs) => convert: (vs) =>

View File

@ -28,7 +28,7 @@ class GhPullsScreen extends StatelessWidget {
b.vars.cursor = cursor; b.vars.cursor = cursor;
}); });
final OperationResponse<GPullsData, GPullsVars?> res = final OperationResponse<GPullsData, GPullsVars?> res =
await context.read<AuthModel>().gqlClient!.request(req).first; await context.read<AuthModel>().gqlClient.request(req).first;
final pulls = res.data!.repository!.pullRequests; final pulls = res.data!.repository!.pullRequests;
return ListPayload( return ListPayload(
cursor: pulls.pageInfo.endCursor, cursor: pulls.pageInfo.endCursor,

View File

@ -26,7 +26,7 @@ class GhReleasesScreen extends StatelessWidget {
..vars.name = name ..vars.name = name
..vars.cursor = page); ..vars.cursor = page);
final OperationResponse<GReleasesData, GReleasesVars?> res = final OperationResponse<GReleasesData, GReleasesVars?> res =
await context.read<AuthModel>().gqlClient!.request(req).first; await context.read<AuthModel>().gqlClient.request(req).first;
final releases = res.data!.repository!.releases; final releases = res.data!.repository!.releases;
return ListPayload( return ListPayload(
cursor: releases.pageInfo.endCursor, cursor: releases.pageInfo.endCursor,

View File

@ -57,10 +57,10 @@ class GhRepoScreen extends StatelessWidget {
..vars.branchSpecified = branch != null ..vars.branchSpecified = branch != null
..vars.branch = branch ?? ''); ..vars.branch = branch ?? '');
final OperationResponse<GRepoData, GRepoVars?> res = final OperationResponse<GRepoData, GRepoVars?> res =
await context.read<AuthModel>().gqlClient!.request(req).first; await context.read<AuthModel>().gqlClient.request(req).first;
final repo = res.data!.repository; final repo = res.data!.repository;
final ghClient = context.read<AuthModel>().ghClient!; final ghClient = context.read<AuthModel>().ghClient;
final countFuture = ghClient final countFuture = ghClient
.getJSON('/repos/$owner/$name/stats/contributors') .getJSON('/repos/$owner/$name/stats/contributors')
.then((v) => (v as List).length); .then((v) => (v as List).length);
@ -132,10 +132,8 @@ class GhRepoScreen extends StatelessWidget {
ActionItem( ActionItem(
text: _buildWatchState(v), text: _buildWatchState(v),
onTap: (_) async { onTap: (_) async {
final activityApi = context final activityApi =
.read<AuthModel>() context.read<AuthModel>().ghClient.activity;
.ghClient!
.activity;
switch (v) { switch (v) {
case GSubscriptionState.SUBSCRIBED: case GSubscriptionState.SUBSCRIBED:
case GSubscriptionState.IGNORED: case GSubscriptionState.IGNORED:
@ -173,7 +171,7 @@ class GhRepoScreen extends StatelessWidget {
text: repo.viewerHasStarred ? 'Unstar' : 'Star', text: repo.viewerHasStarred ? 'Unstar' : 'Star',
onTap: () async { onTap: () async {
final activityApi = final activityApi =
context.read<AuthModel>().ghClient!.activity; context.read<AuthModel>().ghClient.activity;
if (repo.viewerHasStarred) { if (repo.viewerHasStarred) {
await activityApi.unstar( await activityApi.unstar(
RepositorySlug(repo.owner.login, repo.name)); RepositorySlug(repo.owner.login, repo.name));

View File

@ -25,7 +25,7 @@ class GhRepos extends StatelessWidget {
b.vars.after = cursor; b.vars.after = cursor;
}); });
final OperationResponse<GReposData, GReposVars?> res = final OperationResponse<GReposData, GReposVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
final p = res.data!.user!.repositories; final p = res.data!.user!.repositories;
return ListPayload( return ListPayload(
cursor: p.pageInfo.endCursor, cursor: p.pageInfo.endCursor,
@ -56,7 +56,7 @@ class GhStars extends StatelessWidget {
b.vars.after = cursor; b.vars.after = cursor;
}); });
final OperationResponse<GStarsData, GStarsVars?> res = final OperationResponse<GStarsData, GStarsVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
final p = res.data!.user!.starredRepositories; final p = res.data!.user!.starredRepositories;
return ListPayload( return ListPayload(
cursor: p.pageInfo.endCursor, cursor: p.pageInfo.endCursor,

View File

@ -272,7 +272,7 @@ class GhViewer extends StatelessWidget {
fetch: () async { fetch: () async {
final req = GViewerReq(); final req = GViewerReq();
final OperationResponse<GViewerData, GViewerVars?> res = final OperationResponse<GViewerData, GViewerVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
return res.data!.viewer; return res.data!.viewer;
}, },
title: AppBarTitle(AppLocalizations.of(context)!.me), title: AppBarTitle(AppLocalizations.of(context)!.me),
@ -298,7 +298,7 @@ class GhUser extends StatelessWidget {
fetch: () async { fetch: () async {
final req = GUserReq((b) => b..vars.login = login); final req = GUserReq((b) => b..vars.login = login);
final OperationResponse<GUserData, GUserVars?> res = final OperationResponse<GUserData, GUserVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
return res.data; return res.data;
}, },
title: AppBarTitle(login), title: AppBarTitle(login),
@ -322,9 +322,9 @@ class GhUser extends StatelessWidget {
: AppLocalizations.of(context)!.follow, : AppLocalizations.of(context)!.follow,
onTap: () async { onTap: () async {
if (p.viewerIsFollowing) { if (p.viewerIsFollowing) {
await auth.ghClient!.users.unfollowUser(p.login); await auth.ghClient.users.unfollowUser(p.login);
} else { } else {
await auth.ghClient!.users.followUser(p.login); await auth.ghClient.users.followUser(p.login);
} }
setData(data.rebuild((b) { setData(data.rebuild((b) {
final u = b.repositoryOwner final u = b.repositoryOwner

View File

@ -24,7 +24,7 @@ class GhFollowers extends StatelessWidget {
b.vars.after = cursor; b.vars.after = cursor;
}); });
final OperationResponse<GFollowersData, GFollowersVars?> res = final OperationResponse<GFollowersData, GFollowersVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
final p = res.data!.user!.followers; final p = res.data!.user!.followers;
return ListPayload( return ListPayload(
cursor: p.pageInfo.endCursor, cursor: p.pageInfo.endCursor,
@ -54,7 +54,7 @@ class GhFollowing extends StatelessWidget {
b.vars.after = cursor; b.vars.after = cursor;
}); });
final OperationResponse<GFollowingData, GFollowingVars?> res = final OperationResponse<GFollowingData, GFollowingVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
final p = res.data!.user!.following; final p = res.data!.user!.following;
return ListPayload( return ListPayload(
cursor: p.pageInfo.endCursor, cursor: p.pageInfo.endCursor,
@ -84,7 +84,7 @@ class GhMembers extends StatelessWidget {
b.vars.after = cursor; b.vars.after = cursor;
}); });
final OperationResponse<GMembersData, GMembersVars?> res = final OperationResponse<GMembersData, GMembersVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
final p = res.data!.organization!.membersWithRole; final p = res.data!.organization!.membersWithRole;
return ListPayload( return ListPayload(
cursor: p.pageInfo.endCursor, cursor: p.pageInfo.endCursor,
@ -116,7 +116,7 @@ class GhWachers extends StatelessWidget {
b.vars.after = cursor; b.vars.after = cursor;
}); });
final OperationResponse<GWatchersData, GWatchersVars?> res = final OperationResponse<GWatchersData, GWatchersVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
final p = res.data!.repository!.watchers; final p = res.data!.repository!.watchers;
return ListPayload( return ListPayload(
cursor: p.pageInfo.endCursor, cursor: p.pageInfo.endCursor,
@ -148,7 +148,7 @@ class GhStargazers extends StatelessWidget {
b.vars.after = cursor; b.vars.after = cursor;
}); });
final OperationResponse<GStargazersData, GStargazersVars?> res = final OperationResponse<GStargazersData, GStargazersVars?> res =
await auth.gqlClient!.request(req).first; await auth.gqlClient.request(req).first;
final p = res.data!.repository!.stargazers; final p = res.data!.repository!.stargazers;
return ListPayload( return ListPayload(
cursor: p.pageInfo.endCursor, cursor: p.pageInfo.endCursor,

View File

@ -44,62 +44,58 @@ class GoUserScreen extends StatelessWidget {
bodyBuilder: (p, _) { bodyBuilder: (p, _) {
final user = p.item1; final user = p.item1;
final repos = p.item2; final repos = p.item2;
if (p.item1 != null) { return Column(
return Column( children: <Widget>[
children: <Widget>[ UserHeader(
UserHeader( login: user.username,
login: user.username, avatarUrl: user.avatarUrl,
avatarUrl: user.avatarUrl, name: user.fullName,
name: user.fullName, createdAt:
createdAt: null, // TODO: API response does not have this attribute
null, // TODO: API response does not have this attribute isViewer: isViewer,
isViewer: isViewer, bio: null, // TODO: API response does not have this attribute
bio: null, // TODO: API response does not have this attribute ),
CommonStyle.border,
Row(children: [
EntryItem(
text: 'Repositories',
url: '/gogs/$login?tab=repositories&isViewer=$isViewer',
), ),
CommonStyle.border, EntryItem(
Row(children: [ text: 'Followers',
EntryItem( url: '/gogs/$login?tab=followers',
text: 'Repositories', ),
url: '/gogs/$login?tab=repositories&isViewer=$isViewer', EntryItem(
text: 'Following',
url: '/gogs/$login?tab=following',
),
]),
CommonStyle.border,
TableView(
items: [
TableViewItem(
leftIconData: Octicons.home,
text: Text('Organizations'),
url:
'/gogs/${user.username}?tab=organizations&isViewer=$isViewer',
), ),
EntryItem( ],
text: 'Followers', ),
url: '/gogs/$login?tab=followers', CommonStyle.border,
), Column(
EntryItem( children: <Widget>[
text: 'Following', for (var v in repos) ...[
url: '/gogs/$login?tab=following', RepositoryItem.go(
), payload: v,
]), name: v.fullName!.split('/')[1],
CommonStyle.border, owner: v.owner!.username,
TableView(
items: [
TableViewItem(
leftIconData: Octicons.home,
text: Text('Organizations'),
url:
'/gogs/${user.username}?tab=organizations&isViewer=$isViewer',
), ),
], CommonStyle.border,
), ]
CommonStyle.border, ],
Column( ),
children: <Widget>[ ],
for (var v in repos) ...[ );
RepositoryItem.go(
payload: v,
name: v.fullName!.split('/')[1],
owner: v.owner!.username,
),
CommonStyle.border,
]
],
),
],
);
} else {
return Text('404'); // TODO:
}
}, },
); );
} }

View File

@ -83,7 +83,7 @@ class _NotificationItemState extends State<NotificationItem> {
try { try {
await context await context
.read<AuthModel>() .read<AuthModel>()
.ghClient! .ghClient
.activity .activity
.markThreadRead(payload.id!); .markThreadRead(payload.id!);
widget.markAsRead(); widget.markAsRead();