mirror of
https://github.com/git-touch/git-touch
synced 2025-02-23 14:57:42 +01:00
feat(gitee): watch, star a repo (#157)
* feat(gitee): watch, star a repo * fix: pass in props as Tuple * feat: bitbucket branches * fix: use class instead of map
This commit is contained in:
parent
2017014ffd
commit
c75288ef97
@ -337,7 +337,15 @@ class AuthModel with ChangeNotifier {
|
|||||||
'${activeAccount.domain}/api/v5$p',
|
'${activeAccount.domain}/api/v5$p',
|
||||||
headers: headers,
|
headers: headers,
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
|
}
|
||||||
|
case 'PUT':
|
||||||
|
{
|
||||||
|
await http.put(
|
||||||
|
'${activeAccount.domain}/api/v5$p',
|
||||||
|
headers: headers,
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
case 'POST':
|
case 'POST':
|
||||||
{
|
{
|
||||||
@ -357,6 +365,12 @@ class AuthModel with ChangeNotifier {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'NO CONTENT':
|
||||||
|
{
|
||||||
|
res = await http.get('${activeAccount.domain}/api/v5$p',
|
||||||
|
headers: headers);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
res = await http.get('${activeAccount.domain}/api/v5$p',
|
res = await http.get('${activeAccount.domain}/api/v5$p',
|
||||||
@ -364,11 +378,8 @@ class AuthModel with ChangeNotifier {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (requestType != 'DELETE') {
|
final info = json.decode(utf8.decode(res.bodyBytes));
|
||||||
final info = json.decode(utf8.decode(res.bodyBytes));
|
return info;
|
||||||
return info;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<DataWithPage> fetchGiteeWithPage(String path,
|
Future<DataWithPage> fetchGiteeWithPage(String path,
|
||||||
|
@ -144,3 +144,12 @@ class BbComment {
|
|||||||
factory BbComment.fromJson(Map<String, dynamic> json) =>
|
factory BbComment.fromJson(Map<String, dynamic> json) =>
|
||||||
_$BbCommentFromJson(json);
|
_$BbCommentFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||||
|
class BbBranch {
|
||||||
|
String name;
|
||||||
|
String type;
|
||||||
|
BbBranch();
|
||||||
|
factory BbBranch.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$BbBranchFromJson(json);
|
||||||
|
}
|
||||||
|
@ -247,3 +247,14 @@ Map<String, dynamic> _$BbCommentToJson(BbComment instance) => <String, dynamic>{
|
|||||||
'content': instance.content,
|
'content': instance.content,
|
||||||
'user': instance.user,
|
'user': instance.user,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BbBranch _$BbBranchFromJson(Map<String, dynamic> json) {
|
||||||
|
return BbBranch()
|
||||||
|
..name = json['name'] as String
|
||||||
|
..type = json['type'] as String;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> _$BbBranchToJson(BbBranch instance) => <String, dynamic>{
|
||||||
|
'name': instance.name,
|
||||||
|
'type': instance.type,
|
||||||
|
};
|
||||||
|
@ -426,11 +426,14 @@ class BitbucketRouter {
|
|||||||
'/:login',
|
'/:login',
|
||||||
(context, parameters) => BbUserScreen(parameters['login'].first,
|
(context, parameters) => BbUserScreen(parameters['login'].first,
|
||||||
isTeam: parameters['team'].first == '1'));
|
isTeam: parameters['team'].first == '1'));
|
||||||
static final repo = RouterScreen(
|
static final repo = RouterScreen('/:owner/:name', (context, parameters) {
|
||||||
'/:owner/:name',
|
if (parameters['branch'] == null) {
|
||||||
(context, parameters) =>
|
return BbRepoScreen(parameters['owner'].first, parameters['name'].first);
|
||||||
BbRepoScreen(parameters['owner'].first, parameters['name'].first),
|
} else {
|
||||||
);
|
return BbRepoScreen(parameters['owner'].first, parameters['name'].first,
|
||||||
|
branch: parameters['branch'].first);
|
||||||
|
}
|
||||||
|
});
|
||||||
static final object = RouterScreen(
|
static final object = RouterScreen(
|
||||||
'/:owner/:name/src/:ref',
|
'/:owner/:name/src/:ref',
|
||||||
(context, parameters) => BbObjectScreen(
|
(context, parameters) => BbObjectScreen(
|
||||||
|
@ -18,11 +18,12 @@ import '../generated/l10n.dart';
|
|||||||
class BbRepoScreen extends StatelessWidget {
|
class BbRepoScreen extends StatelessWidget {
|
||||||
final String owner;
|
final String owner;
|
||||||
final String name;
|
final String name;
|
||||||
BbRepoScreen(this.owner, this.name);
|
final String branch;
|
||||||
|
BbRepoScreen(this.owner, this.name, {this.branch});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return RefreshStatefulScaffold<Tuple2<BbRepo, String>>(
|
return RefreshStatefulScaffold<Tuple3<BbRepo, String, List<BbBranch>>>(
|
||||||
title: AppBarTitle(S.of(context).repository),
|
title: AppBarTitle(S.of(context).repository),
|
||||||
fetch: () async {
|
fetch: () async {
|
||||||
final auth = context.read<AuthModel>();
|
final auth = context.read<AuthModel>();
|
||||||
@ -32,11 +33,17 @@ class BbRepoScreen extends StatelessWidget {
|
|||||||
'/repositories/$owner/$name/src/${repo.mainbranch.name}/README.md');
|
'/repositories/$owner/$name/src/${repo.mainbranch.name}/README.md');
|
||||||
final readme =
|
final readme =
|
||||||
res.statusCode >= 400 ? null : utf8.decode(res.bodyBytes);
|
res.statusCode >= 400 ? null : utf8.decode(res.bodyBytes);
|
||||||
return Tuple2(repo, readme);
|
final branches = await auth
|
||||||
|
.fetchBbWithPage('/repositories/$owner/$name/refs/branches')
|
||||||
|
.then((v) {
|
||||||
|
return [for (var branch in v.data) BbBranch.fromJson(branch)];
|
||||||
|
});
|
||||||
|
return Tuple3(repo, readme, branches);
|
||||||
},
|
},
|
||||||
bodyBuilder: (t, setState) {
|
bodyBuilder: (t, setState) {
|
||||||
final theme = Provider.of<ThemeModel>(context);
|
final theme = Provider.of<ThemeModel>(context);
|
||||||
final p = t.item1;
|
final p = t.item1;
|
||||||
|
final branches = t.item3;
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
@ -56,7 +63,8 @@ class BbRepoScreen extends StatelessWidget {
|
|||||||
leftIconData: Octicons.code,
|
leftIconData: Octicons.code,
|
||||||
text: Text('Code'),
|
text: Text('Code'),
|
||||||
rightWidget: Text(filesize(p.size)),
|
rightWidget: Text(filesize(p.size)),
|
||||||
url: '/bitbucket/$owner/$name/src/${p.mainbranch.name}',
|
url:
|
||||||
|
'/bitbucket/$owner/$name/src/${branch == null ? p.mainbranch.name : branch}',
|
||||||
),
|
),
|
||||||
TableViewItem(
|
TableViewItem(
|
||||||
leftIconData: Octicons.issue_opened,
|
leftIconData: Octicons.issue_opened,
|
||||||
@ -71,8 +79,38 @@ class BbRepoScreen extends StatelessWidget {
|
|||||||
TableViewItem(
|
TableViewItem(
|
||||||
leftIconData: Octicons.history,
|
leftIconData: Octicons.history,
|
||||||
text: Text('Commits'),
|
text: Text('Commits'),
|
||||||
url: '/bitbucket/$owner/$name/commits/${p.mainbranch.name}',
|
url:
|
||||||
|
'/bitbucket/$owner/$name/commits/${branch == null ? p.mainbranch.name : branch}',
|
||||||
),
|
),
|
||||||
|
if (branches != null)
|
||||||
|
TableViewItem(
|
||||||
|
leftIconData: Octicons.git_branch,
|
||||||
|
text: Text(S.of(context).branches),
|
||||||
|
rightWidget: Text(
|
||||||
|
(branch == null ? p.mainbranch.name : branch) +
|
||||||
|
' • ' +
|
||||||
|
branches.length.toString()),
|
||||||
|
onTap: () async {
|
||||||
|
if (branches.length < 2) return;
|
||||||
|
|
||||||
|
await theme.showPicker(
|
||||||
|
context,
|
||||||
|
PickerGroupItem(
|
||||||
|
value: branch,
|
||||||
|
items: branches
|
||||||
|
.map((b) => PickerItem(b.name, text: b.name))
|
||||||
|
.toList(),
|
||||||
|
onClose: (ref) {
|
||||||
|
if (ref != branch) {
|
||||||
|
theme.push(context,
|
||||||
|
'/bitbucket/$owner/$name?branch=$ref',
|
||||||
|
replace: true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
CommonStyle.verticalGap,
|
CommonStyle.verticalGap,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:git_touch/models/auth.dart';
|
import 'package:git_touch/models/auth.dart';
|
||||||
import 'package:git_touch/models/gitee.dart';
|
import 'package:git_touch/models/gitee.dart';
|
||||||
@ -8,6 +9,7 @@ import 'package:git_touch/utils/utils.dart';
|
|||||||
import 'package:git_touch/widgets/app_bar_title.dart';
|
import 'package:git_touch/widgets/app_bar_title.dart';
|
||||||
import 'package:git_touch/widgets/entry_item.dart';
|
import 'package:git_touch/widgets/entry_item.dart';
|
||||||
import 'package:git_touch/widgets/markdown_view.dart';
|
import 'package:git_touch/widgets/markdown_view.dart';
|
||||||
|
import 'package:git_touch/widgets/mutation_button.dart';
|
||||||
import 'package:git_touch/widgets/repo_header.dart';
|
import 'package:git_touch/widgets/repo_header.dart';
|
||||||
import 'package:git_touch/widgets/table_view.dart';
|
import 'package:git_touch/widgets/table_view.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -15,6 +17,12 @@ import 'package:tuple/tuple.dart';
|
|||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import '../generated/l10n.dart';
|
import '../generated/l10n.dart';
|
||||||
|
|
||||||
|
class StatusPayload {
|
||||||
|
bool isWatching;
|
||||||
|
bool isStarred;
|
||||||
|
StatusPayload(this.isWatching, this.isStarred);
|
||||||
|
}
|
||||||
|
|
||||||
class GeRepoScreen extends StatelessWidget {
|
class GeRepoScreen extends StatelessWidget {
|
||||||
final String owner;
|
final String owner;
|
||||||
final String name;
|
final String name;
|
||||||
@ -24,7 +32,7 @@ class GeRepoScreen extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return RefreshStatefulScaffold<
|
return RefreshStatefulScaffold<
|
||||||
Tuple3<GiteeRepo, MarkdownViewData, List<GiteeBranch>>>(
|
Tuple4<GiteeRepo, MarkdownViewData, List<GiteeBranch>, StatusPayload>>(
|
||||||
title: AppBarTitle(S.of(context).repository),
|
title: AppBarTitle(S.of(context).repository),
|
||||||
fetch: () async {
|
fetch: () async {
|
||||||
final auth = context.read<AuthModel>();
|
final auth = context.read<AuthModel>();
|
||||||
@ -49,7 +57,15 @@ class GeRepoScreen extends StatelessWidget {
|
|||||||
await auth.fetchGitee('/repos/$owner/$name/branches').then((v) {
|
await auth.fetchGitee('/repos/$owner/$name/branches').then((v) {
|
||||||
return [for (var branch in v) GiteeBranch.fromJson(branch)];
|
return [for (var branch in v) GiteeBranch.fromJson(branch)];
|
||||||
});
|
});
|
||||||
return Tuple3(repo, readmeData, branches);
|
bool isStarred = await auth
|
||||||
|
.fetchGitee('/user/starred/$owner/$name', requestType: 'NO CONTENT')
|
||||||
|
.then((v) => v.statusCode == HttpStatus.noContent);
|
||||||
|
bool isWatching = await auth
|
||||||
|
.fetchGitee('/user/subscriptions/$owner/$name',
|
||||||
|
requestType: 'NO CONTENT')
|
||||||
|
.then((v) => v.statusCode == HttpStatus.noContent);
|
||||||
|
StatusPayload statusPayload = StatusPayload(isWatching, isStarred);
|
||||||
|
return Tuple4(repo, readmeData, branches, statusPayload);
|
||||||
},
|
},
|
||||||
bodyBuilder: (t, setState) {
|
bodyBuilder: (t, setState) {
|
||||||
final p = t.item1;
|
final p = t.item1;
|
||||||
@ -59,17 +75,48 @@ class GeRepoScreen extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
RepoHeader(
|
RepoHeader(
|
||||||
avatarUrl: p.owner.avatarUrl,
|
avatarUrl: p.owner.avatarUrl,
|
||||||
avatarLink: '/gitee/${p.namespace.path}',
|
avatarLink: '/gitee/${p.namespace.path}',
|
||||||
owner: p.namespace.path,
|
owner: p.namespace.path,
|
||||||
name: p.path,
|
name: p.path,
|
||||||
description: p.description,
|
description: p.description,
|
||||||
homepageUrl: p.homepage,
|
homepageUrl: p.homepage,
|
||||||
),
|
actions: [
|
||||||
CommonStyle.border,
|
Row(children: <Widget>[
|
||||||
|
MutationButton(
|
||||||
|
active: t.item4.isWatching,
|
||||||
|
text: t.item4.isWatching ? 'Ignore' : 'Watch',
|
||||||
|
onTap: () async {
|
||||||
|
final String watchType =
|
||||||
|
t.item4.isWatching ? 'ignoring' : 'watching';
|
||||||
|
await context.read<AuthModel>().fetchGitee(
|
||||||
|
'/user/subscriptions/$owner/$name?watch_type=$watchType',
|
||||||
|
requestType: t.item4.isWatching ? 'DELETE' : 'PUT');
|
||||||
|
setState(() {
|
||||||
|
t.item4.isWatching = !t.item4.isWatching;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
MutationButton(
|
||||||
|
active: t.item4.isStarred,
|
||||||
|
text: t.item4.isStarred ? 'Unstar' : 'Star',
|
||||||
|
onTap: () async {
|
||||||
|
await context.read<AuthModel>().fetchGitee(
|
||||||
|
'/user/starred/$owner/$name',
|
||||||
|
requestType: t.item4.isStarred ? 'DELETE' : 'PUT');
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
t.item4.isStarred = !t.item4.isStarred;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
])
|
||||||
|
]),
|
||||||
Row(
|
Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
EntryItem(
|
EntryItem(
|
||||||
|
count: p.watchersCount,
|
||||||
text: 'Watchers',
|
text: 'Watchers',
|
||||||
url: '/gitee/$owner/$name/watchers',
|
url: '/gitee/$owner/$name/watchers',
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user