2022-09-24 20:46:37 +02:00
|
|
|
import 'package:antd_mobile/antd_mobile.dart';
|
2019-01-23 12:52:51 +01:00
|
|
|
import 'package:flutter/cupertino.dart';
|
2022-09-17 14:35:45 +02:00
|
|
|
import 'package:flutter_gen/gen_l10n/S.dart';
|
|
|
|
import 'package:git_touch/models/auth.dart';
|
2019-10-02 08:58:11 +02:00
|
|
|
import 'package:git_touch/scaffolds/common.dart';
|
2020-01-11 12:25:33 +01:00
|
|
|
import 'package:git_touch/utils/utils.dart';
|
2019-09-25 14:51:23 +02:00
|
|
|
import 'package:git_touch/widgets/issue_item.dart';
|
2019-09-29 16:10:15 +02:00
|
|
|
import 'package:git_touch/widgets/loading.dart';
|
2022-10-02 06:49:55 +02:00
|
|
|
import 'package:git_touch/widgets/repo_item.dart';
|
2019-09-25 14:51:23 +02:00
|
|
|
import 'package:git_touch/widgets/user_item.dart';
|
2019-09-29 16:10:15 +02:00
|
|
|
import 'package:primer/primer.dart';
|
2019-09-02 15:52:32 +02:00
|
|
|
import 'package:provider/provider.dart';
|
2020-01-11 12:25:33 +01:00
|
|
|
import 'package:timeago/timeago.dart' as timeago;
|
2019-01-23 12:52:51 +01:00
|
|
|
|
2020-02-07 07:17:05 +01:00
|
|
|
class GhSearchScreen extends StatefulWidget {
|
2019-01-23 12:52:51 +01:00
|
|
|
@override
|
2022-10-03 19:05:29 +02:00
|
|
|
State<GhSearchScreen> createState() => _GhSearchScreenState();
|
2019-02-02 17:28:51 +01:00
|
|
|
}
|
|
|
|
|
2020-02-07 07:17:05 +01:00
|
|
|
class _GhSearchScreenState extends State<GhSearchScreen> {
|
2021-05-16 09:16:35 +02:00
|
|
|
int? _activeTab = 0;
|
2019-09-25 14:51:23 +02:00
|
|
|
bool _loading = false;
|
2022-09-06 18:28:12 +02:00
|
|
|
final List<List?> _payloads = [[], [], []];
|
2019-01-23 12:52:51 +01:00
|
|
|
|
2021-05-16 09:16:35 +02:00
|
|
|
TextEditingController? _controller;
|
2019-09-25 14:51:23 +02:00
|
|
|
|
2021-06-05 07:54:52 +02:00
|
|
|
String get _keyword => _controller!.text.trim();
|
2019-09-25 14:51:23 +02:00
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
_controller = TextEditingController();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void dispose() {
|
2021-05-16 09:16:35 +02:00
|
|
|
_controller!.dispose();
|
2019-09-25 14:51:23 +02:00
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _query() async {
|
|
|
|
if (_loading || _keyword.isEmpty) return;
|
|
|
|
|
2022-09-24 07:41:46 +02:00
|
|
|
final keyword = _controller!.text;
|
2019-02-10 06:42:02 +01:00
|
|
|
setState(() {
|
2019-09-25 14:51:23 +02:00
|
|
|
_loading = true;
|
2019-02-10 06:42:02 +01:00
|
|
|
});
|
|
|
|
try {
|
2020-10-04 14:37:23 +02:00
|
|
|
final auth = context.read<AuthModel>();
|
|
|
|
final data = await auth.query('''
|
2019-02-10 06:42:02 +01:00
|
|
|
{
|
2022-10-03 19:05:29 +02:00
|
|
|
repository: search(first: $kPageSize, type: REPOSITORY, query: "$keyword") {
|
2019-02-10 06:42:02 +01:00
|
|
|
nodes {
|
|
|
|
... on Repository {
|
2020-01-11 10:25:01 +01:00
|
|
|
owner {
|
|
|
|
__typename
|
|
|
|
login
|
|
|
|
avatarUrl
|
|
|
|
}
|
|
|
|
name
|
|
|
|
description
|
|
|
|
isPrivate
|
|
|
|
isFork
|
2020-01-11 12:25:33 +01:00
|
|
|
updatedAt
|
2020-01-11 10:25:01 +01:00
|
|
|
stargazers {
|
|
|
|
totalCount
|
|
|
|
}
|
|
|
|
forks {
|
|
|
|
totalCount
|
|
|
|
}
|
|
|
|
primaryLanguage {
|
|
|
|
color
|
|
|
|
name
|
|
|
|
}
|
2019-02-10 06:42:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-10-03 19:05:29 +02:00
|
|
|
user: search(first: $kPageSize, type: USER, query: "$keyword") {
|
2019-09-25 14:51:23 +02:00
|
|
|
nodes {
|
|
|
|
... on Organization {
|
|
|
|
__typename
|
|
|
|
name
|
|
|
|
avatarUrl
|
|
|
|
bio: description
|
|
|
|
login
|
|
|
|
}
|
|
|
|
... on User {
|
|
|
|
$userGqlChunk
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-10-03 19:05:29 +02:00
|
|
|
issue: search(first: $kPageSize, type: ISSUE, query: "$keyword") {
|
2019-09-25 14:51:23 +02:00
|
|
|
nodes {
|
|
|
|
... on PullRequest {
|
|
|
|
__typename
|
|
|
|
$issueGqlChunk
|
|
|
|
}
|
|
|
|
... on Issue {
|
|
|
|
$issueGqlChunk
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-10 06:42:02 +01:00
|
|
|
}
|
|
|
|
''');
|
2019-09-25 14:51:23 +02:00
|
|
|
_payloads[0] = data['repository']['nodes'];
|
|
|
|
_payloads[1] = data['user']['nodes'];
|
|
|
|
_payloads[2] = data['issue']['nodes'];
|
2019-02-10 06:42:02 +01:00
|
|
|
} finally {
|
|
|
|
setState(() {
|
2019-09-25 14:51:23 +02:00
|
|
|
_loading = false;
|
2019-02-10 06:42:02 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-16 09:16:35 +02:00
|
|
|
_onTabSwitch(int? index) {
|
2019-09-29 16:10:15 +02:00
|
|
|
setState(() {
|
|
|
|
_activeTab = index;
|
|
|
|
});
|
2021-05-16 09:16:35 +02:00
|
|
|
if (_payloads[_activeTab!]!.isEmpty) {
|
2019-09-29 16:10:15 +02:00
|
|
|
_query();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const tabs = ['Repositories', 'Users', 'Issues'];
|
|
|
|
|
2021-01-30 08:42:02 +01:00
|
|
|
// static IconData _buildIconData(p) {
|
|
|
|
// if (p['isPrivate']) {
|
|
|
|
// return Octicons.lock;
|
|
|
|
// }
|
|
|
|
// if (p['isFork']) {
|
|
|
|
// return Octicons.repo_forked;
|
|
|
|
// }
|
|
|
|
// return Octicons.repo;
|
|
|
|
// }
|
2020-01-11 10:25:01 +01:00
|
|
|
|
|
|
|
Widget _buildItem(p) {
|
2019-09-25 14:51:23 +02:00
|
|
|
switch (_activeTab) {
|
|
|
|
case 0:
|
2020-01-11 12:25:33 +01:00
|
|
|
final updatedAt = timeago.format(DateTime.parse(p['updatedAt']));
|
2022-10-02 06:49:55 +02:00
|
|
|
return RepoItem.gh(
|
2020-01-29 06:06:55 +01:00
|
|
|
owner: p['owner']['login'],
|
|
|
|
avatarUrl: p['owner']['avatarUrl'],
|
|
|
|
name: p['name'],
|
|
|
|
description: p['description'],
|
|
|
|
starCount: p['stargazers']['totalCount'],
|
|
|
|
forkCount: p['forks']['totalCount'],
|
|
|
|
primaryLanguageName: p['primaryLanguage'] == null
|
|
|
|
? null
|
|
|
|
: p['primaryLanguage']['name'],
|
|
|
|
primaryLanguageColor: p['primaryLanguage'] == null
|
|
|
|
? null
|
|
|
|
: p['primaryLanguage']['color'],
|
|
|
|
note: 'Updated $updatedAt',
|
2020-01-11 12:52:17 +01:00
|
|
|
isPrivate: p['isPrivate'],
|
|
|
|
isFork: p['isFork'],
|
2020-01-11 10:25:01 +01:00
|
|
|
);
|
2019-09-25 14:51:23 +02:00
|
|
|
case 1:
|
2020-10-08 09:55:26 +02:00
|
|
|
return UserItem.github(
|
2020-01-11 10:25:01 +01:00
|
|
|
login: p['login'],
|
2020-10-08 09:55:26 +02:00
|
|
|
name: p['name'],
|
2020-01-11 10:25:01 +01:00
|
|
|
avatarUrl: p['avatarUrl'],
|
|
|
|
bio: Text(p['bio'] ?? ''),
|
2020-01-01 08:58:49 +01:00
|
|
|
);
|
2019-09-25 14:51:23 +02:00
|
|
|
case 2:
|
2019-02-02 17:28:51 +01:00
|
|
|
default:
|
2019-09-25 14:51:23 +02:00
|
|
|
return IssueItem(
|
2020-01-28 16:19:05 +01:00
|
|
|
author: p['author']['login'],
|
|
|
|
avatarUrl: p['author']['avatarUrl'],
|
|
|
|
commentCount: p['comments']['totalCount'],
|
2022-09-06 18:28:12 +02:00
|
|
|
subtitle: '#${p['number']}',
|
2020-01-28 16:19:05 +01:00
|
|
|
title: p['title'],
|
|
|
|
updatedAt: DateTime.parse(p['updatedAt']),
|
2022-09-06 18:28:12 +02:00
|
|
|
url: '/github${Uri.parse(p['url']).path}',
|
2020-01-28 16:19:05 +01:00
|
|
|
isPr: p['__typename'] == 'PullRequest',
|
|
|
|
);
|
2019-02-02 17:28:51 +01:00
|
|
|
}
|
2019-01-23 12:52:51 +01:00
|
|
|
}
|
2019-02-10 06:42:02 +01:00
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2022-09-17 14:35:45 +02:00
|
|
|
return CommonScaffold(
|
|
|
|
title: Container(
|
2022-09-24 20:46:37 +02:00
|
|
|
color: AntTheme.of(context).colorBackground,
|
2022-09-17 14:35:45 +02:00
|
|
|
child: CupertinoTextField(
|
|
|
|
prefix: Row(
|
|
|
|
children: const <Widget>[
|
|
|
|
SizedBox(width: 8),
|
|
|
|
Icon(Octicons.search, size: 20, color: PrimerColors.gray400),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
placeholder: AppLocalizations.of(context)!.search,
|
|
|
|
clearButtonMode: OverlayVisibilityMode.editing,
|
|
|
|
textInputAction: TextInputAction.go,
|
|
|
|
onSubmitted: (_) => _query(),
|
|
|
|
controller: _controller,
|
|
|
|
),
|
|
|
|
),
|
2019-09-29 16:10:15 +02:00
|
|
|
body: SingleChildScrollView(
|
2019-10-03 04:46:53 +02:00
|
|
|
child: Column(
|
|
|
|
children: [
|
2022-09-17 14:46:39 +02:00
|
|
|
Center(
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
|
|
|
child: CupertinoSlidingSegmentedControl(
|
|
|
|
groupValue: _activeTab,
|
|
|
|
onValueChanged: _onTabSwitch,
|
|
|
|
children: tabs.asMap().map((key, text) => MapEntry(
|
|
|
|
key,
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
|
|
child: Text(text, style: const TextStyle(fontSize: 14)),
|
|
|
|
))),
|
2019-10-03 04:46:53 +02:00
|
|
|
),
|
2019-09-29 16:10:15 +02:00
|
|
|
),
|
2022-09-17 14:46:39 +02:00
|
|
|
),
|
2019-10-03 04:46:53 +02:00
|
|
|
if (_loading)
|
2022-09-06 18:28:12 +02:00
|
|
|
const Loading()
|
2019-10-03 04:46:53 +02:00
|
|
|
else
|
2021-05-16 09:16:35 +02:00
|
|
|
..._payloads[_activeTab!]!.map(_buildItem).toList(),
|
2019-10-03 04:46:53 +02:00
|
|
|
],
|
|
|
|
),
|
2019-09-29 16:10:15 +02:00
|
|
|
),
|
2019-02-10 06:42:02 +01:00
|
|
|
);
|
|
|
|
}
|
2019-01-23 12:52:51 +01:00
|
|
|
}
|