Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
7d09169c06 | |||
ce6f11f3f2 | |||
d0fb6ac3c0 | |||
ae801a2918 | |||
257fd46e27 | |||
bb96c3ed63 |
@ -15,7 +15,8 @@
|
|||||||
android:label="ReVanced Manager"
|
android:label="ReVanced Manager"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:largeHeap="true">
|
android:largeHeap="true"
|
||||||
|
android:extractNativeLibs="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
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",
|
"widgetTitle": "Select application",
|
||||||
"widgetTitleSelected": "Selected application",
|
"widgetTitleSelected": "Selected application",
|
||||||
"widgetSubtitle": "No application selected.",
|
"widgetSubtitle": "No application selected.",
|
||||||
"noAppsLabel": "No applications found."
|
"noAppsLabel": "No applications found.",
|
||||||
|
"currentVersion": "Current",
|
||||||
|
"recommendedVersion": "Recommended",
|
||||||
|
"anyVersion": "any"
|
||||||
},
|
},
|
||||||
"patchSelectorCard": {
|
"patchSelectorCard": {
|
||||||
"widgetTitle": "Select patches",
|
"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,
|
List<PatchedApplication> patchedApps,
|
||||||
) async {
|
) async {
|
||||||
List<PatchedApplication> unsavedApps = [];
|
List<PatchedApplication> unsavedApps = [];
|
||||||
List<String> installedApps = await _rootAPI.getInstalledApps();
|
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
|
||||||
for (String packageName in installedApps) {
|
if (hasRootPermissions) {
|
||||||
if (!patchedApps.any((app) => app.packageName == packageName)) {
|
List<String> installedApps = await _rootAPI.getInstalledApps();
|
||||||
ApplicationWithIcon? application =
|
for (String packageName in installedApps) {
|
||||||
await DeviceApps.getApp(packageName, true) as ApplicationWithIcon?;
|
if (!patchedApps.any((app) => app.packageName == packageName)) {
|
||||||
if (application != null) {
|
ApplicationWithIcon? application =
|
||||||
unsavedApps.add(
|
await DeviceApps.getApp(packageName, true)
|
||||||
PatchedApplication(
|
as ApplicationWithIcon?;
|
||||||
name: application.appName,
|
if (application != null) {
|
||||||
packageName: application.packageName,
|
unsavedApps.add(
|
||||||
version: application.versionName!,
|
PatchedApplication(
|
||||||
apkFilePath: application.apkFilePath,
|
name: application.appName,
|
||||||
icon: application.icon,
|
packageName: application.packageName,
|
||||||
patchDate: DateTime.now(),
|
version: application.versionName!,
|
||||||
isRooted: true,
|
apkFilePath: application.apkFilePath,
|
||||||
),
|
icon: application.icon,
|
||||||
);
|
patchDate: DateTime.now(),
|
||||||
|
isRooted: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,7 +231,6 @@ class ManagerAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return unsavedApps;
|
return unsavedApps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,14 +263,15 @@ class ManagerAPI {
|
|||||||
|
|
||||||
Future<bool> isAppUninstalled(PatchedApplication app) async {
|
Future<bool> isAppUninstalled(PatchedApplication app) async {
|
||||||
bool existsRoot = false;
|
bool existsRoot = false;
|
||||||
|
bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
|
||||||
if (app.isRooted) {
|
if (app.isRooted) {
|
||||||
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
|
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
|
||||||
if (hasRootPermissions) {
|
if (hasRootPermissions) {
|
||||||
existsRoot = await _rootAPI.isAppInstalled(app.packageName);
|
existsRoot = await _rootAPI.isAppInstalled(app.packageName);
|
||||||
}
|
}
|
||||||
|
return !existsRoot || !existsNonRoot;
|
||||||
}
|
}
|
||||||
bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
|
return !existsNonRoot;
|
||||||
return !existsRoot && !existsNonRoot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> hasAppUpdates(String packageName, DateTime patchDate) async {
|
Future<bool> hasAppUpdates(String packageName, DateTime patchDate) async {
|
||||||
|
@ -220,4 +220,32 @@ class PatcherAPI {
|
|||||||
log.writeAsStringSync(logs);
|
log.writeAsStringSync(logs);
|
||||||
ShareExtend.share(log.path, 'file');
|
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) {
|
if (res != null) {
|
||||||
List<String> apps = res.split('\n');
|
List<String> apps = res.split('\n');
|
||||||
List<String> toRemove = [];
|
apps.removeWhere((pack) => pack.isEmpty);
|
||||||
for (String packageName in apps) {
|
return apps.map((pack) => pack.trim()).toList();
|
||||||
bool isInstalled = await isAppInstalled(packageName);
|
|
||||||
if (!isInstalled) {
|
|
||||||
toRemove.add(packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
apps.removeWhere((a) => toRemove.contains(a));
|
|
||||||
return apps;
|
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception {
|
||||||
return List.empty();
|
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(
|
: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 16.0,
|
height: 18.0,
|
||||||
child: ClipOval(
|
child: ClipOval(
|
||||||
child: Image.memory(
|
child: Image.memory(
|
||||||
locator<PatcherViewModel>().selectedApp == null
|
locator<PatcherViewModel>().selectedApp == null
|
||||||
@ -49,8 +49,23 @@ class AppSelectorCard extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 6),
|
||||||
Text(_getAppSelection()),
|
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'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.0.9+9
|
version: 0.0.10+10
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.17.5 <3.0.0"
|
sdk: ">=2.17.5 <3.0.0"
|
||||||
@ -75,13 +75,6 @@ dev_dependencies:
|
|||||||
injectable_generator: ^1.5.4
|
injectable_generator: ^1.5.4
|
||||||
json_serializable: ^6.3.1
|
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:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
assets:
|
assets:
|
||||||
|