diff --git a/lib/app_sources/apkcombo.dart b/lib/app_sources/apkcombo.dart index 6c5dfa6..16e21c5 100644 --- a/lib/app_sources/apkcombo.dart +++ b/lib/app_sources/apkcombo.dart @@ -1,6 +1,5 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:html/parser.dart'; -import 'package:http/http.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; @@ -85,7 +84,6 @@ class APKCombo extends AppSource { Map additionalSettings, ) async { String appId = tryInferringAppId(standardUrl)!; - String host = Uri.parse(standardUrl).host; var preres = await sourceRequest(standardUrl); if (preres.statusCode != 200) { throw getObtainiumHttpError(preres); diff --git a/lib/app_sources/apkpure.dart b/lib/app_sources/apkpure.dart index 1ab017d..20028a4 100644 --- a/lib/app_sources/apkpure.dart +++ b/lib/app_sources/apkpure.dart @@ -1,6 +1,5 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:html/parser.dart'; -import 'package:http/http.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; diff --git a/lib/app_sources/codeberg.dart b/lib/app_sources/codeberg.dart index d50332d..f94cdb9 100644 --- a/lib/app_sources/codeberg.dart +++ b/lib/app_sources/codeberg.dart @@ -1,6 +1,4 @@ -import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; -import 'package:http/http.dart'; import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/custom_errors.dart'; @@ -9,7 +7,6 @@ import 'package:obtainium/providers/source_provider.dart'; class Codeberg extends AppSource { Codeberg() { host = 'codeberg.org'; - overrideEligible = true; additionalSourceSpecificSettingFormItems = []; @@ -58,10 +55,10 @@ class Codeberg extends AppSource { String standardUrl, Map additionalSettings, ) async { - return gh.getLatestAPKDetailsCommon( - 'https://$host/api/v1/repos${standardUrl.substring('https://$host'.length)}/releases?per_page=100', - standardUrl, - additionalSettings); + return await gh.getLatestAPKDetailsCommon2(standardUrl, additionalSettings, + (bool useTagUrl) async { + return 'https://$host/api/v1/repos${standardUrl.substring('https://$host'.length)}/${useTagUrl ? 'tags' : 'releases'}?per_page=100'; + }, null); } AppNames getAppNames(String standardUrl) { diff --git a/lib/app_sources/fdroidrepo.dart b/lib/app_sources/fdroidrepo.dart index 184e139..9bf2931 100644 --- a/lib/app_sources/fdroidrepo.dart +++ b/lib/app_sources/fdroidrepo.dart @@ -1,6 +1,5 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:html/parser.dart'; -import 'package:http/http.dart'; import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; @@ -8,7 +7,6 @@ import 'package:obtainium/providers/source_provider.dart'; class FDroidRepo extends AppSource { FDroidRepo() { name = tr('fdroidThirdPartyRepo'); - overrideEligible = true; additionalSourceAppSpecificSettingFormItems = [ [ diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index c314d26..a34bda2 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -13,7 +13,6 @@ import 'package:url_launcher/url_launcher_string.dart'; class GitHub extends AppSource { GitHub() { host = 'github.com'; - overrideEligible = true; additionalSourceSpecificSettingFormItems = [ GeneratedFormTextField('github-creds', @@ -143,15 +142,17 @@ class GitHub extends AppSource { } else if (b == null) { return 1; } else { - var stdFormats = findStandardFormatsForVersion(a['tag_name'], true) - .intersection(findStandardFormatsForVersion(b['tag_name'], true)); + var nameA = a['tag_name'] ?? a['name']; + var nameB = b['tag_name'] ?? b['name']; + var stdFormats = findStandardFormatsForVersion(nameA, true) + .intersection(findStandardFormatsForVersion(nameB, true)); if (stdFormats.isNotEmpty) { var reg = RegExp(stdFormats.first); - var matchA = reg.firstMatch(a['tag_name']); - var matchB = reg.firstMatch(b['tag_name']); + var matchA = reg.firstMatch(nameA); + var matchB = reg.firstMatch(nameB); return compareAlphaNumeric( - (a['tag_name'] as String).substring(matchA!.start, matchA.end), - (b['tag_name'] as String).substring(matchB!.start, matchB.end)); + (nameA as String).substring(matchA!.start, matchA.end), + (nameB as String).substring(matchB!.start, matchB.end)); } else { return getReleaseDateFromRelease(a)! .compareTo(getReleaseDateFromRelease(b)!); @@ -191,7 +192,7 @@ class GitHub extends AppSource { if (targetRelease == null) { throw NoReleasesError(); } - String? version = targetRelease['tag_name']; + String? version = targetRelease['tag_name'] ?? targetRelease['name']; DateTime? releaseDate = getReleaseDateFromRelease(targetRelease); if (version == null) { throw NoVersionError(); @@ -211,15 +212,35 @@ class GitHub extends AppSource { } } + getLatestAPKDetailsCommon2( + String standardUrl, + Map additionalSettings, + Future Function(bool) reqUrlGenerator, + dynamic Function(Response)? onHttpErrorCode) async { + try { + return await getLatestAPKDetailsCommon( + await reqUrlGenerator(false), standardUrl, additionalSettings, + onHttpErrorCode: onHttpErrorCode); + } catch (err) { + if (err is NoReleasesError && additionalSettings['trackOnly'] == true) { + return await getLatestAPKDetailsCommon( + await reqUrlGenerator(true), standardUrl, additionalSettings, + onHttpErrorCode: onHttpErrorCode); + } else { + rethrow; + } + } + } + @override Future getLatestAPKDetails( String standardUrl, Map additionalSettings, ) async { - return getLatestAPKDetailsCommon( - 'https://${await getCredentialPrefixIfAny()}api.$host/repos${standardUrl.substring('https://$host'.length)}/releases?per_page=100', - standardUrl, - additionalSettings, onHttpErrorCode: (Response res) { + return await getLatestAPKDetailsCommon2(standardUrl, additionalSettings, + (bool useTagUrl) async { + return 'https://${await getCredentialPrefixIfAny()}api.$host/repos${standardUrl.substring('https://$host'.length)}/${useTagUrl ? 'tags' : 'releases'}?per_page=100'; + }, (Response res) { rateLimitErrorCheck(res); }); } diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index ae65875..c6d8a63 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -14,7 +14,6 @@ import 'package:url_launcher/url_launcher_string.dart'; class GitLab extends AppSource { GitLab() { host = 'gitlab.com'; - overrideEligible = true; canSearch = true; additionalSourceSpecificSettingFormItems = [ @@ -83,12 +82,12 @@ class GitLab extends AppSource { } var json = jsonDecode(res.body) as List; Map> results = {}; - json.forEach((element) { + for (var element in json) { results['https://$host/${element['path_with_namespace']}'] = [ element['name_with_namespace'], element['description'] ?? tr('noDescription') ]; - }); + } return results; } diff --git a/lib/app_sources/html.dart b/lib/app_sources/html.dart index c6ec9e2..7b69ade 100644 --- a/lib/app_sources/html.dart +++ b/lib/app_sources/html.dart @@ -85,10 +85,6 @@ bool _isNumeric(String s) { } class HTML extends AppSource { - HTML() { - overrideEligible = true; - } - @override // TODO: implement requestHeaders choice, hardcoded for now Map? get requestHeaders => { diff --git a/lib/app_sources/izzyondroid.dart b/lib/app_sources/izzyondroid.dart index cdab17a..1773558 100644 --- a/lib/app_sources/izzyondroid.dart +++ b/lib/app_sources/izzyondroid.dart @@ -1,4 +1,3 @@ -import 'package:http/http.dart'; import 'package:obtainium/app_sources/fdroid.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; diff --git a/lib/app_sources/jenkins.dart b/lib/app_sources/jenkins.dart index 804b3fb..2aa8853 100644 --- a/lib/app_sources/jenkins.dart +++ b/lib/app_sources/jenkins.dart @@ -6,11 +6,9 @@ import 'package:obtainium/providers/source_provider.dart'; class Jenkins extends AppSource { Jenkins() { - overrideEligible = true; overrideVersionDetectionFormDefault('releaseDateAsVersion', true); } - @override String trimJobUrl(String url) { RegExp standardUrlRegEx = RegExp('.*/job/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url); diff --git a/lib/app_sources/sourceforge.dart b/lib/app_sources/sourceforge.dart index 794eef1..3253926 100644 --- a/lib/app_sources/sourceforge.dart +++ b/lib/app_sources/sourceforge.dart @@ -6,7 +6,6 @@ import 'package:obtainium/providers/source_provider.dart'; class SourceForge extends AppSource { SourceForge() { host = 'sourceforge.net'; - overrideEligible = true; } @override diff --git a/lib/app_sources/sourcehut.dart b/lib/app_sources/sourcehut.dart index b85758f..d74fd7c 100644 --- a/lib/app_sources/sourcehut.dart +++ b/lib/app_sources/sourcehut.dart @@ -1,6 +1,5 @@ import 'package:html/parser.dart'; import 'package:http/http.dart'; -import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/app_sources/html.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; @@ -10,7 +9,6 @@ import 'package:easy_localization/easy_localization.dart'; class SourceHut extends AppSource { SourceHut() { host = 'git.sr.ht'; - overrideEligible = true; additionalSourceAppSpecificSettingFormItems = [ [ @@ -58,11 +56,19 @@ class SourceHut extends AppSource { throw NoVersionError(); } String? releaseDateString = entry.querySelector('pubDate')?.innerHtml; - var link = entry.querySelector('link'); String releasePage = '$standardUrl/refs/$version'; - DateTime? releaseDate = releaseDateString != null - ? DateFormat('EEE, dd MMM yyyy HH:mm:ss Z').parse(releaseDateString) - : null; + DateTime? releaseDate; + try { + releaseDate = releaseDateString != null + ? DateFormat('E, dd MMM yyyy HH:mm:ss Z').parse(releaseDateString) + : null; + releaseDate = releaseDateString != null + ? DateFormat('EEE, dd MMM yyyy HH:mm:ss Z') + .parse(releaseDateString) + : null; + } catch (e) { + // ignore + } var res2 = await sourceRequest(releasePage); List> apkUrls = []; if (res2.statusCode == 200) { diff --git a/lib/app_sources/vlc.dart b/lib/app_sources/vlc.dart index 06ad878..c531f26 100644 --- a/lib/app_sources/vlc.dart +++ b/lib/app_sources/vlc.dart @@ -1,6 +1,5 @@ import 'package:html/parser.dart'; import 'package:http/http.dart'; -import 'package:obtainium/app_sources/html.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; diff --git a/lib/main.dart b/lib/main.dart index 98f12d9..089c1fb 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.3'; +const String currentVersion = '0.13.4'; const String currentReleaseTag = 'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index ac85b10..c439f30 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -321,10 +321,8 @@ class _AddAppPageState extends State { 'overrideSource', defaultValue: HTML().runtimeType.toString(), [ - ...sourceProvider.sources - .where((s) => s.overrideEligible) - .map((s) => - MapEntry(s.runtimeType.toString(), s.name)) + ...sourceProvider.sources.map( + (s) => MapEntry(s.runtimeType.toString(), s.name)) ], label: tr('overrideSource')) ] diff --git a/lib/pages/app.dart b/lib/pages/app.dart index b7585c8..3e2e993 100644 --- a/lib/pages/app.dart +++ b/lib/pages/app.dart @@ -32,6 +32,7 @@ class _AppPageState extends State { getUpdate(String id) { appsProvider.checkUpdate(id).catchError((e) { showError(e, context); + return null; }); } diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index 37fa60c..c06e3fe 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -71,6 +71,7 @@ class AppsPageState extends State { }); return appsProvider.checkUpdates().catchError((e) { showError(e, context); + return []; }).whenComplete(() { setState(() { refreshingSince = null; @@ -379,6 +380,7 @@ class AppsPageState extends State { [listedApps[appIndex].app.id], globalNavigatorKey.currentContext).catchError((e) { showError(e, context); + return []; }); }, icon: Icon( @@ -441,37 +443,35 @@ class AppsPageState extends State { width: 10, ) : const SizedBox.shrink(), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Row(mainAxisSize: MainAxisSize.min, children: [ - Container( - constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).size.width / 4), - child: Text( - getVersionText(index), - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.end, - )), - ]), - Row( - mainAxisSize: MainAxisSize.min, + GestureDetector( + onTap: showChangesFn, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, children: [ - GestureDetector( - onTap: showChangesFn, - child: Text( + Row(mainAxisSize: MainAxisSize.min, children: [ + Container( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width / 4), + child: Text(getVersionText(index), + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.end)), + ]), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( getChangesButtonString(index, showChangesFn != null), style: TextStyle( fontStyle: FontStyle.italic, decoration: showChangesFn != null ? TextDecoration.underline : TextDecoration.none), - )) + ) + ], + ), ], - ), - ], - ) + )) ], ); @@ -540,15 +540,20 @@ class AppsPageState extends State { : FontWeight.normal)), trailing: listedApps[index].downloadProgress != null ? SizedBox( - width: 110, - child: Text(tr('percentProgress', args: [ + width: 90, + child: Text( listedApps[index].downloadProgress! >= 0 - ? listedApps[index] - .downloadProgress! - .toInt() - .toString() - : tr('pleaseWait') - ]))) + ? tr('percentProgress', args: [ + listedApps[index] + .downloadProgress! + .toInt() + .toString() + ]) + : tr('pleaseWait'), + textAlign: (listedApps[index].downloadProgress! >= 0) + ? TextAlign.start + : TextAlign.end, + )) : trailingRow, onTap: () { if (selectedAppIds.isNotEmpty) { @@ -681,6 +686,7 @@ class AppsPageState extends State { settingsProvider: settingsProvider) .catchError((e) { showError(e, context); + return []; }); } }); diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index 7a896c9..fd10f86 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -323,8 +323,8 @@ class _ImportExportPageState extends State { ], ), if (importInProgress) - Column( - children: const [ + const Column( + children: [ SizedBox( height: 14, ), diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index f498496..d980e3c 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -7,7 +7,6 @@ import 'package:device_info_plus/device_info_plus.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:html/dom.dart'; import 'package:http/http.dart'; -import 'package:obtainium/app_sources/apkcombo.dart'; import 'package:obtainium/app_sources/apkmirror.dart'; import 'package:obtainium/app_sources/apkpure.dart'; import 'package:obtainium/app_sources/codeberg.dart'; @@ -318,7 +317,6 @@ abstract class AppSource { late String name; bool enforceTrackOnly = false; bool changeLogIfAnyIsMarkDown = true; - bool overrideEligible = false; AppSource() { name = runtimeType.toString(); diff --git a/pubspec.yaml b/pubspec.yaml index 59ae74a..12cdeee 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.3+167 # When changing this, update the tag in main() accordingly +version: 0.13.4+168 # When changing this, update the tag in main() accordingly environment: sdk: '>=2.18.2 <3.0.0'