diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index 2a620960..6c81588e 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -275,14 +275,15 @@ class GitHub extends AppSource { } } - List> getReleaseAssetUrls(dynamic release) => + findReleaseAssetUrls(dynamic release) => (release['assets'] as List?)?.map((e) { var url = !e['name'].toString().toLowerCase().endsWith('.apk') ? (e['browser_download_url'] ?? e['url']) : (e['url'] ?? e['browser_download_url']); - return (e['name'] != null) && (url != null) + e['final_url'] = (e['name'] != null) && (url != null) ? MapEntry(e['name'] as String, url as String) : const MapEntry('', ''); + return e; }).toList() ?? []; @@ -293,7 +294,9 @@ class GitHub extends AppSource { ? DateTime.parse(rel['commit']['created']) : null; DateTime? getNewestAssetDateFromRelease(dynamic rel) { - var t = (rel['assets'] as List?) + var allAssets = rel['assets'] as List?; + var filteredAssets = rel['filteredAssets'] as List?; + var t = (filteredAssets ?? allAssets) ?.map((e) { return e?['updated_at'] != null ? DateTime.parse(e['updated_at']) @@ -387,18 +390,38 @@ class GitHub extends AppSource { .hasMatch(((releases[i]['body'] as String?) ?? '').trim())) { continue; } - var allAssetUrls = getReleaseAssetUrls(releases[i]); - List> apkUrls = allAssetUrls - .where((element) => element.key.toLowerCase().endsWith('.apk')) + var allAssetsWithUrls = findReleaseAssetUrls(releases[i]); + List> allAssetUrls = allAssetsWithUrls + .map((e) => e['final_url'] as MapEntry) + .toList(); + var apkAssetsWithUrls = allAssetsWithUrls + .where((element) => + (element['final_url'] as MapEntry) + .key + .toLowerCase() + .endsWith('.apk')) .toList(); - apkUrls = filterApks(apkUrls, additionalSettings['apkFilterRegEx'], + var filteredApkUrls = filterApks( + apkAssetsWithUrls + .map((e) => e['final_url'] as MapEntry) + .toList(), + additionalSettings['apkFilterRegEx'], additionalSettings['invertAPKFilter']); - if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) { + var filteredApks = apkAssetsWithUrls + .where((e) => filteredApkUrls + .where((e2) => + e2.key == (e['final_url'] as MapEntry).key) + .isNotEmpty) + .toList(); + + if (apkAssetsWithUrls.isEmpty && + additionalSettings['trackOnly'] != true) { continue; } targetRelease = releases[i]; - targetRelease['apkUrls'] = apkUrls; + targetRelease['apkUrls'] = filteredApkUrls; + targetRelease['filteredAssets'] = filteredApks; targetRelease['version'] = additionalSettings['releaseTitleAsVersion'] == true ? nameToFilter @@ -420,6 +443,7 @@ class GitHub extends AppSource { throw NoReleasesError(); } String? version = targetRelease['version']; + DateTime? releaseDate = getReleaseDateFromRelease( targetRelease, useLatestAssetDateAsReleaseDate); if (version == null) { diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index 505a98db..42796774 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -838,30 +838,6 @@ class AppsPageState extends State { Navigator.of(context).pop(); } - resetSelectedAppsInstallStatuses() async { - try { - var values = await showDialog( - context: context, - builder: (BuildContext ctx) { - return GeneratedFormModal( - title: tr('resetInstallStatusForSelectedAppsQuestion'), - items: const [], - initValid: true, - message: tr('installStatusOfXWillBeResetExplanation', - args: [plural('apps', selectedAppIds.length)]), - ); - }); - if (values != null) { - appsProvider.saveApps(selectedApps.map((e) { - e.installedVersion = null; - return e; - }).toList()); - } - } finally { - Navigator.of(context).pop(); - } - } - showMoreOptionsDialog() { return showDialog( context: context, diff --git a/lib/pages/home.dart b/lib/pages/home.dart index e9f02fe4..337c703e 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -130,13 +130,18 @@ class _HomePageState extends State { // Check initial link if app was in cold state (terminated) final appLink = await _appLinks.getInitialLink(); + var initLinked = false; if (appLink != null) { await interpretLink(appLink); + initLinked = true; } - // Handle link when app is in warm state (front or background) _linkSubscription = _appLinks.uriLinkStream.listen((uri) async { - await interpretLink(uri); + if (!initLinked) { + await interpretLink(uri); + } else { + initLinked = false; + } }); } diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 51d0b9fd..a28a8a93 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -19,6 +19,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/io_client.dart'; +import 'package:obtainium/app_sources/directAPKLink.dart'; +import 'package:obtainium/app_sources/html.dart'; import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/components/generated_form_modal.dart'; import 'package:obtainium/custom_errors.dart'; @@ -1159,17 +1161,25 @@ class AppsProvider with ChangeNotifier { if (app?.app == null) { return false; } + var source = SourceProvider() + .getSource(app!.app.url, overrideSource: app.app.overrideSource); var naiveStandardVersionDetection = - app!.app.additionalSettings['naiveStandardVersionDetection'] == true || - SourceProvider() - .getSource(app.app.url, overrideSource: app.app.overrideSource) - .naiveStandardVersionDetection; + app.app.additionalSettings['naiveStandardVersionDetection'] == true || + source.naiveStandardVersionDetection; String? realInstalledVersion = app.app.additionalSettings['useVersionCodeAsOSVersion'] == true ? app.installedInfo?.versionCode.toString() : app.installedInfo?.versionName; + bool isHTMLWithNoVersionDetection = + (source.runtimeType == HTML().runtimeType && + (app.app.additionalSettings['versionExtractionRegEx'] as String?) + ?.isNotEmpty != + true); + bool isDirectAPKLink = source.runtimeType == DirectAPKLink().runtimeType; return app.app.additionalSettings['trackOnly'] != true && app.app.additionalSettings['releaseDateAsVersion'] != true && + !isHTMLWithNoVersionDetection && + !isDirectAPKLink && realInstalledVersion != null && app.app.installedVersion != null && (reconcileVersionDifferences( @@ -1240,6 +1250,7 @@ class AppsProvider with ChangeNotifier { !isVersionDetectionPossible( AppInMemory(app, null, installedInfo, null))) { app.additionalSettings['versionDetection'] = false; + app.installedVersion = app.latestVersion; logs.add('Could not reconcile version formats for: ${app.id}'); modded = true; } diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 2b2ce683..e33961ba 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -151,10 +151,6 @@ appJSONCompatibilityModifiers(Map json) { additionalSettings['autoApkFilterByArch'] = false; } if (source.runtimeType == HTML().runtimeType) { - // HTML 'fixed URL' support should be disabled if it previously did not exist - if (originalAdditionalSettings['supportFixedAPKURL'] == null) { - additionalSettings['supportFixedAPKURL'] = false; - } // HTML key rename if (originalAdditionalSettings['sortByFileNamesNotLinks'] != null) { additionalSettings['sortByLastLinkSegment'] = diff --git a/pubspec.yaml b/pubspec.yaml index ba18f7b5..ba5358ce 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: 1.1.34+2291 +version: 1.1.35+2292 environment: sdk: '>=3.0.0 <4.0.0'