import 'dart:io'; import 'package:flutter/services.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:injectable/injectable.dart'; import 'package:installed_apps/app_info.dart'; import 'package:installed_apps/installed_apps.dart'; import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/utils/string.dart'; @lazySingleton class PatcherAPI { final GithubAPI githubAPI = GithubAPI(); final List _filteredPackages = []; final Map> _filteredPatches = >{}; File? _patchBundleFile; static const platform = MethodChannel('app.revanced/patcher'); Future loadPatches() async { if (_patchBundleFile == null) { String? dexFileUrl = await githubAPI.latestRelease('revanced', 'revanced-patches'); if (dexFileUrl != null && dexFileUrl.isNotEmpty) { _patchBundleFile = await DefaultCacheManager().getSingleFile(dexFileUrl); try { await platform.invokeMethod( 'loadPatches', { 'pathBundlesPaths': [_patchBundleFile!.absolute.path], }, ); } on PlatformException { _patchBundleFile = null; } } } } Future> getFilteredInstalledApps() async { if (_patchBundleFile != null && _filteredPackages.isEmpty) { List all = await InstalledApps.getInstalledApps(false, true); try { List? patchesPackages = await platform.invokeListMethod('getCompatiblePackages'); if (patchesPackages != null) { for (AppInfo app in all) { if (patchesPackages.contains(app.packageName)) { _filteredPackages.add(app); } } } } on Exception { return List.empty(); } } return _filteredPackages; } Future?> getFilteredPatches(AppInfo? targetApp) async { if (_patchBundleFile != null && targetApp != null) { if (_filteredPatches[targetApp.packageName] == null || _filteredPatches[targetApp.packageName]!.isEmpty) { _filteredPatches[targetApp.packageName!] = []; try { var patches = await platform.invokeListMethod>( 'getFilteredPatches', { 'targetPackage': targetApp.packageName, 'targetVersion': targetApp.versionName, 'ignoreVersion': true, }, ); if (patches != null) { for (var patch in patches) { _filteredPatches[targetApp.packageName]!.add( Patch( name: patch['name'], simpleName: (patch['name'] as String) .replaceAll('-', ' ') .split('-') .join(' ') .toTitleCase(), version: patch['version'] ?? 'unknown', description: patch['description'] ?? 'unknown', ), ); } } } on Exception { return List.empty(); } } } else { return List.empty(); } return _filteredPatches[targetApp.packageName]; } }