import 'dart:convert'; import 'dart:io'; import 'package:device_apps/device_apps.dart'; import 'package:github/github.dart'; import 'package:injectable/injectable.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/root_api.dart'; import 'package:shared_preferences/shared_preferences.dart'; @lazySingleton class ManagerAPI { final GithubAPI _githubAPI = GithubAPI(); final RootAPI _rootAPI = RootAPI(); late SharedPreferences _prefs; Future initialize() async { _prefs = await SharedPreferences.getInstance(); } Future downloadPatches(String extension) async { return await _githubAPI.latestReleaseFile(extension, ghOrg, patchesRepo); } Future downloadIntegrations(String extension) async { return await _githubAPI.latestReleaseFile( extension, ghOrg, integrationsRepo, ); } Future downloadManager(String extension) async { return await _githubAPI.latestReleaseFile(extension, ghOrg, managerRepo); } Future getLatestPatchesVersion() async { return await _githubAPI.latestReleaseVersion(ghOrg, patchesRepo); } Future getLatestManagerVersion() async { return await _githubAPI.latestReleaseVersion(ghOrg, managerRepo); } Future getCurrentManagerVersion() async { PackageInfo packageInfo = await PackageInfo.fromPlatform(); return packageInfo.version; } bool? isRooted() { return _prefs.getBool('isRooted'); } List getPatchedApps() { List apps = _prefs.getStringList('patchedApps') ?? []; return apps .map((a) => PatchedApplication.fromJson(json.decode(a))) .toList(); } Future setPatchedApps(List patchedApps) async { await _prefs.setStringList('patchedApps', patchedApps.map((a) => json.encode(a.toJson())).toList()); } Future savePatchedApp(PatchedApplication app) async { List patchedApps = getPatchedApps(); patchedApps.removeWhere((a) => a.packageName == app.packageName); patchedApps.add(app); await setPatchedApps(patchedApps); } Future reAssessSavedApps() async { bool isRoot = isRooted() ?? false; List patchedApps = getPatchedApps(); List toRemove = []; for (PatchedApplication app in patchedApps) { bool isRemove = await isAppUninstalled(app, isRoot); if (isRemove) { toRemove.add(app); } else { app.hasUpdates = await hasAppUpdates(app.packageName, app.patchDate); app.changelog = await getAppChangelog(app.packageName, app.patchDate); } } patchedApps.removeWhere((a) => toRemove.contains(a)); await setPatchedApps(patchedApps); } Future isAppUninstalled(PatchedApplication app, bool isRoot) async { bool existsRoot = false; if (isRoot) { existsRoot = await _rootAPI.isAppInstalled(app.packageName); } bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName); return !existsRoot && !existsNonRoot; } Future hasAppUpdates(String packageName, DateTime patchDate) async { List commits = await _githubAPI.getCommits(packageName, ghOrg, patchesRepo); return commits.any((c) => c.commit != null && c.commit!.author != null && c.commit!.author!.date != null && c.commit!.author!.date!.isAfter(patchDate)); } Future> getAppChangelog( String packageName, DateTime patchDate, ) async { List commits = await _githubAPI.getCommits(packageName, ghOrg, patchesRepo); List newCommits = commits .where((c) => c.commit != null && c.commit!.author != null && c.commit!.author!.date != null && c.commit!.author!.date!.isAfter(patchDate) && c.commit!.message != null) .map((c) => c.commit!.message!) .toList(); if (newCommits.isEmpty) { newCommits = commits .where((c) => c.commit != null && c.commit!.message != null) .take(3) .map((c) => c.commit!.message!) .toList(); } return newCommits; } }