mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-08-02 05:40:15 +02:00
Added descriptions to search results
This commit is contained in:
@@ -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(
|
||||||
|
@@ -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'))
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user