diff --git a/assets/translations/bs.json b/assets/translations/bs.json index 38e2b0d..b0296f6 100644 --- a/assets/translations/bs.json +++ b/assets/translations/bs.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Provjerite ima li novosti pri otvaranju stranice s detaljima aplikacije", "disablePageTransitions": "Ugasite animaciju prijelaza stranice", "reversePageTransitions": "Reverzne animacije prijelaza stranice", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "Želite li ukloniti aplikaciju?", "other": "Želite li ukloniti aplikacije?" diff --git a/assets/translations/de.json b/assets/translations/de.json index bee3009..78911ce 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", "disablePageTransitions": "Disable page transition animations", "reversePageTransitions": "Reverse page transition animations", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "App entfernen?", "other": "Apps entfernen?" diff --git a/assets/translations/en.json b/assets/translations/en.json index 6937f3e..d6afd88 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", "disablePageTransitions": "Disable page transition animations", "reversePageTransitions": "Reverse page transition animations", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "Remove App?", "other": "Remove Apps?" diff --git a/assets/translations/es.json b/assets/translations/es.json index a572f71..ad5789e 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", "disablePageTransitions": "Disable page transition animations", "reversePageTransitions": "Reverse page transition animations", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "¿Eliminar Aplicación?", "other": "¿Eliminar Aplicaciones?" diff --git a/assets/translations/fa.json b/assets/translations/fa.json index 4db143d..eaa94a6 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", "disablePageTransitions": "Disable page transition animations", "reversePageTransitions": "Reverse page transition animations", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "برنامه حذف شود؟", "other": "برنامه ها حذف شوند؟" diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 8c014b4..6869452 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", "disablePageTransitions": "Disable page transition animations", "reversePageTransitions": "Reverse page transition animations", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "Supprimer l'application ?", "other": "Supprimer les applications ?" diff --git a/assets/translations/hu.json b/assets/translations/hu.json index 32fd821..7a9b1dd 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -238,6 +238,7 @@ "checkUpdateOnDetailPage": "Frissítések keresése az app részleteit tartalmazó oldal megnyitásakor", "disablePageTransitions": "Disable page transition animations", "reversePageTransitions": "Reverse page transition animations", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "Eltávolítja az alkalmazást?", "other": "Eltávolítja az alkalmazást?" diff --git a/assets/translations/it.json b/assets/translations/it.json index 057d88f..064382e 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", "disablePageTransitions": "Disable page transition animations", "reversePageTransitions": "Reverse page transition animations", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "Rimuovere l'app?", "other": "Rimuovere le app?" diff --git a/assets/translations/ja.json b/assets/translations/ja.json index b5532f3..bf70542 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "アプリの詳細ページを開く際にアップデートを確認する", "disablePageTransitions": "ページ遷移アニメーションを無効化する", "reversePageTransitions": "ページ遷移アニメーションを反転する", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "アプリを削除しますか?", "other": "アプリを削除しますか?" diff --git a/assets/translations/pl.json b/assets/translations/pl.json index e475cc0..755db7e 100644 --- a/assets/translations/pl.json +++ b/assets/translations/pl.json @@ -243,6 +243,7 @@ "checkUpdateOnDetailPage": "Sprawdzaj aktualizacje podczas otwierania strony szczegółów aplikacji", "disablePageTransitions": "Wyłącz animacje przejścia między stronami", "reversePageTransitions": "Odwróć animacje przejścia pomiędzy stronami", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "Usunąć aplikację?", "other": "Usunąć aplikacje?" diff --git a/assets/translations/ru.json b/assets/translations/ru.json index aa3d2eb..4b90d63 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Проверять наличие обновлений при открытии страницы представления приложения", "disablePageTransitions": "Отключить анимацию перехода между страницами", "reversePageTransitions": "Реверс анимации перехода между страницами", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "Удалить приложение?", "other": "Удалить приложения?" diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 2904972..55763dd 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -239,6 +239,7 @@ "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", "disablePageTransitions": "Disable page transition animations", "reversePageTransitions": "Reverse page transition animations", + "minStarCount": "Minimum Star Count", "removeAppQuestion": { "one": "是否删除应用?", "other": "是否删除应用?" diff --git a/lib/app_sources/codeberg.dart b/lib/app_sources/codeberg.dart index f94cdb9..669e0d9 100644 --- a/lib/app_sources/codeberg.dart +++ b/lib/app_sources/codeberg.dart @@ -5,6 +5,7 @@ import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; class Codeberg extends AppSource { + GitHub gh = GitHub(); Codeberg() { host = 'codeberg.org'; @@ -32,10 +33,9 @@ class Codeberg extends AppSource { ]; canSearch = true; + searchQuerySettingFormItems = gh.searchQuerySettingFormItems; } - var gh = GitHub(); - @override String sourceSpecificStandardizeURL(String url) { RegExp standardUrlRegEx = RegExp('^https?://$host/[^/]+/[^/]+'); @@ -68,10 +68,12 @@ class Codeberg extends AppSource { } @override - Future>> search(String query) async { + Future>> search(String query, + {Map querySettings = const {}}) async { return gh.searchCommon( query, 'https://$host/api/v1/repos/search?q=${Uri.encodeQueryComponent(query)}&limit=100', - 'data'); + 'data', + querySettings: querySettings); } } diff --git a/lib/app_sources/fdroid.dart b/lib/app_sources/fdroid.dart index 0602f6d..2f96fe7 100644 --- a/lib/app_sources/fdroid.dart +++ b/lib/app_sources/fdroid.dart @@ -72,7 +72,8 @@ class FDroid extends AppSource { } @override - Future>> search(String query) async { + Future>> search(String query, + {Map querySettings = const {}}) async { Response res = await sourceRequest( 'https://search.$host/?q=${Uri.encodeQueryComponent(query)}'); if (res.statusCode == 200) { diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index 8cb08e2..0f74c47 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -79,6 +79,21 @@ class GitHub extends AppSource { ]; canSearch = true; + searchQuerySettingFormItems = [ + GeneratedFormTextField('minStarCount', + label: tr('minStarCount'), + defaultValue: '0', + additionalValidators: [ + (value) { + try { + int.parse(value ?? '0'); + } catch (e) { + return tr('invalidInput'); + } + return null; + } + ]) + ]; } @override @@ -211,8 +226,8 @@ class GitHub extends AppSource { (nameA as String).substring(matchA!.start, matchA.end), (nameB as String).substring(matchB!.start, matchB.end)); } else { - return getReleaseDateFromRelease(a)! - .compareTo(getReleaseDateFromRelease(b)!); + return (getReleaseDateFromRelease(a) ?? DateTime(1)) + .compareTo(getReleaseDateFromRelease(b) ?? DateTime(0)); } } }); @@ -310,20 +325,26 @@ class GitHub extends AppSource { Future>> searchCommon( String query, String requestUrl, String rootProp, - {Function(Response)? onHttpErrorCode}) async { + {Function(Response)? onHttpErrorCode, + Map querySettings = const {}}) async { Response res = await sourceRequest(requestUrl); if (res.statusCode == 200) { + int minStarCount = querySettings['minStarCount'] != null + ? int.parse(querySettings['minStarCount']) + : 0; Map> urlsWithDescriptions = {}; for (var e in (jsonDecode(res.body)[rootProp] as List)) { - urlsWithDescriptions.addAll({ - e['html_url'] as String: [ - e['full_name'] as String, - ((e['archived'] == true ? '[ARCHIVED] ' : '') + - (e['description'] != null - ? e['description'] as String - : tr('noDescription'))) - ] - }); + if ((e['stargazers_count'] ?? e['stars_count'] ?? 0) >= minStarCount) { + urlsWithDescriptions.addAll({ + e['html_url'] as String: [ + e['full_name'] as String, + ((e['archived'] == true ? '[ARCHIVED] ' : '') + + (e['description'] != null + ? e['description'] as String + : tr('noDescription'))) + ] + }); + } } return urlsWithDescriptions; } else { @@ -335,13 +356,14 @@ class GitHub extends AppSource { } @override - Future>> search(String query) async { + Future>> search(String query, + {Map querySettings = const {}}) async { return searchCommon( query, '${await getAPIHost()}/search/repositories?q=${Uri.encodeQueryComponent(query)}&per_page=100', 'items', onHttpErrorCode: (Response res) { rateLimitErrorCheck(res); - }); + }, querySettings: querySettings); } rateLimitErrorCheck(Response res) { diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index 574e814..ec2fd94 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -69,7 +69,8 @@ class GitLab extends AppSource { } @override - Future>> search(String query) async { + Future>> search(String query, + {Map querySettings = const {}}) async { String? PAT = await getPATIfAny(); if (PAT == null) { throw CredsNeededError(name); diff --git a/lib/custom_errors.dart b/lib/custom_errors.dart index 5d0bb20..6343c87 100644 --- a/lib/custom_errors.dart +++ b/lib/custom_errors.dart @@ -1,6 +1,7 @@ import 'package:android_package_installer/android_package_installer.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:obtainium/providers/logs_provider.dart'; import 'package:provider/provider.dart'; @@ -101,7 +102,14 @@ showError(dynamic e, BuildContext context) { title: Text(e is MultiAppMultiError ? tr('someErrors') : tr('unexpectedError')), - content: Text(e.toString()), + content: GestureDetector( + onLongPress: () { + Clipboard.setData(ClipboardData(text: e.toString())); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(tr('copiedToClipboard')), + )); + }, + child: Text(e.toString())), actions: [ TextButton( onPressed: () { diff --git a/lib/main.dart b/lib/main.dart index 609f9d9..2b0d098 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,7 +21,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart'; // ignore: implementation_imports import 'package:easy_localization/src/localization.dart'; -const String currentVersion = '0.13.18'; +const String currentVersion = '0.13.19'; const String currentReleaseTag = 'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index fd10f86..e2ebdf9 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -182,7 +182,8 @@ class _ImportExportPageState extends State { [ GeneratedFormTextField('searchQuery', label: tr('searchQuery')) - ] + ], + ...source.searchQuerySettingFormItems.map((e) => [e]) ], ); }); @@ -191,8 +192,8 @@ class _ImportExportPageState extends State { setState(() { importInProgress = true; }); - var urlsWithDescriptions = - await source.search(values['searchQuery'] as String); + var urlsWithDescriptions = await source + .search(values['searchQuery'] as String, querySettings: values); if (urlsWithDescriptions.isNotEmpty) { var selectedUrls = // ignore: use_build_context_synchronously diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 80e6312..6cf8507 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -346,7 +346,7 @@ class AppsProvider with ChangeNotifier { // If 0 APKs installed, throw the first install error encountered try { var somethingInstalled = false; - var firstError = null; + Object? firstError; for (var file in dir.extracted .listSync(recursive: true, followLinks: false) .whereType()) { @@ -366,7 +366,7 @@ class AppsProvider with ChangeNotifier { } if (somethingInstalled) { dir.file.delete(recursive: true); - } else if (firstError) { + } else if (firstError != null) { throw firstError; } } finally { diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 6917ba5..f71c238 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -436,7 +436,9 @@ abstract class AppSource { } bool canSearch = false; - Future>> search(String query) { + List searchQuerySettingFormItems = []; + Future>> search(String query, + {Map querySettings = const {}}) { throw NotImplementedError(); } diff --git a/pubspec.lock b/pubspec.lock index 003eae3..e80522b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -243,10 +243,10 @@ packages: dependency: "direct main" description: name: flutter_fgbg - sha256: d37511eef6afb7e2e3f2278ec6498bb12c650ed517c81bcd09452d910e8b9174 + sha256: "08c4d2fd229e3df26083d5aecc3dea9ff4f2d188f8cd57aaf2b3f047bd08a047" url: "https://pub.dev" source: hosted - version: "0.2.2" + version: "0.3.0" flutter_launcher_icons: dependency: "direct dev" description: @@ -538,10 +538,10 @@ packages: dependency: transitive description: name: permission_handler_android - sha256: c0c9754479a4c4b1c1f3862ddc11930c9b3f03bef2816bb4ea6eed1e13551d6f + sha256: "2ffaf52a21f64ac9b35fe7369bb9533edbd4f698e5604db8645b1064ff4cf221" url: "https://pub.dev" source: hosted - version: "10.3.2" + version: "10.3.3" permission_handler_apple: dependency: transitive description: @@ -586,10 +586,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pointycastle: dependency: transitive description: @@ -783,10 +783,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03" + sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af" url: "https://pub.dev" source: hosted - version: "6.0.36" + version: "6.0.37" url_launcher_ios: dependency: transitive description: @@ -863,10 +863,10 @@ packages: dependency: transitive description: name: webview_flutter_android - sha256: "27ad6a99c4b2d5e1ffd2b993a10f738b6b4979f139b4d64c34ac511595fcd748" + sha256: "8587d0b4991bd0f223f4b4957101c2c7449f905601571315f4967072498dd3fb" url: "https://pub.dev" source: hosted - version: "3.9.0" + version: "3.9.1" webview_flutter_platform_interface: dependency: transitive description: @@ -879,10 +879,10 @@ packages: dependency: transitive description: name: webview_flutter_wkwebview - sha256: "369fdf6160944a7db660ff15fa048c2bd681b09557907beaef1f95e8557d21dc" + sha256: "3e36a8f564809cb7c257ff4278502b185e2191349df0ddee98837f91805c74b8" url: "https://pub.dev" source: hosted - version: "3.7.0" + version: "3.7.1" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9f785ad..0ab3397 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.13.18+182 # When changing this, update the tag in main() accordingly +version: 0.13.19+183 # When changing this, update the tag in main() accordingly environment: sdk: '>=2.18.2 <3.0.0' @@ -37,7 +37,7 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.5 path_provider: ^2.0.11 - flutter_fgbg: ^0.2.0 # Try removing reliance on this + flutter_fgbg: ^0.3.0 # Try removing reliance on this flutter_local_notifications: ^15.1.0+1 provider: ^6.0.3 http: ^1.0.0