mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-31 13:33:28 +01:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			v0.11.26-b
			...
			v0.11.28-b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b62475de87 | ||
|  | 334ac8d3d6 | ||
|  | 9193788356 | ||
|  | 8f75ddd43f | 
| @@ -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.11.26'; | ||||
| const String currentVersion = '0.11.28'; | ||||
| const String currentReleaseTag = | ||||
|     'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES | ||||
|  | ||||
|   | ||||
| @@ -38,7 +38,7 @@ class _AppPageState extends State<AppPage> { | ||||
|     bool areDownloadsRunning = appsProvider.areDownloadsRunning(); | ||||
|  | ||||
|     var sourceProvider = SourceProvider(); | ||||
|     AppInMemory? app = appsProvider.apps[widget.appId]; | ||||
|     AppInMemory? app = appsProvider.apps[widget.appId]?.deepCopy(); | ||||
|     var source = app != null ? sourceProvider.getSource(app.app.url) : null; | ||||
|     if (!areDownloadsRunning && prevApp == null && app != null) { | ||||
|       prevApp = app; | ||||
|   | ||||
| @@ -29,13 +29,13 @@ class AppsPageState extends State<AppsPage> { | ||||
|   final AppsFilter neutralFilter = AppsFilter(); | ||||
|   var updatesOnlyFilter = | ||||
|       AppsFilter(includeUptodate: false, includeNonInstalled: false); | ||||
|   Set<App> selectedApps = {}; | ||||
|   Set<String> selectedAppIds = {}; | ||||
|   DateTime? refreshingSince; | ||||
|  | ||||
|   clearSelected() { | ||||
|     if (selectedApps.isNotEmpty) { | ||||
|     if (selectedAppIds.isNotEmpty) { | ||||
|       setState(() { | ||||
|         selectedApps.clear(); | ||||
|         selectedAppIds.clear(); | ||||
|       }); | ||||
|       return true; | ||||
|     } | ||||
| @@ -43,10 +43,10 @@ class AppsPageState extends State<AppsPage> { | ||||
|   } | ||||
|  | ||||
|   selectThese(List<App> apps) { | ||||
|     if (selectedApps.isEmpty) { | ||||
|     if (selectedAppIds.isEmpty) { | ||||
|       setState(() { | ||||
|         for (var a in apps) { | ||||
|           selectedApps.add(a); | ||||
|           selectedAppIds.add(a.id); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
| @@ -57,20 +57,20 @@ class AppsPageState extends State<AppsPage> { | ||||
|     var appsProvider = context.watch<AppsProvider>(); | ||||
|     var settingsProvider = context.watch<SettingsProvider>(); | ||||
|     var sourceProvider = SourceProvider(); | ||||
|     var listedApps = appsProvider.apps.values.toList(); | ||||
|     var listedApps = appsProvider.getAppValues().toList(); | ||||
|     var currentFilterIsUpdatesOnly = | ||||
|         filter.isIdenticalTo(updatesOnlyFilter, settingsProvider); | ||||
|  | ||||
|     selectedApps = selectedApps | ||||
|         .where((element) => listedApps.map((e) => e.app).contains(element)) | ||||
|     selectedAppIds = selectedAppIds | ||||
|         .where((element) => listedApps.map((e) => e.app.id).contains(element)) | ||||
|         .toSet(); | ||||
|  | ||||
|     toggleAppSelected(App app) { | ||||
|       setState(() { | ||||
|         if (selectedApps.contains(app)) { | ||||
|           selectedApps.remove(app); | ||||
|         if (selectedAppIds.map((e) => e).contains(app.id)) { | ||||
|           selectedAppIds.removeWhere((a) => a == app.id); | ||||
|         } else { | ||||
|           selectedApps.add(app); | ||||
|           selectedAppIds.add(app.id); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
| @@ -143,15 +143,15 @@ class AppsPageState extends State<AppsPage> { | ||||
|     var existingUpdates = appsProvider.findExistingUpdates(installedOnly: true); | ||||
|  | ||||
|     var existingUpdateIdsAllOrSelected = existingUpdates | ||||
|         .where((element) => selectedApps.isEmpty | ||||
|         .where((element) => selectedAppIds.isEmpty | ||||
|             ? listedApps.where((a) => a.app.id == element).isNotEmpty | ||||
|             : selectedApps.map((e) => e.id).contains(element)) | ||||
|             : selectedAppIds.map((e) => e).contains(element)) | ||||
|         .toList(); | ||||
|     var newInstallIdsAllOrSelected = appsProvider | ||||
|         .findExistingUpdates(nonInstalledOnly: true) | ||||
|         .where((element) => selectedApps.isEmpty | ||||
|         .where((element) => selectedAppIds.isEmpty | ||||
|             ? listedApps.where((a) => a.app.id == element).isNotEmpty | ||||
|             : selectedApps.map((e) => e.id).contains(element)) | ||||
|             : selectedAppIds.map((e) => e).contains(element)) | ||||
|         .toList(); | ||||
|  | ||||
|     List<String> trackOnlyUpdateIdsAllOrSelected = []; | ||||
| @@ -212,6 +212,11 @@ class AppsPageState extends State<AppsPage> { | ||||
|               : -1; | ||||
|     }); | ||||
|  | ||||
|     Set<App> selectedApps = listedApps | ||||
|         .map((e) => e.app) | ||||
|         .where((a) => selectedAppIds.contains(a.id)) | ||||
|         .toSet(); | ||||
|  | ||||
|     showChangeLogDialog( | ||||
|         String? changesUrl, AppSource appSource, String changeLog, int index) { | ||||
|       showDialog( | ||||
| @@ -288,7 +293,8 @@ class AppsPageState extends State<AppsPage> { | ||||
|         if (refreshingSince != null) | ||||
|           SliverToBoxAdapter( | ||||
|             child: LinearProgressIndicator( | ||||
|               value: appsProvider.apps.values | ||||
|               value: appsProvider | ||||
|                       .getAppValues() | ||||
|                       .where((element) => !(element.app.lastUpdateCheck | ||||
|                               ?.isBefore(refreshingSince!) ?? | ||||
|                           true)) | ||||
| @@ -467,7 +473,8 @@ class AppsPageState extends State<AppsPage> { | ||||
|                 .colorScheme | ||||
|                 .primary | ||||
|                 .withOpacity(listedApps[index].app.pinned ? 0.2 : 0.1), | ||||
|             selected: selectedApps.contains(listedApps[index].app), | ||||
|             selected: | ||||
|                 selectedAppIds.map((e) => e).contains(listedApps[index].app.id), | ||||
|             onLongPress: () { | ||||
|               toggleAppSelected(listedApps[index].app); | ||||
|             }, | ||||
| @@ -497,7 +504,7 @@ class AppsPageState extends State<AppsPage> { | ||||
|                   ])) | ||||
|                 : trailingRow, | ||||
|             onTap: () { | ||||
|               if (selectedApps.isNotEmpty) { | ||||
|               if (selectedAppIds.isNotEmpty) { | ||||
|                 toggleAppSelected(listedApps[index].app); | ||||
|               } else { | ||||
|                 Navigator.push( | ||||
| @@ -534,7 +541,7 @@ class AppsPageState extends State<AppsPage> { | ||||
|     } | ||||
|  | ||||
|     getSelectAllButton() { | ||||
|       return selectedApps.isEmpty | ||||
|       return selectedAppIds.isEmpty | ||||
|           ? TextButton.icon( | ||||
|               style: const ButtonStyle(visualDensity: VisualDensity.compact), | ||||
|               onPressed: () { | ||||
| @@ -548,17 +555,17 @@ class AppsPageState extends State<AppsPage> { | ||||
|           : TextButton.icon( | ||||
|               style: const ButtonStyle(visualDensity: VisualDensity.compact), | ||||
|               onPressed: () { | ||||
|                 selectedApps.isEmpty | ||||
|                 selectedAppIds.isEmpty | ||||
|                     ? selectThese(listedApps.map((e) => e.app).toList()) | ||||
|                     : clearSelected(); | ||||
|               }, | ||||
|               icon: Icon( | ||||
|                 selectedApps.isEmpty | ||||
|                 selectedAppIds.isEmpty | ||||
|                     ? Icons.select_all_outlined | ||||
|                     : Icons.deselect_outlined, | ||||
|                 color: Theme.of(context).colorScheme.primary, | ||||
|               ), | ||||
|               label: Text(selectedApps.length.toString())); | ||||
|               label: Text(selectedAppIds.length.toString())); | ||||
|     } | ||||
|  | ||||
|     getMassObtainFunction() { | ||||
| @@ -706,7 +713,7 @@ class AppsPageState extends State<AppsPage> { | ||||
|           builder: (BuildContext ctx) { | ||||
|             return AlertDialog( | ||||
|               title: Text(tr('markXSelectedAppsAsUpdated', | ||||
|                   args: [selectedApps.length.toString()])), | ||||
|                   args: [selectedAppIds.length.toString()])), | ||||
|               content: Text( | ||||
|                 tr('onlyWorksWithNonVersionDetectApps'), | ||||
|                 style: const TextStyle( | ||||
| @@ -760,7 +767,7 @@ class AppsPageState extends State<AppsPage> { | ||||
|                   items: const [], | ||||
|                   initValid: true, | ||||
|                   message: tr('installStatusOfXWillBeResetExplanation', | ||||
|                       args: [plural('app', selectedApps.length)]), | ||||
|                       args: [plural('app', selectedAppIds.length)]), | ||||
|                 ); | ||||
|               }); | ||||
|           if (values != null) { | ||||
| @@ -836,7 +843,7 @@ class AppsPageState extends State<AppsPage> { | ||||
|         children: [ | ||||
|           IconButton( | ||||
|             visualDensity: VisualDensity.compact, | ||||
|             onPressed: selectedApps.isEmpty | ||||
|             onPressed: selectedAppIds.isEmpty | ||||
|                 ? null | ||||
|                 : () { | ||||
|                     appsProvider.removeAppsWithModal( | ||||
| @@ -848,7 +855,7 @@ class AppsPageState extends State<AppsPage> { | ||||
|           IconButton( | ||||
|               visualDensity: VisualDensity.compact, | ||||
|               onPressed: getMassObtainFunction(), | ||||
|               tooltip: selectedApps.isEmpty | ||||
|               tooltip: selectedAppIds.isEmpty | ||||
|                   ? tr('installUpdateApps') | ||||
|                   : tr('installUpdateSelectedApps'), | ||||
|               icon: const Icon( | ||||
| @@ -856,13 +863,13 @@ class AppsPageState extends State<AppsPage> { | ||||
|               )), | ||||
|           IconButton( | ||||
|             visualDensity: VisualDensity.compact, | ||||
|             onPressed: selectedApps.isEmpty ? null : launchCategorizeDialog(), | ||||
|             onPressed: selectedAppIds.isEmpty ? null : launchCategorizeDialog(), | ||||
|             tooltip: tr('categorize'), | ||||
|             icon: const Icon(Icons.category_outlined), | ||||
|           ), | ||||
|           IconButton( | ||||
|             visualDensity: VisualDensity.compact, | ||||
|             onPressed: selectedApps.isEmpty ? null : showMoreOptionsDialog, | ||||
|             onPressed: selectedAppIds.isEmpty ? null : showMoreOptionsDialog, | ||||
|             tooltip: tr('more'), | ||||
|             icon: const Icon(Icons.more_horiz), | ||||
|           ), | ||||
|   | ||||
| @@ -34,6 +34,8 @@ class AppInMemory { | ||||
|   AppInfo? installedInfo; | ||||
|  | ||||
|   AppInMemory(this.app, this.downloadProgress, this.installedInfo); | ||||
|   AppInMemory deepCopy() => | ||||
|       AppInMemory(app.deepCopy(), downloadProgress, installedInfo); | ||||
| } | ||||
|  | ||||
| class DownloadedApk { | ||||
| @@ -97,6 +99,8 @@ class AppsProvider with ChangeNotifier { | ||||
|   late Stream<FGBGType>? foregroundStream; | ||||
|   late StreamSubscription<FGBGType>? foregroundSubscription; | ||||
|  | ||||
|   Iterable<AppInMemory> getAppValues() => apps.values.map((a) => a.deepCopy()); | ||||
|  | ||||
|   AppsProvider() { | ||||
|     // Subscribe to changes in the app foreground status | ||||
|     foregroundStream = FGBGEvents.stream.asBroadcastStream(); | ||||
| @@ -165,11 +169,10 @@ class AppsProvider with ChangeNotifier { | ||||
|       notifyListeners(); | ||||
|     } | ||||
|     try { | ||||
|       var fileName = | ||||
|           '${app.id}-${app.latestVersion}-${app.preferredApkIndex}.apk'; | ||||
|       String downloadUrl = await SourceProvider() | ||||
|           .getSource(app.url) | ||||
|           .apkUrlPrefetchModifier(app.apkUrls[app.preferredApkIndex].value); | ||||
|       var fileName = '${app.id}-${downloadUrl.hashCode}.apk'; | ||||
|       var notif = DownloadNotification(app.name, 100); | ||||
|       notificationsProvider?.cancel(notif.id); | ||||
|       int? prevProg; | ||||
| @@ -205,7 +208,7 @@ class AppsProvider with ChangeNotifier { | ||||
|         var originalAppId = app.id; | ||||
|         app.id = newInfo.packageName; | ||||
|         downloadedFile = downloadedFile.renameSync( | ||||
|             '${downloadedFile.parent.path}/${app.id}-${app.latestVersion}-${app.preferredApkIndex}.apk'); | ||||
|             '${downloadedFile.parent.path}/${app.id}-${downloadUrl.hashCode}.apk'); | ||||
|         if (apps[originalAppId] != null) { | ||||
|           await removeApps([originalAppId]); | ||||
|           await saveApps([app]); | ||||
| @@ -668,7 +671,8 @@ class AppsProvider with ChangeNotifier { | ||||
|       bool onlyIfExists = true}) async { | ||||
|     attemptToCorrectInstallStatus = | ||||
|         attemptToCorrectInstallStatus && (await doesInstalledAppsPluginWork()); | ||||
|     for (var app in apps) { | ||||
|     for (var a in apps) { | ||||
|       var app = a.deepCopy(); | ||||
|       AppInfo? info = await getInstalledInfo(app.id); | ||||
|       app.name = info?.name ?? app.name; | ||||
|       if (app.additionalSettings['appName']?.toString().isNotEmpty == true) { | ||||
|   | ||||
| @@ -164,7 +164,8 @@ class SettingsProvider with ChangeNotifier { | ||||
|  | ||||
|   void setCategories(Map<String, int> cats, {AppsProvider? appsProvider}) { | ||||
|     if (appsProvider != null) { | ||||
|       List<App> changedApps = appsProvider.apps.values | ||||
|       List<App> changedApps = appsProvider | ||||
|           .getAppValues() | ||||
|           .map((a) { | ||||
|             var n1 = a.app.categories.length; | ||||
|             a.app.categories.removeWhere((c) => !cats.keys.contains(c)); | ||||
|   | ||||
| @@ -80,6 +80,22 @@ class App { | ||||
|     return 'ID: $id URL: $url INSTALLED: $installedVersion LATEST: $latestVersion APK: $apkUrls PREFERREDAPK: $preferredApkIndex ADDITIONALSETTINGS: ${additionalSettings.toString()} LASTCHECK: ${lastUpdateCheck.toString()} PINNED $pinned'; | ||||
|   } | ||||
|  | ||||
|   App deepCopy() => App( | ||||
|       id, | ||||
|       url, | ||||
|       author, | ||||
|       name, | ||||
|       installedVersion, | ||||
|       latestVersion, | ||||
|       apkUrls, | ||||
|       preferredApkIndex, | ||||
|       Map.from(additionalSettings), | ||||
|       lastUpdateCheck, | ||||
|       pinned, | ||||
|       categories: categories, | ||||
|       changeLog: changeLog, | ||||
|       releaseDate: releaseDate); | ||||
|  | ||||
|   factory App.fromJson(Map<String, dynamic> json) { | ||||
|     var source = SourceProvider().getSource(json['url']); | ||||
|     var formItems = source.combinedAppSpecificSettingFormItems | ||||
|   | ||||
| @@ -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.11.26+148 # When changing this, update the tag in main() accordingly | ||||
| version: 0.11.28+150 # When changing this, update the tag in main() accordingly | ||||
|  | ||||
| environment: | ||||
|   sdk: '>=2.18.2 <3.0.0' | ||||
|   | ||||
		Reference in New Issue
	
	Block a user