feat: call Installer through Home View

This commit is contained in:
Alberto Ponces 2022-08-17 18:44:27 +01:00
parent 750f035104
commit 40f27b3a09
10 changed files with 139 additions and 78 deletions

View File

@ -18,7 +18,7 @@ class PatchedApplication {
final DateTime patchDate; final DateTime patchDate;
final bool isRooted; final bool isRooted;
final bool isFromStorage; final bool isFromStorage;
final List<String> appliedPatches; List<String> appliedPatches;
PatchedApplication({ PatchedApplication({
required this.name, required this.name,
@ -29,7 +29,7 @@ class PatchedApplication {
required this.patchDate, required this.patchDate,
required this.isRooted, required this.isRooted,
required this.isFromStorage, required this.isFromStorage,
this.appliedPatches = const <String>[], required this.appliedPatches,
}); });
factory PatchedApplication.fromJson(Map<String, dynamic> json) => factory PatchedApplication.fromJson(Map<String, dynamic> json) =>

View File

@ -24,8 +24,6 @@ class PatcherAPI {
); );
final GithubAPI githubAPI = GithubAPI(); final GithubAPI githubAPI = GithubAPI();
final RootAPI rootAPI = RootAPI(); final RootAPI rootAPI = RootAPI();
final List<ApplicationWithIcon> _filteredPackages = [];
final Map<String, List<Patch>> _filteredPatches = <String, List<Patch>>{};
Directory? _tmpDir; Directory? _tmpDir;
Directory? _workDir; Directory? _workDir;
Directory? _cacheDir; Directory? _cacheDir;
@ -77,7 +75,8 @@ class PatcherAPI {
} }
Future<List<ApplicationWithIcon>> getFilteredInstalledApps() async { Future<List<ApplicationWithIcon>> getFilteredInstalledApps() async {
if (_patchBundleFile != null && _filteredPackages.isEmpty) { List<ApplicationWithIcon> filteredPackages = [];
if (_patchBundleFile != null) {
try { try {
List<String>? patchesPackages = await patcherChannel List<String>? patchesPackages = await patcherChannel
.invokeListMethod<String>('getCompatiblePackages'); .invokeListMethod<String>('getCompatiblePackages');
@ -87,7 +86,7 @@ class PatcherAPI {
ApplicationWithIcon? app = await DeviceApps.getApp(package, true) ApplicationWithIcon? app = await DeviceApps.getApp(package, true)
as ApplicationWithIcon?; as ApplicationWithIcon?;
if (app != null) { if (app != null) {
_filteredPackages.add(app); filteredPackages.add(app);
} }
} catch (e) { } catch (e) {
continue; continue;
@ -95,58 +94,91 @@ class PatcherAPI {
} }
} }
} on Exception { } on Exception {
_filteredPackages.clear();
return List.empty(); return List.empty();
} }
} }
return _filteredPackages; return filteredPackages;
} }
Future<List<Patch>?> getFilteredPatches( Future<List<Patch>> getFilteredPatches(
PatchedApplication? selectedApp, PatchedApplication? selectedApp,
) async { ) async {
List<Patch> filteredPatches = [];
if (_patchBundleFile != null && selectedApp != null) { if (_patchBundleFile != null && selectedApp != null) {
if (_filteredPatches[selectedApp.packageName] == null || try {
_filteredPatches[selectedApp.packageName]!.isEmpty) { var patches =
_filteredPatches[selectedApp.packageName] = []; await patcherChannel.invokeListMethod<Map<dynamic, dynamic>>(
try { 'getFilteredPatches',
var patches = {
await patcherChannel.invokeListMethod<Map<dynamic, dynamic>>( 'targetPackage': selectedApp.packageName,
'getFilteredPatches', 'targetVersion': selectedApp.version,
{ 'ignoreVersion': true,
'targetPackage': selectedApp.packageName, },
'targetVersion': selectedApp.version, );
'ignoreVersion': true, if (patches != null) {
}, for (var patch in patches) {
); if (!filteredPatches
if (patches != null) { .any((element) => element.name == patch['name'])) {
for (var patch in patches) { filteredPatches.add(
if (!_filteredPatches[selectedApp.packageName]! Patch(
.any((element) => element.name == patch['name'])) { name: patch['name'],
_filteredPatches[selectedApp.packageName]!.add( simpleName: (patch['name'] as String)
Patch( .replaceAll('-', ' ')
name: patch['name'], .split('-')
simpleName: (patch['name'] as String) .join(' ')
.replaceAll('-', ' ') .toTitleCase(),
.split('-') version: patch['version'] ?? '?.?.?',
.join(' ') description: patch['description'] ?? 'N/A',
.toTitleCase(), ),
version: patch['version'] ?? '?.?.?', );
description: patch['description'] ?? 'N/A',
),
);
}
} }
} }
} on Exception {
_filteredPatches[selectedApp.packageName]!.clear();
return List.empty();
} }
} on Exception {
return List.empty();
} }
} else {
return List.empty();
} }
return _filteredPatches[selectedApp.packageName]; return filteredPatches;
}
Future<List<Patch>> getAppliedPatches(
PatchedApplication? selectedApp,
) async {
List<Patch> appliedPatches = [];
if (_patchBundleFile != null && selectedApp != null) {
try {
var patches =
await patcherChannel.invokeListMethod<Map<dynamic, dynamic>>(
'getFilteredPatches',
{
'targetPackage': selectedApp.packageName,
'targetVersion': selectedApp.version,
'ignoreVersion': true,
},
);
if (patches != null) {
for (var patch in patches) {
if (selectedApp.appliedPatches.contains(patch['name'])) {
appliedPatches.add(
Patch(
name: patch['name'],
simpleName: (patch['name'] as String)
.replaceAll('-', ' ')
.split('-')
.join(' ')
.toTitleCase(),
version: patch['version'] ?? '?.?.?',
description: patch['description'] ?? 'N/A',
),
);
}
}
}
} on Exception {
return List.empty();
}
}
return appliedPatches;
} }
Future<File?> downloadIntegrations() async { Future<File?> downloadIntegrations() async {
@ -187,7 +219,7 @@ class PatcherAPI {
'patchedFilePath': _patchedFile!.path, 'patchedFilePath': _patchedFile!.path,
'outFilePath': _outFile!.path, 'outFilePath': _outFile!.path,
'integrationsPath': _integrations!.path, 'integrationsPath': _integrations!.path,
'selectedPatches': selectedPatches.map((e) => e.name).toList(), 'selectedPatches': selectedPatches.map((p) => p.name).toList(),
'cacheDirPath': _cacheDir!.path, 'cacheDirPath': _cacheDir!.path,
'mergeIntegrations': mergeIntegrations, 'mergeIntegrations': mergeIntegrations,
'resourcePatching': resourcePatching, 'resourcePatching': resourcePatching,

View File

@ -27,7 +27,6 @@ class AppSelectorViewModel extends BaseViewModel {
} }
Future<void> getApps() async { Future<void> getApps() async {
await patcherAPI.loadPatches();
apps = await patcherAPI.getFilteredInstalledApps(); apps = await patcherAPI.getFilteredInstalledApps();
} }
@ -42,6 +41,7 @@ class AppSelectorViewModel extends BaseViewModel {
patchDate: DateTime.now(), patchDate: DateTime.now(),
isRooted: isRooted, isRooted: isRooted,
isFromStorage: isFromStorage, isFromStorage: isFromStorage,
appliedPatches: [],
); );
locator<AppSelectorViewModel>().selectedApp = app; locator<AppSelectorViewModel>().selectedApp = app;
locator<PatchesSelectorViewModel>().selectedPatches.clear(); locator<PatchesSelectorViewModel>().selectedPatches.clear();
@ -70,6 +70,7 @@ class AppSelectorViewModel extends BaseViewModel {
patchDate: DateTime.now(), patchDate: DateTime.now(),
isRooted: isRooted, isRooted: isRooted,
isFromStorage: isFromStorage, isFromStorage: isFromStorage,
appliedPatches: [],
); );
locator<AppSelectorViewModel>().selectedApp = app; locator<AppSelectorViewModel>().selectedApp = app;
locator<PatchesSelectorViewModel>().selectedPatches.clear(); locator<PatchesSelectorViewModel>().selectedPatches.clear();

