2022-08-25 01:51:47 +02:00
|
|
|
import 'dart:convert';
|
2022-08-01 21:05:11 +02:00
|
|
|
import 'dart:io';
|
2022-08-25 01:51:47 +02:00
|
|
|
import 'package:device_apps/device_apps.dart';
|
2022-08-29 16:01:51 +02:00
|
|
|
import 'package:github/github.dart';
|
2022-08-25 01:51:47 +02:00
|
|
|
import 'package:injectable/injectable.dart';
|
2022-08-18 18:32:58 +02:00
|
|
|
import 'package:package_info_plus/package_info_plus.dart';
|
2022-08-06 23:35:35 +02:00
|
|
|
import 'package:revanced_manager/constants.dart';
|
2022-08-25 01:51:47 +02:00
|
|
|
import 'package:revanced_manager/models/patched_application.dart';
|
2022-08-09 01:01:06 +02:00
|
|
|
import 'package:revanced_manager/services/github_api.dart';
|
2022-08-25 01:51:47 +02:00
|
|
|
import 'package:revanced_manager/services/root_api.dart';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
2022-07-31 21:46:27 +02:00
|
|
|
|
2022-08-25 01:51:47 +02:00
|
|
|
@lazySingleton
|
2022-08-02 10:06:35 +02:00
|
|
|
class ManagerAPI {
|
2022-08-18 16:33:33 +02:00
|
|
|
final GithubAPI _githubAPI = GithubAPI();
|
2022-08-25 01:51:47 +02:00
|
|
|
final RootAPI _rootAPI = RootAPI();
|
|
|
|
late SharedPreferences _prefs;
|
|
|
|
|
|
|
|
Future<void> initialize() async {
|
|
|
|
_prefs = await SharedPreferences.getInstance();
|
|
|
|
}
|
2022-08-02 10:06:35 +02:00
|
|
|
|
2022-08-19 20:13:43 +02:00
|
|
|
Future<File?> downloadPatches(String extension) async {
|
|
|
|
return await _githubAPI.latestReleaseFile(extension, ghOrg, patchesRepo);
|
2022-08-02 10:06:35 +02:00
|
|
|
}
|
|
|
|
|
2022-08-19 20:13:43 +02:00
|
|
|
Future<File?> downloadIntegrations(String extension) async {
|
2022-08-18 18:32:58 +02:00
|
|
|
return await _githubAPI.latestReleaseFile(
|
2022-08-19 20:13:43 +02:00
|
|
|
extension,
|
|
|
|
ghOrg,
|
|
|
|
integrationsRepo,
|
2022-08-18 18:32:58 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-19 20:13:43 +02:00
|
|
|
Future<File?> downloadManager(String extension) async {
|
|
|
|
return await _githubAPI.latestReleaseFile(extension, ghOrg, managerRepo);
|
|
|
|
}
|
|
|
|
|
2022-08-18 18:32:58 +02:00
|
|
|
Future<String?> getLatestPatchesVersion() async {
|
|
|
|
return await _githubAPI.latestReleaseVersion(ghOrg, patchesRepo);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<String?> getLatestManagerVersion() async {
|
2022-08-19 20:13:43 +02:00
|
|
|
return await _githubAPI.latestReleaseVersion(ghOrg, managerRepo);
|
2022-08-18 18:32:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<String> getCurrentManagerVersion() async {
|
|
|
|
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
|
|
|
return packageInfo.version;
|
|
|
|
}
|
|
|
|
|
2022-09-05 04:32:36 +02:00
|
|
|
bool getUseDynamicTheme() {
|
|
|
|
return _prefs.getBool('useDynamicTheme') ?? false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> setUseDynamicTheme(bool value) async {
|
|
|
|
await _prefs.setBool('useDynamicTheme', value);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool getUseDarkTheme() {
|
|
|
|
return _prefs.getBool('useDarkTheme') ?? false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> setUseDarkTheme(bool value) async {
|
|
|
|
await _prefs.setBool('useDarkTheme', value);
|
|
|
|
}
|
|
|
|
|
2022-08-25 01:51:47 +02:00
|
|
|
bool? isRooted() {
|
|
|
|
return _prefs.getBool('isRooted');
|
|
|
|
}
|
|
|
|
|
2022-09-05 04:32:36 +02:00
|
|
|
Future<void> setIsRooted(bool value) async {
|
|
|
|
await _prefs.setBool('isRooted', value);
|
|
|
|
}
|
|
|
|
|
2022-08-25 01:51:47 +02:00
|
|
|
List<PatchedApplication> getPatchedApps() {
|
|
|
|
List<String> apps = _prefs.getStringList('patchedApps') ?? [];
|
|
|
|
return apps
|
|
|
|
.map((a) => PatchedApplication.fromJson(json.decode(a)))
|
|
|
|
.toList();
|
|
|
|
}
|
|
|
|
|
2022-08-30 03:07:28 +02:00
|
|
|
Future<void> setPatchedApps(List<PatchedApplication> patchedApps) async {
|
2022-09-03 16:28:22 +02:00
|
|
|
if (patchedApps.length > 1) {
|
|
|
|
patchedApps.sort((a, b) => a.name.compareTo(b.name));
|
|
|
|
}
|
2022-08-30 03:07:28 +02:00
|
|
|
await _prefs.setStringList('patchedApps',
|
2022-08-25 01:51:47 +02:00
|
|
|
patchedApps.map((a) => json.encode(a.toJson())).toList());
|
|
|
|
}
|
|
|
|
|
2022-08-30 03:07:28 +02:00
|
|
|
Future<void> savePatchedApp(PatchedApplication app) async {
|
2022-08-25 01:51:47 +02:00
|
|
|
List<PatchedApplication> patchedApps = getPatchedApps();
|
|
|
|
patchedApps.removeWhere((a) => a.packageName == app.packageName);
|
2022-09-01 14:52:51 +02:00
|
|
|
ApplicationWithIcon? installed =
|
|
|
|
await DeviceApps.getApp(app.packageName, true) as ApplicationWithIcon?;
|
|
|
|
if (installed != null) {
|
|
|
|
app.name = installed.appName;
|
|
|
|
app.version = installed.versionName!;
|
|
|
|
app.icon = installed.icon;
|
|
|
|
}
|
2022-08-25 01:51:47 +02:00
|
|
|
patchedApps.add(app);
|
2022-08-30 03:07:28 +02:00
|
|
|
await setPatchedApps(patchedApps);
|
2022-08-25 01:51:47 +02:00
|
|
|
}
|
|
|
|
|
2022-09-05 14:43:13 +02:00
|
|
|
Future<void> deletePatchedApp(PatchedApplication app) async {
|
|
|
|
List<PatchedApplication> patchedApps = getPatchedApps();
|
|
|
|
patchedApps.removeWhere((a) => a.packageName == app.packageName);
|
|
|
|
await setPatchedApps(patchedApps);
|
|
|
|
}
|
|
|
|
|
2022-08-25 01:51:47 +02:00
|
|
|
Future<void> reAssessSavedApps() async {
|
2022-09-05 14:43:13 +02:00
|
|
|
bool isRooted = this.isRooted() ?? false;
|
2022-08-29 16:01:51 +02:00
|
|
|
List<PatchedApplication> patchedApps = getPatchedApps();
|
2022-08-26 03:01:53 +02:00
|
|
|
List<PatchedApplication> toRemove = [];
|
2022-08-25 01:51:47 +02:00
|
|
|
for (PatchedApplication app in patchedApps) {
|
2022-09-05 14:43:13 +02:00
|
|
|
bool isRemove = await isAppUninstalled(app, isRooted);
|
2022-08-29 16:01:51 +02:00
|
|
|
if (isRemove) {
|
2022-08-26 03:01:53 +02:00
|
|
|
toRemove.add(app);
|
2022-08-29 16:01:51 +02:00
|
|
|
} else {
|
2022-08-30 03:07:28 +02:00
|
|
|
app.hasUpdates = await hasAppUpdates(app.packageName, app.patchDate);
|
|
|
|
app.changelog = await getAppChangelog(app.packageName, app.patchDate);
|
2022-09-01 14:23:24 +02:00
|
|
|
if (!app.hasUpdates) {
|
|
|
|
String? currentInstalledVersion =
|
|
|
|
(await DeviceApps.getApp(app.packageName))?.versionName;
|
|
|
|
if (currentInstalledVersion != null) {
|
|
|
|
String currentSavedVersion = app.version;
|
|
|
|
int currentInstalledVersionInt = int.parse(
|
|
|
|
currentInstalledVersion.replaceAll(RegExp('[^0-9]'), ''));
|
|
|
|
int currentSavedVersionInt =
|
|
|
|
int.parse(currentSavedVersion.replaceAll(RegExp('[^0-9]'), ''));
|
|
|
|
if (currentInstalledVersionInt > currentSavedVersionInt) {
|
|
|
|
app.hasUpdates = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-25 01:51:47 +02:00
|
|
|
}
|
|
|
|
}
|
2022-08-26 03:01:53 +02:00
|
|
|
patchedApps.removeWhere((a) => toRemove.contains(a));
|
2022-08-30 03:07:28 +02:00
|
|
|
await setPatchedApps(patchedApps);
|
2022-08-25 01:51:47 +02:00
|
|
|
}
|
|
|
|
|
2022-09-05 14:43:13 +02:00
|
|
|
Future<bool> isAppUninstalled(PatchedApplication app, bool isRooted) async {
|
2022-08-29 16:01:51 +02:00
|
|
|
bool existsRoot = false;
|
2022-09-05 14:43:13 +02:00
|
|
|
if (isRooted) {
|
2022-08-29 16:01:51 +02:00
|
|
|
existsRoot = await _rootAPI.isAppInstalled(app.packageName);
|
|
|
|
}
|
|
|
|
bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
|
|
|
|
return !existsRoot && !existsNonRoot;
|
2022-08-18 18:32:58 +02:00
|
|
|
}
|
|
|
|
|
2022-08-30 03:07:28 +02:00
|
|
|
Future<bool> hasAppUpdates(String packageName, DateTime patchDate) async {
|
|
|
|
List<RepositoryCommit> 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<List<String>> getAppChangelog(
|
|
|
|
String packageName,
|
|
|
|
DateTime patchDate,
|
|
|
|
) async {
|
|
|
|
List<RepositoryCommit> commits =
|
|
|
|
await _githubAPI.getCommits(packageName, ghOrg, patchesRepo);
|
|
|
|
List<String> newCommits = commits
|
2022-08-26 03:01:53 +02:00
|
|
|
.where((c) =>
|
|
|
|
c.commit != null &&
|
|
|
|
c.commit!.author != null &&
|
2022-08-29 16:01:51 +02:00
|
|
|
c.commit!.author!.date != null &&
|
2022-08-30 03:07:28 +02:00
|
|
|
c.commit!.author!.date!.isAfter(patchDate) &&
|
|
|
|
c.commit!.message != null)
|
2022-08-29 16:01:51 +02:00
|
|
|
.map((c) => c.commit!.message!)
|
|
|
|
.toList();
|
2022-08-30 03:07:28 +02:00
|
|
|
if (newCommits.isEmpty) {
|
|
|
|
newCommits = commits
|
|
|
|
.where((c) => c.commit != null && c.commit!.message != null)
|
|
|
|
.take(3)
|
|
|
|
.map((c) => c.commit!.message!)
|
|
|
|
.toList();
|
2022-08-29 16:01:51 +02:00
|
|
|
}
|
2022-08-30 03:07:28 +02:00
|
|
|
return newCommits;
|
2022-08-02 09:55:01 +02:00
|
|
|
}
|
2022-08-01 21:05:11 +02:00
|
|
|
}
|