Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
7d09169c06 | |||
ce6f11f3f2 | |||
d0fb6ac3c0 | |||
ae801a2918 | |||
257fd46e27 | |||
bb96c3ed63 |
@ -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"
|
||||
|
BIN
android/app/src/main/res/drawable/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
19
android/app/src/main/res/values-night-v31/styles.xml
Normal 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>
|
20
android/app/src/main/res/values-v31/styles.xml
Normal 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>
|
||||
|
@ -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",
|
||||
|
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 14 KiB |
@ -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 {
|
||||
|
@ -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 '';
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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';
|
||||
}
|
||||
}
|
||||
|
@ -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)';
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|