Added descriptions to search results

This commit is contained in:
Imran Remtulla
2022-11-12 10:35:59 -05:00
parent 0e0a39a40f
commit 18951d6461
3 changed files with 68 additions and 23 deletions

View File

@@ -186,13 +186,19 @@ class GitHub extends AppSource {
} }
@override @override
Future<List<String>> search(String query) async { Future<Map<String, String>> search(String query) async {
Response res = await get(Uri.parse( Response res = await get(Uri.parse(
'https://${await getCredentialPrefixIfAny()}api.$host/search/repositories?q=${Uri.encodeQueryComponent(query)}&per_page=100')); 'https://${await getCredentialPrefixIfAny()}api.$host/search/repositories?q=${Uri.encodeQueryComponent(query)}&per_page=100'));
if (res.statusCode == 200) { if (res.statusCode == 200) {
return (jsonDecode(res.body)['items'] as List<dynamic>) Map<String, String> urlsWithDescriptions = {};
.map((e) => e['html_url'] as String) for (var e in (jsonDecode(res.body)['items'] as List<dynamic>)) {
.toList(); urlsWithDescriptions.addAll({
e['html_url'] as String: e['description'] != null
? e['description'] as String
: 'No description'
});
}
return urlsWithDescriptions;
} else { } else {
if (res.headers['x-ratelimit-remaining'] == '0') { if (res.headers['x-ratelimit-remaining'] == '0') {
throw RateLimitError( throw RateLimitError(

View File

@@ -12,6 +12,7 @@ import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:url_launcher/url_launcher_string.dart';
class ImportExportPage extends StatefulWidget { class ImportExportPage extends StatefulWidget {
const ImportExportPage({super.key}); const ImportExportPage({super.key});
@@ -258,9 +259,11 @@ class _ImportExportPageState extends State<ImportExportPage> {
setState(() { setState(() {
importInProgress = true; importInProgress = true;
}); });
var urls = await source var urlsWithDescriptions =
.search(values[0]); await source
if (urls.isNotEmpty) { .search(values[0]);
if (urlsWithDescriptions
.isNotEmpty) {
var selectedUrls = var selectedUrls =
await showDialog< await showDialog<
List< List<
@@ -270,7 +273,8 @@ class _ImportExportPageState extends State<ImportExportPage> {
(BuildContext (BuildContext
ctx) { ctx) {
return UrlSelectionModal( return UrlSelectionModal(
urls: urls, urlsWithDescriptions:
urlsWithDescriptions,
defaultSelected: defaultSelected:
false, false,
); );
@@ -363,7 +367,11 @@ class _ImportExportPageState extends State<ImportExportPage> {
(BuildContext (BuildContext
ctx) { ctx) {
return UrlSelectionModal( return UrlSelectionModal(
urls: urls); urlsWithDescriptions:
Map.fromIterable(
urls,
value: (item) =>
''));
}); });
if (selectedUrls != null) { if (selectedUrls != null) {
var errors = var errors =
@@ -477,9 +485,11 @@ class _ImportErrorDialogState extends State<ImportErrorDialog> {
// ignore: must_be_immutable // ignore: must_be_immutable
class UrlSelectionModal extends StatefulWidget { class UrlSelectionModal extends StatefulWidget {
UrlSelectionModal( UrlSelectionModal(
{super.key, required this.urls, this.defaultSelected = true}); {super.key,
required this.urlsWithDescriptions,
this.defaultSelected = true});
List<String> urls; Map<String, String> urlsWithDescriptions;
bool defaultSelected; bool defaultSelected;
@override @override
@@ -487,12 +497,13 @@ class UrlSelectionModal extends StatefulWidget {
} }
class _UrlSelectionModalState extends State<UrlSelectionModal> { class _UrlSelectionModalState extends State<UrlSelectionModal> {
Map<String, bool> urlSelections = {}; Map<MapEntry<String, String>, bool> urlWithDescriptionSelections = {};
@override @override
void initState() { void initState() {
super.initState(); super.initState();
for (var url in widget.urls) { for (var url in widget.urlsWithDescriptions.entries) {
urlSelections.putIfAbsent(url, () => widget.defaultSelected); urlWithDescriptionSelections.putIfAbsent(
url, () => widget.defaultSelected);
} }
} }
@@ -502,21 +513,48 @@ class _UrlSelectionModalState extends State<UrlSelectionModal> {
scrollable: true, scrollable: true,
title: const Text('Select URLs to Import'), title: const Text('Select URLs to Import'),
content: Column(children: [ content: Column(children: [
...urlSelections.keys.map((url) { ...urlWithDescriptionSelections.keys.map((urlWithD) {
return Row(children: [ return Row(children: [
Checkbox( Checkbox(
value: urlSelections[url], value: urlWithDescriptionSelections[urlWithD],
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
urlSelections[url] = value ?? false; urlWithDescriptionSelections[urlWithD] = value ?? false;
}); });
}), }),
const SizedBox( const SizedBox(
width: 8, width: 8,
), ),
Expanded( Expanded(
child: Text( child: Column(
Uri.parse(url).path.substring(1), crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 8,
),
GestureDetector(
onTap: () {
launchUrlString(urlWithD.key,
mode: LaunchMode.externalApplication);
},
child: Text(
Uri.parse(urlWithD.key).path.substring(1),
style:
const TextStyle(decoration: TextDecoration.underline),
textAlign: TextAlign.start,
)),
Text(
urlWithD.value.length > 128
? '${urlWithD.value.substring(0, 128)}...'
: urlWithD.value,
style: const TextStyle(
fontStyle: FontStyle.italic, fontSize: 12),
),
const SizedBox(
height: 8,
)
],
)) ))
]); ]);
}) })
@@ -529,12 +567,13 @@ class _UrlSelectionModalState extends State<UrlSelectionModal> {
child: const Text('Cancel')), child: const Text('Cancel')),
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(urlSelections.keys Navigator.of(context).pop(urlWithDescriptionSelections.entries
.where((url) => urlSelections[url] ?? false) .where((entry) => entry.value)
.map((e) => e.key.key)
.toList()); .toList());
}, },
child: Text( child: Text(
'Import ${urlSelections.values.where((b) => b).length} URLs')) 'Import ${urlWithDescriptionSelections.values.where((b) => b).length} URLs'))
], ],
); );
} }

View File

@@ -159,7 +159,7 @@ class AppSource {
} }
bool canSearch = false; bool canSearch = false;
Future<List<String>> search(String query) { Future<Map<String, String>> search(String query) {
throw NotImplementedError(); throw NotImplementedError();
} }
} }