revanced-manager/lib/services/manager_api.dart

308 lines
9.6 KiB
Dart
Raw Normal View History

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';
import 'package:injectable/injectable.dart';
2022-08-18 18:32:58 +02:00
import 'package:package_info_plus/package_info_plus.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/patch.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';
import 'package:revanced_manager/services/revanced_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-08-25 01:51:47 +02:00
@lazySingleton
2022-08-02 10:06:35 +02:00
class ManagerAPI {
final RevancedAPI _revancedAPI = locator<RevancedAPI>();
final GithubAPI _githubAPI = locator<GithubAPI>();
2022-08-25 01:51:47 +02:00
final RootAPI _rootAPI = RootAPI();
2022-09-07 03:37:25 +02:00
final String patcherRepo = 'revanced-patcher';
final String cliRepo = 'revanced-cli';
2022-08-25 01:51:47 +02:00
late SharedPreferences _prefs;
2022-10-08 15:33:45 +02:00
String defaultApiUrl = 'https://releases.rvcd.win/';
2022-09-07 03:37:25 +02:00
String defaultPatcherRepo = 'revanced/revanced-patcher';
String defaultPatchesRepo = 'revanced/revanced-patches';
String defaultIntegrationsRepo = 'revanced/revanced-integrations';
String defaultCliRepo = 'revanced/revanced-cli';
String defaultManagerRepo = 'revanced/revanced-manager';
2022-08-25 01:51:47 +02:00
Future<void> initialize() async {
_prefs = await SharedPreferences.getInstance();
}
2022-08-02 10:06:35 +02:00
String getApiUrl() {
return _prefs.getString('apiUrl') ?? defaultApiUrl;
}
Future<void> setApiUrl(String url) async {
if (url.isEmpty || url == ' ') {
url = defaultApiUrl;
}
await _revancedAPI.initialize(url);
await _revancedAPI.clearAllCache();
await _prefs.setString('apiUrl', url);
}
2022-09-07 03:37:25 +02:00
String getPatchesRepo() {
return _prefs.getString('patchesRepo') ?? defaultPatchesRepo;
}
Future<void> setPatchesRepo(String value) async {
if (value.isEmpty || value.startsWith('/') || value.endsWith('/')) {
2022-09-07 03:37:25 +02:00
value = defaultPatchesRepo;
}
await _prefs.setString('patchesRepo', value);
}
String getIntegrationsRepo() {
return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo;
}
Future<void> setIntegrationsRepo(String value) async {
if (value.isEmpty || value.startsWith('/') || value.endsWith('/')) {
2022-09-07 03:37:25 +02:00
value = defaultIntegrationsRepo;
}
await _prefs.setString('integrationsRepo', value);
}
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
List<PatchedApplication> getPatchedApps() {
List<String> apps = _prefs.getStringList('patchedApps') ?? [];
return apps.map((a) => PatchedApplication.fromJson(jsonDecode(a))).toList();
2022-08-25 01:51:47 +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));
}
await _prefs.setStringList('patchedApps',
2022-08-25 01:51:47 +02:00
patchedApps.map((a) => json.encode(a.toJson())).toList());
}
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);
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);
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);
}
void clearAllData() {
_revancedAPI.clearAllCache();
_githubAPI.clearAllCache();
}
Future<Map<String, List<dynamic>>> getContributors() async {
return await _revancedAPI.getContributors();
}
Future<List<Patch>> getPatches() async {
String repoName = getPatchesRepo();
if (repoName == defaultPatchesRepo) {
return await _revancedAPI.getPatches();
} else {
return await _githubAPI.getPatches(repoName);
}
}
Future<File?> downloadPatches() async {
String repoName = getPatchesRepo();
if (repoName == defaultPatchesRepo) {
return await _revancedAPI.getLatestReleaseFile(
'.jar',
defaultPatchesRepo,
);
} else {
return await _githubAPI.getLatestReleaseFile('.jar', repoName);
}
}
Future<File?> downloadIntegrations() async {
String repoName = getIntegrationsRepo();
if (repoName == defaultIntegrationsRepo) {
return await _revancedAPI.getLatestReleaseFile(
'.apk',
defaultIntegrationsRepo,
);
} else {
return await _githubAPI.getLatestReleaseFile('.apk', repoName);
}
}
Future<File?> downloadManager() async {
return await _revancedAPI.getLatestReleaseFile('.apk', defaultManagerRepo);
}
Future<String?> getLatestPatcherReleaseTime() async {
return await _revancedAPI.getLatestReleaseTime('.gz', defaultPatcherRepo);
}
Future<String?> getLatestManagerReleaseTime() async {
return await _revancedAPI.getLatestReleaseTime('.apk', defaultManagerRepo);
}
Future<String?> getLatestManagerVersion() async {
return await _revancedAPI.getLatestReleaseVersion(
'.apk',
defaultManagerRepo,
);
}
Future<String> getCurrentManagerVersion() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
return packageInfo.version;
}
Future<List<PatchedApplication>> getAppsToRemove(
List<PatchedApplication> patchedApps,
) async {
List<PatchedApplication> toRemove = [];
2022-08-25 01:51:47 +02:00
for (PatchedApplication app in patchedApps) {
bool isRemove = await isAppUninstalled(app);
if (isRemove) {
toRemove.add(app);
}
}
return toRemove;
}
Future<List<PatchedApplication>> getUnsavedApps(
List<PatchedApplication> patchedApps,
) async {
List<PatchedApplication> unsavedApps = [];
2022-09-18 02:54:25 +02:00
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
if (hasRootPermissions) {
List<String> installedApps = await _rootAPI.getInstalledApps();
for (String packageName in installedApps) {
if (!patchedApps.any((app) => app.packageName == packageName)) {
ApplicationWithIcon? application = await DeviceApps.getApp(
packageName,
true,
) as ApplicationWithIcon?;
2022-09-18 02:54:25 +02:00
if (application != null) {
unsavedApps.add(
PatchedApplication(
name: application.appName,
packageName: application.packageName,
originalPackageName: application.packageName,
2022-09-18 02:54:25 +02:00
version: application.versionName!,
apkFilePath: application.apkFilePath,
icon: application.icon,
patchDate: DateTime.now(),
isRooted: true,
),
);
}
}
}
}
List<Application> userApps = await DeviceApps.getInstalledApplications(
includeSystemApps: false,
includeAppIcons: false,
);
for (Application app in userApps) {
if (app.packageName.startsWith('app.revanced') &&
!app.packageName.startsWith('app.revanced.manager.') &&
!patchedApps.any((uapp) => uapp.packageName == app.packageName)) {
ApplicationWithIcon? application = await DeviceApps.getApp(
app.packageName,
true,
) as ApplicationWithIcon?;
if (application != null) {
unsavedApps.add(
PatchedApplication(
name: application.appName,
packageName: application.packageName,
originalPackageName: application.packageName,
version: application.versionName!,
apkFilePath: application.apkFilePath,
icon: application.icon,
patchDate: DateTime.now(),
isRooted: false,
),
);
}
2022-08-25 01:51:47 +02:00
}
}
return unsavedApps;
}
Future<bool> isAppUninstalled(PatchedApplication app) async {
bool existsRoot = false;
2022-09-18 02:54:25 +02:00
bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
if (app.isRooted) {
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
if (hasRootPermissions) {
existsRoot = await _rootAPI.isAppInstalled(app.packageName);
}
2022-09-18 02:54:25 +02:00
return !existsRoot || !existsNonRoot;
}
2022-09-18 02:54:25 +02:00
return !existsNonRoot;
2022-08-18 18:32:58 +02:00
}
Future<bool> hasAppUpdates(String packageName, DateTime patchDate) async {
List<String> commits = await _githubAPI.getCommits(
2022-09-07 03:37:25 +02:00
packageName,
getPatchesRepo(),
patchDate,
2022-09-07 03:37:25 +02:00
);
return commits.isNotEmpty;
}
Future<List<String>> getAppChangelog(
String packageName, DateTime patchDate) async {
List<String> newCommits = await _githubAPI.getCommits(
2022-09-07 03:37:25 +02:00
packageName,
getPatchesRepo(),
patchDate,
2022-09-07 03:37:25 +02:00
);
if (newCommits.isEmpty) {
newCommits = await _githubAPI.getCommits(
packageName,
getPatchesRepo(),
2022-10-08 18:36:45 +02:00
patchDate,
);
}
return newCommits;
}
Future<bool> isSplitApk(PatchedApplication patchedApp) async {
Application? app;
if (patchedApp.isFromStorage) {
app = await DeviceApps.getAppFromStorage(patchedApp.apkFilePath);
} else {
app = await DeviceApps.getApp(patchedApp.packageName);
}
return app != null && app.isSplit;
}
2022-08-01 21:05:11 +02:00
}