Compare commits

..

6 Commits

18 changed files with 146 additions and 48 deletions

View File

@ -15,7 +15,8 @@
android:label="ReVanced Manager"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:largeHeap="true">
android:largeHeap="true"
android:extractNativeLibs="true">
<activity
android:name=".MainActivity"
android:exported="true"

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_launcher_round</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_launcher_round</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -50,7 +50,10 @@
"widgetTitle": "Select application",
"widgetTitleSelected": "Selected application",
"widgetSubtitle": "No application selected.",
"noAppsLabel": "No applications found."
"noAppsLabel": "No applications found.",
"currentVersion": "Current",
"recommendedVersion": "Recommended",
"anyVersion": "any"
},
"patchSelectorCard": {
"widgetTitle": "Select patches",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -182,23 +182,27 @@ class ManagerAPI {
List<PatchedApplication> patchedApps,
) async {
List<PatchedApplication> unsavedApps = [];
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?;
if (application != null) {
unsavedApps.add(
PatchedApplication(
name: application.appName,
packageName: application.packageName,
version: application.versionName!,
apkFilePath: application.apkFilePath,
icon: application.icon,
patchDate: DateTime.now(),
isRooted: true,
),
);
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?;
if (application != null) {
unsavedApps.add(
PatchedApplication(
name: application.appName,
packageName: application.packageName,
version: application.versionName!,
apkFilePath: application.apkFilePath,
icon: application.icon,
patchDate: DateTime.now(),
isRooted: true,
),
);
}
}
}
}
@ -227,7 +231,6 @@ class ManagerAPI {
}
}
}
return unsavedApps;
}
@ -260,14 +263,15 @@ class ManagerAPI {
Future<bool> isAppUninstalled(PatchedApplication app) async {
bool existsRoot = false;
bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
if (app.isRooted) {
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
if (hasRootPermissions) {
existsRoot = await _rootAPI.isAppInstalled(app.packageName);
}
return !existsRoot || !existsNonRoot;
}
bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
return !existsRoot && !existsNonRoot;
return !existsNonRoot;
}
Future<bool> hasAppUpdates(String packageName, DateTime patchDate) async {

View File

@ -220,4 +220,32 @@ class PatcherAPI {
log.writeAsStringSync(logs);
ShareExtend.share(log.path, 'file');
}
String getRecommendedVersion(String packageName) {
Map<String, int> versions = {};
for (Patch patch in _patches) {
Package? package = patch.compatiblePackages.firstWhereOrNull(
(pack) => pack.name == packageName,
);
if (package != null) {
for (String version in package.versions) {
versions.update(
version,
(value) => versions[version]! + 1,
ifAbsent: () => 1,
);
}
}
}
if (versions.isNotEmpty) {
var entries = versions.entries.toList()
..sort((a, b) => a.value.compareTo(b.value));
versions
..clear()
..addEntries(entries);
versions.removeWhere((key, value) => value != versions.values.last);
return (versions.keys.toList()..sort()).last;
}
return '';
}
}

View File

@ -59,15 +59,8 @@ class RootAPI {
);
if (res != null) {
List<String> apps = res.split('\n');
List<String> toRemove = [];
for (String packageName in apps) {
bool isInstalled = await isAppInstalled(packageName);
if (!isInstalled) {
toRemove.add(packageName);
}
}
apps.removeWhere((a) => toRemove.contains(a));
return apps;
apps.removeWhere((pack) => pack.isEmpty);
return apps.map((pack) => pack.trim()).toList();
}
} on Exception {
return List.empty();

View File

@ -79,4 +79,32 @@ class PatcherViewModel extends BaseViewModel {
);
}
}
String getAppSelectionString() {
String text = '${selectedApp!.name} (${selectedApp!.packageName})';
if (text.length > 32) {
text = '${text.substring(0, 32)}...)';
}
return text;
}
String getRecommendedVersionString(BuildContext context) {
String recommendedVersion =
_patcherAPI.getRecommendedVersion(selectedApp!.packageName);
if (recommendedVersion.isEmpty) {
recommendedVersion = FlutterI18n.translate(
context,
'appSelectorCard.anyVersion',
);
} else {
recommendedVersion = 'v$recommendedVersion';
}
return '${FlutterI18n.translate(
context,
'appSelectorCard.currentVersion',
)}: v${selectedApp!.version}\n${FlutterI18n.translate(
context,
'appSelectorCard.recommendedVersion',
)}: $recommendedVersion';
}
}

View File

@ -39,7 +39,7 @@ class AppSelectorCard extends StatelessWidget {
: Row(
children: <Widget>[
SizedBox(
height: 16.0,
height: 18.0,
child: ClipOval(
child: Image.memory(
locator<PatcherViewModel>().selectedApp == null
@ -49,8 +49,23 @@ class AppSelectorCard extends StatelessWidget {
),
),
),
const SizedBox(width: 4),
Text(_getAppSelection()),
const SizedBox(width: 6),
Text(locator<PatcherViewModel>().getAppSelectionString()),
],
),
locator<PatcherViewModel>().selectedApp == null
? Container()
: Column(
children: [
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(
locator<PatcherViewModel>()
.getRecommendedVersionString(context),
style: const TextStyle(fontStyle: FontStyle.italic),
),
),
],
),
],
@ -58,10 +73,4 @@ class AppSelectorCard extends StatelessWidget {
),
);
}
String _getAppSelection() {
String name = locator<PatcherViewModel>().selectedApp!.name;
String version = locator<PatcherViewModel>().selectedApp!.version;
return '$name (v$version)';
}
}

View File

@ -4,7 +4,7 @@ homepage: https://github.com/revanced/revanced-manager
publish_to: 'none'
version: 0.0.9+9
version: 0.0.10+10
environment:
sdk: ">=2.17.5 <3.0.0"
@ -75,13 +75,6 @@ dev_dependencies:
injectable_generator: ^1.5.4
json_serializable: ^6.3.1
flutter_icons:
android: true
ios: false
image_path: "assets/images/ic_launcher_round.png"
adaptive_icon_background: "#1B1B1B"
adaptive_icon_foreground: "assets/images/ic_launcher.png"
flutter:
uses-material-design: true
assets: