From 9c46e3f88c98edcb2dc1275bd43e158c29f5f074 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Wed, 22 May 2024 19:35:51 -0400 Subject: [PATCH 1/8] Attempt to improve app load time Slight icon opacity tweak (#1637) --- lib/pages/apps.dart | 10 ++++- lib/providers/apps_provider.dart | 73 ++++++++++++++++++++------------ 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index d55a393..64d8465 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -354,7 +354,11 @@ class AppsPageState extends State { SliverFillRemaining( child: Center( child: Text( - appsProvider.apps.isEmpty ? tr('noApps') : tr('noAppsForFilter'), + appsProvider.apps.isEmpty + ? appsProvider.loadingApps + ? tr('pleaseWait') + : tr('noApps') + : tr('noAppsForFilter'), style: Theme.of(context).textTheme.headlineMedium, textAlign: TextAlign.center, ))), @@ -419,7 +423,9 @@ class AppsPageState extends State { child: Image( image: const AssetImage( 'assets/graphics/icon_small.png'), - color: Colors.white.withOpacity(0.3), + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.4) + : Colors.white.withOpacity(0.3), colorBlendMode: BlendMode.modulate, gaplessPlayback: true, ), diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 6542f7c..6674557 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -329,6 +329,10 @@ Future> getHeaders(String url, return returnHeaders; } +Future> getAllInstalledInfo() async { + return await pm.getInstalledPackages() ?? []; +} + Future getInstalledInfo(String? packageName, {bool printErr = true}) async { if (packageName != null) { @@ -1160,8 +1164,9 @@ class AppsProvider with ChangeNotifier { : false; } - Future updateInstallStatusInMemory(AppInMemory app) async { - apps[app.app.id]?.installedInfo = await getInstalledInfo(app.app.id); + Future updateInstallStatusInMemory( + AppInMemory app, PackageInfo? installedInfo) async { + apps[app.app.id]?.installedInfo = installedInfo; apps[app.app.id]?.icon = await apps[app.app.id]?.installedInfo?.applicationInfo?.getAppIcon(); apps[app.app.id]?.app.name = await (apps[app.app.id] @@ -1179,6 +1184,8 @@ class AppsProvider with ChangeNotifier { notifyListeners(); var sp = SourceProvider(); List> errors = []; + var installedAppsData = await getAllInstalledInfo(); + List removedAppIds = []; await Future.wait((await getAppsDir()) // Parse Apps from JSON .listSync() .map((item) async { @@ -1199,43 +1206,57 @@ class AppsProvider with ChangeNotifier { } } if (app != null) { + // Save the app to the in-memory list without grabbing any OS info first + apps.update( + app.id, + (value) => AppInMemory( + app!, value.downloadProgress, value.installedInfo, value.icon), + ifAbsent: () => AppInMemory(app!, null, null, null)); + notifyListeners(); try { + // Try getting the app's source to ensure no invalid apps get loaded sp.getSource(app.url, overrideSource: app.overrideSource); + // If the app is installed, grab its OS data and reconcile install statuses + PackageInfo? installedInfo; + try { + installedInfo = + installedAppsData.firstWhere((i) => i.packageName == app!.id); + } catch (e) { + // If the app isn't installed the above throws an error + } + // Reconcile differences between the installed and recorded install info + var moddedApp = + getCorrectedInstallStatusAppIfPossible(app, installedInfo); + if (moddedApp != null) { + app = moddedApp; + // Note the app ID if it was uninstalled externally + if (moddedApp.installedVersion == null) { + removedAppIds.add(moddedApp.id); + } + } + var icon = await installedInfo?.applicationInfo?.getAppIcon(); + app.name = + await (installedInfo?.applicationInfo?.getAppLabel()) ?? app.name; + // Update the app in memory with install info and corrections apps.update( app.id, - (value) => AppInMemory(app!, value.downloadProgress, - value.installedInfo, value.icon), - ifAbsent: () => AppInMemory(app!, null, null, null)); + (value) => AppInMemory( + app!, value.downloadProgress, installedInfo, icon), + ifAbsent: () => AppInMemory(app!, null, installedInfo, icon)); + notifyListeners(); } catch (e) { - errors.add([app.id, app.finalName, e.toString()]); + errors.add([app!.id, app.finalName, e.toString()]); } } })); - notifyListeners(); + if (errors.isNotEmpty) { removeApps(errors.map((e) => e[0]).toList()); NotificationsProvider().notify( AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList())); } - // Get install status and other OS info for each App (slow) - List modifiedApps = []; - await Future.wait(apps.values.map((app) async { - await updateInstallStatusInMemory(app); - var moddedApp = - getCorrectedInstallStatusAppIfPossible(app.app, app.installedInfo); - if (moddedApp != null) { - modifiedApps.add(moddedApp); - } - })); - notifyListeners(); - // Reconcile version differences - if (modifiedApps.isNotEmpty) { - await saveApps(modifiedApps, attemptToCorrectInstallStatus: false); - var removedAppIds = modifiedApps - .where((a) => a.installedVersion == null) - .map((e) => e.id) - .toList(); - // After reconciliation, delete externally uninstalled Apps if needed + // Delete externally uninstalled Apps if needed + if (removedAppIds.isNotEmpty) { if (removedAppIds.isNotEmpty) { if (settingsProvider.removeOnExternalUninstall) { await removeApps(removedAppIds); From de509737e6a8d7b7f62372b4a32e59225e00d175 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Wed, 22 May 2024 19:51:35 -0400 Subject: [PATCH 2/8] Include GitLab token in APK request (#1622) --- lib/app_sources/gitlab.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index 49f7246..7383f66 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -111,6 +111,14 @@ class GitLab extends AppSource { } } + @override + Future apkUrlPrefetchModifier(String apkUrl, String standardUrl, + Map additionalSettings) async { + String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {}); + String optionalAuth = (PAT != null) ? 'private_token=$PAT' : ''; + return '$apkUrl?$optionalAuth'; + } + @override Future getLatestAPKDetails( String standardUrl, From 06a079e4528759f9e3c13bc24eb8ccabf142dc14 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Thu, 23 May 2024 19:35:52 -0400 Subject: [PATCH 3/8] Attempt to improve load times again + link parsing bugfix (#1625) --- lib/providers/apps_provider.dart | 39 +++++++++++++++++++++++------- lib/providers/source_provider.dart | 13 +++++----- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 6674557..67e6f24 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -368,7 +368,10 @@ class AppsProvider with ChangeNotifier { foregroundStream = FGBGEvents.stream.asBroadcastStream(); foregroundSubscription = foregroundStream?.listen((event) async { isForeground = event == FGBGType.foreground; - if (isForeground) loadApps(); + if (isForeground) { + await loadApps(andUpdateSuperficialDetails: false); + updateAppsSuperficialDetails(); + } }); () async { await settingsProvider.initializeSettings(); @@ -384,7 +387,9 @@ class AppsProvider with ChangeNotifier { } if (!isBg) { // Load Apps into memory (in background processes, this is done later instead of in the constructor) - await loadApps(); + await loadApps(andUpdateSuperficialDetails: false); + // Update app names/icons asynchronously + updateAppsSuperficialDetails(); // Delete any partial APKs (if safe to do so) var cutoff = DateTime.now().subtract(const Duration(days: 7)); APKDir.listSync() @@ -1176,7 +1181,24 @@ class AppsProvider with ChangeNotifier { app.name; } - Future loadApps({String? singleId}) async { + Future updateAppsSuperficialDetails() async { + await Future.wait(apps.values.map((app) async { + var icon = await app.installedInfo?.applicationInfo?.getAppIcon(); + app.app.name = + await (app.installedInfo?.applicationInfo?.getAppLabel()) ?? + app.app.name; + // Update the app in memory with install info and corrections + apps.update( + app.app.id, + (value) => AppInMemory( + app.app, value.downloadProgress, app.installedInfo, icon), + ifAbsent: () => AppInMemory(app.app, null, app.installedInfo, icon)); + notifyListeners(); + })); + } + + Future loadApps( + {String? singleId, bool andUpdateSuperficialDetails = true}) async { while (loadingApps) { await Future.delayed(const Duration(microseconds: 1)); } @@ -1234,22 +1256,21 @@ class AppsProvider with ChangeNotifier { removedAppIds.add(moddedApp.id); } } - var icon = await installedInfo?.applicationInfo?.getAppIcon(); - app.name = - await (installedInfo?.applicationInfo?.getAppLabel()) ?? app.name; // Update the app in memory with install info and corrections apps.update( app.id, (value) => AppInMemory( - app!, value.downloadProgress, installedInfo, icon), - ifAbsent: () => AppInMemory(app!, null, installedInfo, icon)); + app!, value.downloadProgress, installedInfo, value.icon), + ifAbsent: () => AppInMemory(app!, null, installedInfo, null)); notifyListeners(); } catch (e) { errors.add([app!.id, app.finalName, e.toString()]); } } })); - + if (andUpdateSuperficialDetails) { + await updateAppsSuperficialDetails(); + } if (errors.isNotEmpty) { removeApps(errors.map((e) => e[0]).toList()); NotificationsProvider().notify( diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 20de673..73d9b46 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -354,11 +354,13 @@ preStandardizeUrl(String url) { url.toLowerCase().indexOf('https://') != 0) { url = 'https://$url'; } + var trailingSlash = Uri.tryParse(url)?.path.endsWith('/') ?? false; url = url - .split('/') - .where((e) => e.isNotEmpty) - .join('/') - .replaceFirst(':/', '://'); + .split('/') + .where((e) => e.isNotEmpty) + .join('/') + .replaceFirst(':/', '://') + + (trailingSlash ? '/' : ''); return url; } @@ -523,8 +525,7 @@ abstract class AppSource { [GeneratedFormTextField('appName', label: tr('appName'), required: false)], [ GeneratedFormSwitch('shizukuPretendToBeGooglePlay', - label: tr('shizukuPretendToBeGooglePlay'), - defaultValue: false) + label: tr('shizukuPretendToBeGooglePlay'), defaultValue: false) ], [ GeneratedFormSwitch('exemptFromBackgroundUpdates', From 7808bc5ccbb7ee69be43c0ef08e4db8e0a6a379f Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Thu, 23 May 2024 20:02:43 -0400 Subject: [PATCH 4/8] Improve loading time/stability (at the cost of icon flickering) --- lib/pages/app.dart | 32 +++++++++------ lib/pages/apps.dart | 56 ++++++++++++++------------ lib/providers/apps_provider.dart | 69 +++++++------------------------- 3 files changed, 66 insertions(+), 91 deletions(-) diff --git a/lib/pages/app.dart b/lib/pages/app.dart index ada2054..0039cbb 100644 --- a/lib/pages/app.dart +++ b/lib/pages/app.dart @@ -226,18 +226,26 @@ class _AppPageState extends State { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 20), - app?.icon != null - ? Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - GestureDetector( - child: Image.memory( - app!.icon!, - height: 150, - gaplessPlayback: true, - ), - onTap: () => pm.openApp(app.app.id), - ) - ]) - : Container(), + FutureBuilder( + future: app?.installedInfo?.applicationInfo?.getAppIcon(), + builder: (ctx, val) { + return val.data != null + ? Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: app == null + ? null + : () => pm.openApp(app.app.id), + child: Image.memory( + val.data!, + height: 150, + gaplessPlayback: true, + ), + ) + ]) + : Container(); + }), const SizedBox( height: 25, ), diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index 64d8465..8249940 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -406,31 +406,37 @@ class AppsPageState extends State { } getAppIcon(int appIndex) { - return listedApps[appIndex].icon != null - ? Image.memory( - listedApps[appIndex].icon!, - gaplessPlayback: true, - ) - : Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Transform( - alignment: Alignment.center, - transform: Matrix4.rotationZ(0.31), - child: Padding( - padding: const EdgeInsets.all(15), - child: Image( - image: const AssetImage( - 'assets/graphics/icon_small.png'), - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.4) - : Colors.white.withOpacity(0.3), - colorBlendMode: BlendMode.modulate, - gaplessPlayback: true, - ), - )), - ]); + return FutureBuilder( + future: + listedApps[appIndex].installedInfo?.applicationInfo?.getAppIcon(), + builder: (ctx, val) { + return val.data != null + ? Image.memory( + val.data!, + gaplessPlayback: true, + ) + : Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Transform( + alignment: Alignment.center, + transform: Matrix4.rotationZ(0.31), + child: Padding( + padding: const EdgeInsets.all(15), + child: Image( + image: const AssetImage( + 'assets/graphics/icon_small.png'), + color: Theme.of(context).brightness == + Brightness.dark + ? Colors.white.withOpacity(0.4) + : Colors.white.withOpacity(0.3), + colorBlendMode: BlendMode.modulate, + gaplessPlayback: true, + ), + )), + ]); + }); } getVersionText(int appIndex) { diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 67e6f24..1dc594d 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -42,11 +42,10 @@ class AppInMemory { late App app; double? downloadProgress; PackageInfo? installedInfo; - Uint8List? icon; - AppInMemory(this.app, this.downloadProgress, this.installedInfo, this.icon); + AppInMemory(this.app, this.downloadProgress, this.installedInfo); AppInMemory deepCopy() => - AppInMemory(app.deepCopy(), downloadProgress, installedInfo, icon); + AppInMemory(app.deepCopy(), downloadProgress, installedInfo); String get name => app.overrideName ?? app.finalName; } @@ -369,8 +368,7 @@ class AppsProvider with ChangeNotifier { foregroundSubscription = foregroundStream?.listen((event) async { isForeground = event == FGBGType.foreground; if (isForeground) { - await loadApps(andUpdateSuperficialDetails: false); - updateAppsSuperficialDetails(); + await loadApps(); } }); () async { @@ -387,9 +385,7 @@ class AppsProvider with ChangeNotifier { } if (!isBg) { // Load Apps into memory (in background processes, this is done later instead of in the constructor) - await loadApps(andUpdateSuperficialDetails: false); - // Update app names/icons asynchronously - updateAppsSuperficialDetails(); + await loadApps(); // Delete any partial APKs (if safe to do so) var cutoff = DateTime.now().subtract(const Duration(days: 7)); APKDir.listSync() @@ -1125,8 +1121,7 @@ class AppsProvider with ChangeNotifier { // FOURTH, DISABLE VERSION DETECTION IF ENABLED AND THE REPORTED/REAL INSTALLED VERSIONS ARE NOT STANDARDIZED if (installedInfo != null && versionDetectionIsStandard && - !isVersionDetectionPossible( - AppInMemory(app, null, installedInfo, null))) { + !isVersionDetectionPossible(AppInMemory(app, null, installedInfo))) { app.additionalSettings['versionDetection'] = false; logs.add('Could not reconcile version formats for: ${app.id}'); modded = true; @@ -1169,36 +1164,7 @@ class AppsProvider with ChangeNotifier { : false; } - Future updateInstallStatusInMemory( - AppInMemory app, PackageInfo? installedInfo) async { - apps[app.app.id]?.installedInfo = installedInfo; - apps[app.app.id]?.icon = - await apps[app.app.id]?.installedInfo?.applicationInfo?.getAppIcon(); - apps[app.app.id]?.app.name = await (apps[app.app.id] - ?.installedInfo - ?.applicationInfo - ?.getAppLabel()) ?? - app.name; - } - - Future updateAppsSuperficialDetails() async { - await Future.wait(apps.values.map((app) async { - var icon = await app.installedInfo?.applicationInfo?.getAppIcon(); - app.app.name = - await (app.installedInfo?.applicationInfo?.getAppLabel()) ?? - app.app.name; - // Update the app in memory with install info and corrections - apps.update( - app.app.id, - (value) => AppInMemory( - app.app, value.downloadProgress, app.installedInfo, icon), - ifAbsent: () => AppInMemory(app.app, null, app.installedInfo, icon)); - notifyListeners(); - })); - } - - Future loadApps( - {String? singleId, bool andUpdateSuperficialDetails = true}) async { + Future loadApps({String? singleId}) async { while (loadingApps) { await Future.delayed(const Duration(microseconds: 1)); } @@ -1231,9 +1197,9 @@ class AppsProvider with ChangeNotifier { // Save the app to the in-memory list without grabbing any OS info first apps.update( app.id, - (value) => AppInMemory( - app!, value.downloadProgress, value.installedInfo, value.icon), - ifAbsent: () => AppInMemory(app!, null, null, null)); + (value) => + AppInMemory(app!, value.downloadProgress, value.installedInfo), + ifAbsent: () => AppInMemory(app!, null, null)); notifyListeners(); try { // Try getting the app's source to ensure no invalid apps get loaded @@ -1259,18 +1225,15 @@ class AppsProvider with ChangeNotifier { // Update the app in memory with install info and corrections apps.update( app.id, - (value) => AppInMemory( - app!, value.downloadProgress, installedInfo, value.icon), - ifAbsent: () => AppInMemory(app!, null, installedInfo, null)); + (value) => + AppInMemory(app!, value.downloadProgress, installedInfo), + ifAbsent: () => AppInMemory(app!, null, installedInfo)); notifyListeners(); } catch (e) { errors.add([app!.id, app.finalName, e.toString()]); } } })); - if (andUpdateSuperficialDetails) { - await updateAppsSuperficialDetails(); - } if (errors.isNotEmpty) { removeApps(errors.map((e) => e[0]).toList()); NotificationsProvider().notify( @@ -1295,7 +1258,6 @@ class AppsProvider with ChangeNotifier { await Future.wait(apps.map((a) async { var app = a.deepCopy(); PackageInfo? info = await getInstalledInfo(app.id); - var icon = await info?.applicationInfo?.getAppIcon(); app.name = await (info?.applicationInfo?.getAppLabel()) ?? app.name; if (attemptToCorrectInstallStatus) { app = getCorrectedInstallStatusAppIfPossible(app, info) ?? app; @@ -1305,10 +1267,9 @@ class AppsProvider with ChangeNotifier { .writeAsStringSync(jsonEncode(app.toJson())); } try { - this.apps.update(app.id, - (value) => AppInMemory(app, value.downloadProgress, info, icon), - ifAbsent: - onlyIfExists ? null : () => AppInMemory(app, null, info, icon)); + this.apps.update( + app.id, (value) => AppInMemory(app, value.downloadProgress, info), + ifAbsent: onlyIfExists ? null : () => AppInMemory(app, null, info)); } catch (e) { if (e is! ArgumentError || e.name != 'key') { rethrow; From 5bf7fdb94e441ba0a738a5905095fa7364bbe6c7 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Thu, 23 May 2024 20:15:25 -0400 Subject: [PATCH 5/8] Revert a previous change related to BG downloads (did not work as intended) --- lib/providers/apps_provider.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 1dc594d..2aa795d 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -1944,8 +1944,7 @@ Future bgUpdateCheck(String taskId, Map? params) async { await appsProvider.downloadAndInstallLatestApps( toInstall.map((e) => e.key).toList(), null, notificationsProvider: notificationsProvider, - forceParallelDownloads: true, - useExisting: false); + forceParallelDownloads: true); } catch (e) { if (e is MultiAppMultiError) { e.idsByErrorString.forEach((key, value) { From 5edaf1306da363f01dbf589a5fa4be7f3357751d Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Thu, 23 May 2024 20:17:44 -0400 Subject: [PATCH 6/8] Update packages + Flutter, increment version --- .flutter | 2 +- pubspec.lock | 20 ++++++++++---------- pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.flutter b/.flutter index 5dcb86f..a14f74f 160000 --- a/.flutter +++ b/.flutter @@ -1 +1 @@ -Subproject commit 5dcb86f68f239346676ceb1ed1ea385bd215fba1 +Subproject commit a14f74ff3a1cbd521163c5f03d68113d50af93d3 diff --git a/pubspec.lock b/pubspec.lock index fa8d129..985d33a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -47,18 +47,18 @@ packages: dependency: "direct main" description: name: app_links - sha256: "8c6ef5ba9e26b720d4c9073826befb87df2ab5e7a81c22b6c3145080b5e736c9" + sha256: "96e677810b83707ff5e10fac11e4839daa0ea4e0123c35864c092699165eb3db" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.1.1" archive: dependency: transitive description: name: archive - sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 + sha256: "6bd38d335f0954f5fad9c79e614604fbf03a0e5b975923dd001b6ea965ef5b4b" url: "https://pub.dev" source: hosted - version: "3.5.1" + version: "3.6.0" args: dependency: transitive description: @@ -443,10 +443,10 @@ packages: dependency: transitive description: name: image - sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" url: "https://pub.dev" source: hosted - version: "4.1.7" + version: "4.2.0" intl: dependency: transitive description: @@ -889,10 +889,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775" + sha256: "17cd5e205ea615e2c6ea7a77323a11712dffa0720a8a90540db57a01347f9ad9" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_ios: dependency: transitive description: @@ -985,10 +985,10 @@ packages: dependency: transitive description: name: webview_flutter_android - sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91 + sha256: "2282ba2320af34b2bd5320156c664d73f3f022341ed78847bc87723bf88c142f" url: "https://pub.dev" source: hosted - version: "3.16.1" + version: "3.16.2" webview_flutter_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b648824..a477eaf 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.9+2266 +version: 1.1.10+2267 environment: sdk: '>=3.0.0 <4.0.0' From 6c5e5043a4ee905013a0583e61eeac1a3f691dc4 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Thu, 23 May 2024 21:02:50 -0400 Subject: [PATCH 7/8] Improve icon loading after last commit --- lib/pages/app.dart | 6 ++--- lib/pages/apps.dart | 7 +++-- lib/providers/apps_provider.dart | 44 +++++++++++++++++++++++--------- pubspec.lock | 4 +-- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/lib/pages/app.dart b/lib/pages/app.dart index 0039cbb..4166480 100644 --- a/lib/pages/app.dart +++ b/lib/pages/app.dart @@ -227,9 +227,9 @@ class _AppPageState extends State { children: [ const SizedBox(height: 20), FutureBuilder( - future: app?.installedInfo?.applicationInfo?.getAppIcon(), + future: appsProvider.updateAppIcon(app?.app.id), builder: (ctx, val) { - return val.data != null + return app?.icon != null ? Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -238,7 +238,7 @@ class _AppPageState extends State { ? null : () => pm.openApp(app.app.id), child: Image.memory( - val.data!, + app!.icon!, height: 150, gaplessPlayback: true, ), diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index 8249940..0485a15 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -407,12 +407,11 @@ class AppsPageState extends State { getAppIcon(int appIndex) { return FutureBuilder( - future: - listedApps[appIndex].installedInfo?.applicationInfo?.getAppIcon(), + future: appsProvider.updateAppIcon(listedApps[appIndex].app.id), builder: (ctx, val) { - return val.data != null + return listedApps[appIndex].icon != null ? Image.memory( - val.data!, + listedApps[appIndex].icon!, gaplessPlayback: true, ) : Row( diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 2aa795d..e1f349c 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -42,10 +42,11 @@ class AppInMemory { late App app; double? downloadProgress; PackageInfo? installedInfo; + Uint8List? icon; - AppInMemory(this.app, this.downloadProgress, this.installedInfo); + AppInMemory(this.app, this.downloadProgress, this.installedInfo, this.icon); AppInMemory deepCopy() => - AppInMemory(app.deepCopy(), downloadProgress, installedInfo); + AppInMemory(app.deepCopy(), downloadProgress, installedInfo, icon); String get name => app.overrideName ?? app.finalName; } @@ -1121,7 +1122,8 @@ class AppsProvider with ChangeNotifier { // FOURTH, DISABLE VERSION DETECTION IF ENABLED AND THE REPORTED/REAL INSTALLED VERSIONS ARE NOT STANDARDIZED if (installedInfo != null && versionDetectionIsStandard && - !isVersionDetectionPossible(AppInMemory(app, null, installedInfo))) { + !isVersionDetectionPossible( + AppInMemory(app, null, installedInfo, null))) { app.additionalSettings['versionDetection'] = false; logs.add('Could not reconcile version formats for: ${app.id}'); modded = true; @@ -1197,9 +1199,9 @@ class AppsProvider with ChangeNotifier { // Save the app to the in-memory list without grabbing any OS info first apps.update( app.id, - (value) => - AppInMemory(app!, value.downloadProgress, value.installedInfo), - ifAbsent: () => AppInMemory(app!, null, null)); + (value) => AppInMemory( + app!, value.downloadProgress, value.installedInfo, value.icon), + ifAbsent: () => AppInMemory(app!, null, null, null)); notifyListeners(); try { // Try getting the app's source to ensure no invalid apps get loaded @@ -1225,9 +1227,9 @@ class AppsProvider with ChangeNotifier { // Update the app in memory with install info and corrections apps.update( app.id, - (value) => - AppInMemory(app!, value.downloadProgress, installedInfo), - ifAbsent: () => AppInMemory(app!, null, installedInfo)); + (value) => AppInMemory( + app!, value.downloadProgress, installedInfo, value.icon), + ifAbsent: () => AppInMemory(app!, null, installedInfo, null)); notifyListeners(); } catch (e) { errors.add([app!.id, app.finalName, e.toString()]); @@ -1251,6 +1253,22 @@ class AppsProvider with ChangeNotifier { notifyListeners(); } + Future updateAppIcon(String? appId) async { + if (apps[appId]?.icon == null) { + var icon = + (await apps[appId]?.installedInfo?.applicationInfo?.getAppIcon()); + if (icon != null) { + apps.update( + apps[appId]!.app.id, + (value) => AppInMemory(apps[appId]!.app, value.downloadProgress, + value.installedInfo, icon), + ifAbsent: () => AppInMemory( + apps[appId]!.app, null, apps[appId]?.installedInfo, icon)); + notifyListeners(); + } + } + } + Future saveApps(List apps, {bool attemptToCorrectInstallStatus = true, bool onlyIfExists = true}) async { @@ -1258,6 +1276,7 @@ class AppsProvider with ChangeNotifier { await Future.wait(apps.map((a) async { var app = a.deepCopy(); PackageInfo? info = await getInstalledInfo(app.id); + var icon = await info?.applicationInfo?.getAppIcon(); app.name = await (info?.applicationInfo?.getAppLabel()) ?? app.name; if (attemptToCorrectInstallStatus) { app = getCorrectedInstallStatusAppIfPossible(app, info) ?? app; @@ -1267,9 +1286,10 @@ class AppsProvider with ChangeNotifier { .writeAsStringSync(jsonEncode(app.toJson())); } try { - this.apps.update( - app.id, (value) => AppInMemory(app, value.downloadProgress, info), - ifAbsent: onlyIfExists ? null : () => AppInMemory(app, null, info)); + this.apps.update(app.id, + (value) => AppInMemory(app, value.downloadProgress, info, icon), + ifAbsent: + onlyIfExists ? null : () => AppInMemory(app, null, info, icon)); } catch (e) { if (e is! ArgumentError || e.name != 'key') { rethrow; diff --git a/pubspec.lock b/pubspec.lock index 985d33a..37b4d9d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -977,10 +977,10 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" + sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522" url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.8.0" webview_flutter_android: dependency: transitive description: From 6a73ade3599984ee00e8e4e092c23ff6d6d05413 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Thu, 23 May 2024 21:18:13 -0400 Subject: [PATCH 8/8] Add a "clear logs" button --- lib/pages/settings.dart | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index 7df6eca..d37f494 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -5,6 +5,7 @@ import 'package:flex_color_picker/flex_color_picker.dart'; import 'package:flutter/material.dart'; import 'package:obtainium/components/custom_app_bar.dart'; import 'package:obtainium/components/generated_form.dart'; +import 'package:obtainium/components/generated_form_modal.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/main.dart'; import 'package:obtainium/providers/apps_provider.dart'; @@ -945,6 +946,25 @@ class _LogsDialogState extends State { ], ), actions: [ + TextButton( + onPressed: () async { + var cont = (await showDialog?>( + context: context, + builder: (BuildContext ctx) { + return GeneratedFormModal( + title: tr('appLogs'), + items: const [], + initValid: true, + message: tr('removeFromObtainium'), + ); + })) != + null; + if (cont) { + logsProvider.clear(); + Navigator.of(context).pop(); + } + }, + child: Text(tr('remove'))), TextButton( onPressed: () { Navigator.of(context).pop();