View File

@ -17,6 +17,8 @@ class HomeView extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ViewModelBuilder<HomeViewModel>.reactive( return ViewModelBuilder<HomeViewModel>.reactive(
disposeViewModel: false, disposeViewModel: false,
fireOnModelReadyOnce: true,
onModelReady: (model) => model.initialize(),
viewModelBuilder: () => locator<HomeViewModel>(), viewModelBuilder: () => locator<HomeViewModel>(),
builder: (context, model, child) => Scaffold( builder: (context, model, child) => Scaffold(
body: SafeArea( body: SafeArea(

View File

@ -1,17 +1,28 @@
import 'dart:convert'; import 'dart:convert';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/app/app.router.dart';
import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/github_api.dart';
import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart';
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
@lazySingleton @lazySingleton
class HomeViewModel extends BaseViewModel { class HomeViewModel extends BaseViewModel {
final _navigationService = locator<NavigationService>();
final GithubAPI githubAPI = GithubAPI(); final GithubAPI githubAPI = GithubAPI();
final PatcherAPI patcherAPI = locator<PatcherAPI>();
bool showUpdatableApps = true; bool showUpdatableApps = true;
Future<void> initialize() async {
await patcherAPI.loadPatches();
}
void toggleUpdatableApps(bool value) { void toggleUpdatableApps(bool value) {
showUpdatableApps = value; showUpdatableApps = value;
notifyListeners(); notifyListeners();
@ -20,6 +31,13 @@ class HomeViewModel extends BaseViewModel {
Future downloadPatches() => locator<ManagerAPI>().downloadPatches(); Future downloadPatches() => locator<ManagerAPI>().downloadPatches();
Future downloadIntegrations() => locator<ManagerAPI>().downloadIntegrations(); Future downloadIntegrations() => locator<ManagerAPI>().downloadIntegrations();
void navigateToInstaller(PatchedApplication app) async {
locator<AppSelectorViewModel>().selectedApp = app;
locator<PatchesSelectorViewModel>().selectedPatches =
await patcherAPI.getAppliedPatches(app);
_navigationService.navigateTo(Routes.installerView);
}
Future<List<PatchedApplication>> getPatchedApps(bool isUpdatable) async { Future<List<PatchedApplication>> getPatchedApps(bool isUpdatable) async {
List<PatchedApplication> list = []; List<PatchedApplication> list = [];
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();

View File

@ -109,6 +109,8 @@ class InstallerViewModel extends BaseViewModel {
void installResult() async { void installResult() async {
PatchedApplication? selectedApp = PatchedApplication? selectedApp =
locator<AppSelectorViewModel>().selectedApp; locator<AppSelectorViewModel>().selectedApp;
List<Patch> selectedPatches =
locator<PatchesSelectorViewModel>().selectedPatches;
if (selectedApp != null) { if (selectedApp != null) {
updateLog(selectedApp.isRooted updateLog(selectedApp.isRooted
? 'Installing patched file using root method' ? 'Installing patched file using root method'
@ -116,6 +118,8 @@ class InstallerViewModel extends BaseViewModel {
isInstalled = await locator<PatcherAPI>().installPatchedFile(selectedApp); isInstalled = await locator<PatcherAPI>().installPatchedFile(selectedApp);
if (isInstalled) { if (isInstalled) {
updateLog('Done'); updateLog('Done');
selectedApp.appliedPatches
.addAll(selectedPatches.map((p) => p.name).toList());
await saveApp(selectedApp); await saveApp(selectedApp);
} else { } else {
updateLog('An error occurred! Aborting'); updateLog('An error occurred! Aborting');
@ -153,9 +157,8 @@ class InstallerViewModel extends BaseViewModel {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> patchedApps = prefs.getStringList('patchedApps') ?? []; List<String> patchedApps = prefs.getStringList('patchedApps') ?? [];
String app = json.encode(selectedApp.toJson()); String app = json.encode(selectedApp.toJson());
if (!patchedApps.contains(app)) { patchedApps.remove(app);
patchedApps.add(app); patchedApps.add(app);
prefs.setStringList('patchedApps', patchedApps); prefs.setStringList('patchedApps', patchedApps);
}
} }
} }

View File

@ -22,6 +22,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ViewModelBuilder<PatchesSelectorViewModel>.reactive( return ViewModelBuilder<PatchesSelectorViewModel>.reactive(
disposeViewModel: false, disposeViewModel: false,
fireOnModelReadyOnce: true,
onModelReady: (model) => model.initialize(), onModelReady: (model) => model.initialize(),
viewModelBuilder: () => locator<PatchesSelectorViewModel>(), viewModelBuilder: () => locator<PatchesSelectorViewModel>(),
builder: (context, model, child) => Scaffold( builder: (context, model, child) => Scaffold(
@ -29,7 +30,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
child: Padding( child: Padding(
padding: padding:
const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12.0), const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12.0),
child: model.patches != null && model.patches!.isNotEmpty child: model.patches.isNotEmpty
? Column( ? Column(
children: [ children: [
SearchBar( SearchBar(
@ -84,16 +85,16 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
patches.clear(); patches.clear();
return Expanded( return Expanded(
child: ListView.builder( child: ListView.builder(
itemCount: model.patches!.length, itemCount: model.patches.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
model.patches!.sort((a, b) => a.simpleName.compareTo(b.simpleName)); model.patches.sort((a, b) => a.simpleName.compareTo(b.simpleName));
PatchItem item = PatchItem( PatchItem item = PatchItem(
name: model.patches![index].name, name: model.patches[index].name,
simpleName: model.patches![index].simpleName, simpleName: model.patches[index].simpleName,
version: model.patches![index].version, version: model.patches[index].version,
description: model.patches![index].description, description: model.patches[index].description,
isSelected: model.selectedPatches.any( isSelected: model.selectedPatches.any(
(element) => element.name == model.patches![index].name, (element) => element.name == model.patches[index].name,
), ),
); );
patches.add(item); patches.add(item);
@ -107,19 +108,19 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
patches.clear(); patches.clear();
return Expanded( return Expanded(
child: ListView.builder( child: ListView.builder(
itemCount: model.patches!.length, itemCount: model.patches.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
model.patches!.sort((a, b) => a.simpleName.compareTo(b.simpleName)); model.patches.sort((a, b) => a.simpleName.compareTo(b.simpleName));
if (model.patches![index].simpleName.toLowerCase().contains( if (model.patches[index].simpleName.toLowerCase().contains(
query.toLowerCase(), query.toLowerCase(),
)) { )) {
PatchItem item = PatchItem( PatchItem item = PatchItem(
name: model.patches![index].name, name: model.patches[index].name,
simpleName: model.patches![index].simpleName, simpleName: model.patches[index].simpleName,
version: model.patches![index].version, version: model.patches[index].version,
description: model.patches![index].description, description: model.patches[index].description,
isSelected: model.selectedPatches.any( isSelected: model.selectedPatches.any(
(element) => element.name == model.patches![index].name, (element) => element.name == model.patches[index].name,
), ),
); );
patches.add(item); patches.add(item);

View File

@ -9,7 +9,7 @@ import 'package:stacked/stacked.dart';
class PatchesSelectorViewModel extends BaseViewModel { class PatchesSelectorViewModel extends BaseViewModel {
final PatcherAPI patcherAPI = locator<PatcherAPI>(); final PatcherAPI patcherAPI = locator<PatcherAPI>();
List<Patch>? patches = []; List<Patch> patches = [];
List<Patch> selectedPatches = []; List<Patch> selectedPatches = [];
Future<void> initialize() async { Future<void> initialize() async {
@ -24,14 +24,12 @@ class PatchesSelectorViewModel extends BaseViewModel {
void selectPatches(List<PatchItem> patchItems) { void selectPatches(List<PatchItem> patchItems) {
selectedPatches.clear(); selectedPatches.clear();
if (patches != null) { for (PatchItem item in patchItems) {
for (PatchItem item in patchItems) { if (item.isSelected) {
if (item.isSelected) { Patch patch =
Patch patch = patches.firstWhere((element) => element.name == item.name);
patches!.firstWhere((element) => element.name == item.name); if (!selectedPatches.contains(patch)) {
if (!selectedPatches.contains(patch)) { selectedPatches.add(patch);
selectedPatches.add(patch);
}
} }
} }
} }

View File

@ -39,7 +39,10 @@ class AvailableUpdatesCard extends StatelessWidget {
patchDate: snapshot.data![index].patchDate, patchDate: snapshot.data![index].patchDate,
changelog: snapshot2.data!, changelog: snapshot2.data!,
isUpdatableApp: true, isUpdatableApp: true,
onPressed: () => {}, onPressed: () =>
locator<HomeViewModel>().navigateToInstaller(
snapshot.data![index],
),
), ),
), ),
) )

View File

@ -39,7 +39,10 @@ class InstalledAppsCard extends StatelessWidget {
patchDate: snapshot.data![index].patchDate, patchDate: snapshot.data![index].patchDate,
changelog: snapshot2.data!, changelog: snapshot2.data!,
isUpdatableApp: false, isUpdatableApp: false,
onPressed: () => {}, onPressed: () =>
locator<HomeViewModel>().navigateToInstaller(
snapshot.data![index],
),
), ),
), ),
) )