Compare commits

..

16 Commits

Author SHA1 Message Date
semantic-release-bot
9bf5153e6b chore(release): 1.19.0-dev.6 [skip ci]
## Bug Fixes
* **PopScope:** User able to exit patch screen when the installer is still running (#1663) ([Benjamin](eb6d3cd64e))
## Code Refactoring
* Disable update for dev build (#1662) ([Benjamin](c900d09cf8))
## Continuous Integration
* Add scope to changelog (#1672) ([Benjamin](8cda2c164d))
2024-02-03 03:36:47 +00:00
Benjamin
eb6d3cd64e fix(PopScope): User able to exit patch screen when the installer is still running (#1663) 2024-02-03 10:29:34 +07:00
Benjamin
8cda2c164d ci: Add scope to changelog (#1672) 2024-02-03 09:02:53 +07:00
Benjamin
c900d09cf8 refactor: Disable update for dev build (#1662) 2024-02-02 21:12:10 +07:00
semantic-release-bot
edc8ef4f44 chore(release): 1.19.0-dev.5 [skip ci]
## Bug Fixes
* Add top padding ([Pun Butrach](9aeb156d92))
2024-02-02 13:12:37 +00:00
Pun Butrach
9aeb156d92 fix(Update Confirmation Sheet): Add top padding
Before the "Changelog" or homeView.updateChangelogTitle was almost at the edge of the [DraggableScrollableSheet]

We fix it by adding 12px padding off the top, 12px was chosen because [bottom] padding is using 12px so it would make sense for [top] to be using 12px.
2024-02-02 13:05:15 +00:00
Pun Butrach
8be07de373 ci(release): Migrate deprecated Node version 2024-02-02 11:38:53 +07:00
semantic-release-bot
93482b0041 chore(release): 1.19.0-dev.4 [skip ci]
## Bug Fixes
* Stop patch when signing fails ([#1553](https://github.com/ReVanced/revanced-manager/issues/1553)) ([kitadai31](5b2c55142e))
2024-02-02 00:02:38 +00:00
kitadai31
5b2c55142e fix: Stop patch when signing fails (#1553) 2024-02-02 00:55:18 +01:00
Benjamin
088a3b7c28 ci: Improve build workflow (#1668) 2024-02-01 08:57:15 +07:00
semantic-release-bot
b115643034 chore(release): 1.19.0-dev.3 [skip ci]
# [1.19.0-dev.3](https://github.com/ReVanced/revanced-manager/compare/v1.19.0-dev.2...v1.19.0-dev.3) (2024-01-29)

### Bug Fixes

* Do not delete files from post-fs-data.d ([70a1086](70a1086edf))

### Features

* Show a dialog when an update is available ([#1654](https://github.com/ReVanced/revanced-manager/issues/1654)) ([c7d975e](c7d975e612))
2024-01-29 10:19:31 +00:00
Benjamin
07fc964f9c ci: Specify paths in release workflow (#1664) 2024-01-29 11:11:42 +01:00
Pun Butrach
3e51caf111 docs(Security): Avoid table shifting layout 2024-01-29 11:11:42 +01:00
Pun Butrach
deb1ba339f docs(Security): Use dynamic information on version
Meanwhile latest get the static treatment.
2024-01-29 11:11:42 +01:00
aAbed
70a1086edf fix: Do not delete files from post-fs-data.d 2024-01-27 09:08:44 +05:45
aAbed
c7d975e612 feat: Show a dialog when an update is available (#1654) 2024-01-27 09:08:44 +05:45
22 changed files with 761 additions and 320 deletions

View File

@@ -6,7 +6,14 @@ on:
branches:
- main
- dev
paths:
- ".github/workflows/release-build.yml"
- "android/**"
- "assets/**"
- "lib/**"
- ".releaserc.js"
- "pubspec.yaml"
jobs:
release:
runs-on: ubuntu-latest
@@ -24,7 +31,7 @@ jobs:
channel: "stable"
- name: Cache Node modules
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
node_modules
@@ -33,20 +40,6 @@ jobs:
- name: Setup semantic-release
run: npm install
- name: Get version code
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
npx semantic-release --extends ./.releaserc.getversion.json --no-ci --dry-run
echo "RELEASE_VERSION=v$(cat .VERSION)" >> $GITHUB_ENV
- name: Bump pubspec version
run: |
VERSION=$(echo "${RELEASE_VERSION}" | sed 's/v//')
IFS='.' read -r -a nums <<< "${VERSION/-dev/}.0"
VERSIONCODE=$((nums[0] * 100000000 + nums[1] * 100000 + nums[2] * 100 + nums[3]))
sed -i "/^version/c\\version: $VERSION+$VERSIONCODE" pubspec.yaml
- name: Set up Flutter
run: flutter pub get
@@ -54,22 +47,12 @@ jobs:
run: dart run build_runner build --delete-conflicting-outputs
- name: Build with Flutter
run: flutter build apk
- name: Sign APK
id: sign_apk
uses: ilharp/sign-android-release@v1
with:
releaseDir: build/app/outputs/apk/release
signingKey: ${{ secrets.SIGNING_KEYSTORE }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
signingKey: "keystore.jks"
keyStorePassword: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }}
keyAlias: ${{ secrets.SIGNING_KEY_ALIAS }}
keyPassword: ${{ secrets.SIGNING_KEY_PASSWORD }}
- name: Rename APK
run: mv ${{steps.sign_apk.outputs.signedFile}} revanced-manager-${{ env.RELEASE_VERSION }}.apk
- name: Publish release APK
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release --extends ./.releaserc.release.json
run: |
echo "${{ secrets.SIGNING_KEYSTORE }}" | base64 --decode > android/app/keystore.jks
npx semantic-release

View File

@@ -1,24 +0,0 @@
{
"branches": [
"main",
{
"name": "dev",
"prerelease": true
}
],
"plugins": [
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],
[
"@semantic-release/exec",
{
"verifyReleaseCmd": "echo ${nextRelease.version} > .VERSION"
}
]
]
}

117
.releaserc.js Normal file
View File

@@ -0,0 +1,117 @@
module.exports = {
"branches": [
"main",
{
"name": "dev",
"prerelease": true
}
],
"plugins": [
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],
"@semantic-release/changelog",
[
"@semantic-release/release-notes-generator",
{
preset: "conventionalcommits",
presetConfig: {
types: [
{ type: "feat", section: "Features" },
{ type: "fix", section: "Bug Fixes" },
{ type: "docs", section: "Documentation" },
{ type: "style", section: "Styles" },
{ type: "refactor", section: "Code Refactoring" },
{ type: "perf", section: "Performance Improvements" },
{ type: "test", section: "Tests" },
{ type: "build", section: "Build System" },
{ type: "ci", section: "Continuous Integration" },
{ type: "chore", section: "Chores" },
{ type: "revert", section: "Reverts" },
]
},
writerOpts: {
transform: (commit, context) => {
if (commit.author.name === "semantic-release-bot") return;
const types = {
feat: "Features",
fix: "Bug Fixes",
docs: "Documentation",
style: "Styles",
refactor: "Code Refactoring",
perf: "Performance Improvements",
test: "Tests",
build: "Build System",
ci: "Continuous Integration",
chore: "Chores",
revert: "Reverts",
}
commit.type = types[commit.type];
return commit;
},
commitPartial: "* {{#if scope}}**{{scope}}:** {{/if}}{{subject}} ([{{author.name}}]({{~@root.host}}/{{~@root.owner}}/{{~@root.repository}}/commit/{{hash}}))\n",
mainTemplate: `
{{#each commitGroups}}
{{#if title}}
## {{title}}
{{/if}}
{{#each commits}}
{{> commit root=@root}}
{{/each}}
{{/each}}
`
}
}
],
[
"@droidsolutions-oss/semantic-release-update-file",
{
"files": [
{
"path": ["pubspec.yaml"],
"type": "flutter",
"branches": ["main", "dev"]
}
]
}
],
[
"@semantic-release/exec",
{
"prepareCmd": "flutter build apk"
}
],
[
"@semantic-release/git",
{
"assets": [
"pubspec.yaml"
]
}
],
[
"@semantic-release/github",
{
"assets": [
{
"path": "build/app/outputs/apk/release/revanced-manager*.apk"
}
],
"successComment": false
}
],
[
"@saithodev/semantic-release-backmerge",
{
"backmergeBranches": [{"from": "main", "to": "dev"}],
"clearWorkspace": true
}
]
],
};

View File

@@ -1,46 +0,0 @@
{
"branches": [
"main",
{
"name": "dev",
"prerelease": true
}
],
"plugins": [
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],
"@semantic-release/changelog",
"@semantic-release/release-notes-generator",
[
"@semantic-release/git",
{
"assets": [
"pubspec.yaml"
]
}
],
[
"@semantic-release/github",
{
"assets": [
{
"path": "revanced-manager-v*.apk"
}
],
"successComment": false
}
],
[
"@saithodev/semantic-release-backmerge",
{
"backmergeBranches": [{"from": "main", "to": "dev"}],
"clearWorkspace": true
}
]
]
}

View File

@@ -72,7 +72,6 @@ If a vulnerability is confirmed and accepted, you can join our [Discord](https:/
| Version | Branch | Supported |
| ------- | ------------|------------------- |
| v1.19.0 | main | :white_check_mark: |
| latest | dev | :white_check_mark: |
| latest | compose-dev | :white_check_mark: |
| ![GitHub Release](https://img.shields.io/github/v/release/ReVanced/revanced-manager?style=for-the-badge) | main | :white_check_mark: |
| ![Static Badge](https://img.shields.io/badge/version-latest-brightgreen?style=for-the-badge) | dev | :white_check_mark: |
| ![Static Badge](https://img.shields.io/badge/version-latest-brightgreen?style=for-the-badge) | compose-dev | :white_check_mark: |

View File

@@ -47,11 +47,30 @@ android {
release {
shrinkResources false
minifyEnabled false
resValue "string", "app_name", "ReVanced Manager"
signingConfig signingConfigs.debug
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
}
if (System.getenv("signingKey") != null) {
signingConfigs {
create("release") {
storeFile = file(System.getenv("signingKey"))
storePassword = System.getenv("keyStorePassword")
keyAlias = System.getenv("keyAlias")
keyPassword = System.getenv("keyPassword")
}
}
signingConfig = signingConfigs.release
resValue "string", "app_name", "ReVanced Manager"
applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "revanced-manager-v${flutterVersionName}.apk"
}
}
} else {
signingConfig = signingConfigs.debug
resValue "string", "app_name", "ReVanced Manager Debug"
applicationIdSuffix ".debug"
}
}
debug {
shrinkResources false

View File

@@ -401,13 +401,7 @@ class MainActivity : FlutterActivity() {
updateProgress(0.8, "Signing...", "Signing APK")
try {
Signer("ReVanced", keystorePassword)
.signApk(patchedFile, outFile, keyStoreFile)
} catch (e: Exception) {
print("Error signing APK: ${e.message}")
e.printStackTrace()
}
Signer("ReVanced", keystorePassword).signApk(patchedFile, outFile, keyStoreFile)
updateProgress(.85, "Patched", "Patched APK")
} catch (ex: Throwable) {

View File

@@ -16,6 +16,8 @@
"noShowAgain": "Don't show this again",
"add": "Add",
"remove": "Remove",
"showChangelogButton": "Show changelog",
"showUpdateButton": "Show update",
"navigationView": {
"dashboardTab": "Dashboard",
"patcherTab": "Patcher",
@@ -27,6 +29,7 @@
"updatesSubtitle": "Updates",
"patchedSubtitle": "Patched apps",
"changeLaterSubtitle": "You can change this in the settings at a later time.",
"noUpdates": "No updates available",
@@ -35,20 +38,25 @@
"noInstallations": "No patched apps installed",
"installUpdate": "Continue to install the update?",
"updateDialogTitle": "Update Manager",
"updatePatchesDialogTitle": "Update ReVanced Patches",
"updateSheetTitle": "Update ReVanced Manager",
"updateDialogTitle": "New update available",
"updatePatchesSheetTitle": "Update ReVanced Patches",
"updateChangelogTitle": "Changelog",
"patchesConsentDialogText": "ReVanced Patches needs to be downloaded.",
"patchesConsentDialogText2": "This will connect you to {url}.",
"patchesConsentDialogText3": "Auto update?",
"patchesConsentDialogText3Sub": "You can change this in settings at a later time.",
"updateDialogText": "A new update is available for {file}.\n\nThe currently installed version is {version}.",
"downloadConsentDialogTitle": "Download necessary files?",
"downloadConsentDialogText": "ReVanced Manager needs to download necessary files to work properly.",
"downloadConsentDialogText2": "This will connect you to {url}.",
"checkUpdateDialogTitle": "Check for updates?",
"checkUpdateDialogText": "Do you want ReVanced Manager to check for updates automatically?",
"notificationTitle": "Update downloaded",
"notificationText": "Tap to install the update",
"downloadingMessage": "Downloading update...",
"downloadedMessage": "Update downloaded!",
"downloadedMessage": "Update downloaded",
"installingMessage": "Installing update...",
@@ -157,7 +165,7 @@
"unsupportedPatchVersion": "Patch is not supported for this app version.",
"unsupportedRequiredOption": "This patch contains a required option that is not supported by this app",
"patchesChangeWarningDialogText": "It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou'll need to turn on \"Allow changing patch selection\" in settings before changing any patch selection.",
"patchesChangeWarningDialogText": "It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou'll need to turn on \"Allow changing patch selection\" in the settings before changing any patch selection.",
"patchesChangeWarningDialogButton": "Use default selection"
},
"installerView": {
@@ -235,6 +243,8 @@
"autoUpdatePatchesLabel": "Auto update patches",
"autoUpdatePatchesHint": "Automatically update patches to the latest version",
"showUpdateDialogLabel": "Show update dialog",
"showUpdateDialogHint": "Show a dialog when a new update is available",
"universalPatchesLabel": "Show universal patches",
"universalPatchesHint": "Display all apps and universal patches (may slow down the app list)",

View File

@@ -81,7 +81,7 @@ class GithubAPI {
int updates = 0;
final String currentVersion =
await _managerAPI.getCurrentManagerVersion();
while (response.data[updates]['tag_name'] != 'v$currentVersion') {
while (response.data[updates]['tag_name'] != currentVersion) {
updates++;
}
for (int i = 1; i < updates; i++) {

View File

@@ -36,6 +36,7 @@ class ManagerAPI {
Patch? selectedPatch;
BuildContext? ctx;
bool isRooted = false;
bool releaseBuild = false;
bool suggestedAppVersionSelected = true;
bool isDynamicThemeAvailable = false;
String storedPatchesFile = '/selected-patches.json';
@@ -68,6 +69,9 @@ class ManagerAPI {
(await getSdkVersion()) >= 31; // ANDROID_12_SDK_VERSION = 31
storedPatchesFile =
(await getApplicationDocumentsDirectory()).path + storedPatchesFile;
if (kReleaseMode) {
releaseBuild = !(await getCurrentManagerVersion()).contains('-dev');
}
// Migrate to new API URL if not done yet as the old one is sunset.
final bool hasMigrated = _prefs.getBool('migratedToNewApiUrl') ?? false;
@@ -128,12 +132,12 @@ class ManagerAPI {
await _prefs.setString('patchesRepo', value);
}
bool getPatchesConsent() {
return _prefs.getBool('patchesConsent') ?? false;
bool getDownloadConsent() {
return _prefs.getBool('downloadConsent') ?? false;
}
Future<void> setPatchesConsent(bool consent) async {
await _prefs.setBool('patchesConsent', consent);
void setDownloadConsent(bool consent) {
_prefs.setBool('downloadConsent', consent);
}
bool isPatchesAutoUpdate() {
@@ -156,6 +160,14 @@ class ManagerAPI {
_prefs.setBool('showPatchesChangeWarning', !value);
}
bool showUpdateDialog() {
return _prefs.getBool('showUpdateDialog') ?? true;
}
void setShowUpdateDialog(bool value) {
_prefs.setBool('showUpdateDialog', value);
}
bool isChangingToggleModified() {
return _prefs.getBool('isChangingToggleModified') ?? false;
}
@@ -164,8 +176,8 @@ class ManagerAPI {
_prefs.setBool('isChangingToggleModified', value);
}
Future<void> setPatchesAutoUpdate(bool value) async {
await _prefs.setBool('patchesAutoUpdate', value);
void setPatchesAutoUpdate(bool value) {
_prefs.setBool('patchesAutoUpdate', value);
}
List<Patch> getSavedPatches(String packageName) {
@@ -508,7 +520,11 @@ class ManagerAPI {
Future<String> getCurrentManagerVersion() async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
return packageInfo.version;
String version = packageInfo.version;
if (!version.startsWith('v')) {
version = 'v$version';
}
return version;
}
Future<String> getCurrentPatchesVersion() async {

View File

@@ -8,6 +8,7 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:injectable/injectable.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/services/download_manager.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:synchronized/synchronized.dart';
import 'package:timeago/timeago.dart';
@@ -48,6 +49,9 @@ class RevancedAPI {
String extension,
String repoName,
) {
if (!locator<ManagerAPI>().getDownloadConsent()) {
return Future(() => null);
}
return getToolsLock.synchronized(() async {
try {
final response = await _dio.get('/tools');

View File

@@ -2,9 +2,6 @@ import 'package:flutter/foundation.dart';
import 'package:root/root.dart';
class RootAPI {
// TODO(aAbed): remove in the future, keep it for now during migration.
final String _postFsDataDirPath = '/data/adb/post-fs-data.d';
final String _revancedDirPath = '/data/adb/revanced';
final String _serviceDDirPath = '/data/adb/service.d';
@@ -99,18 +96,9 @@ class RootAPI {
);
}
// TODO(aAbed): remove in the future, keep it for now during migration.
Future<void> removeOrphanedFiles() async {
await Root.exec(
cmd: '''
find $_revancedDirPath -type f -name original.apk -delete
for file in "$_serviceDDirPath"/*; do
filename=\$(basename "\$file")
if [ -f "$_postFsDataDirPath/\$filename" ]; then
rm "$_postFsDataDirPath/\$filename"
fi
done
''',
cmd: 'find $_revancedDirPath -type f -name original.apk -delete',
);
}

View File

@@ -19,7 +19,7 @@ import 'package:revanced_manager/services/revanced_api.dart';
import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/homeView/update_confirmation_dialog.dart';
import 'package:revanced_manager/ui/widgets/homeView/update_confirmation_sheet.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_checkbox_list_tile.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
@@ -34,16 +34,30 @@ class HomeViewModel extends BaseViewModel {
final Toast _toast = locator<Toast>();
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
bool showUpdatableApps = false;
bool releaseBuild = false;
List<PatchedApplication> patchedInstalledApps = [];
String _currentManagerVersion = '';
String _currentPatchesVersion = '';
String? _latestManagerVersion = '';
File? downloadedApk;
Future<void> initialize(BuildContext context) async {
_managerAPI.rePatchedSavedApps().then((_) => _getPatchedApps());
_currentManagerVersion = await _managerAPI.getCurrentManagerVersion();
if (!_managerAPI.getDownloadConsent()) {
await showDownloadConsent(context);
await forceRefresh(context);
return;
}
_latestManagerVersion = await _managerAPI.getLatestManagerVersion();
if (!_managerAPI.getPatchesConsent()) {
await showPatchesConsent(context);
_currentPatchesVersion = await _managerAPI.getCurrentPatchesVersion();
if (_managerAPI.showUpdateDialog() && await hasManagerUpdates()) {
showUpdateDialog(context, false);
}
if (!_managerAPI.isPatchesAutoUpdate() &&
_managerAPI.showUpdateDialog() &&
await hasPatchesUpdates()) {
showUpdateDialog(context, true);
}
await _patcherAPI.initialize();
@@ -114,17 +128,13 @@ class HomeViewModel extends BaseViewModel {
}
Future<bool> hasManagerUpdates() async {
String currentVersion = await _managerAPI.getCurrentManagerVersion();
// add v to current version
if (!currentVersion.startsWith('v')) {
currentVersion = 'v$currentVersion';
if (!_managerAPI.releaseBuild) {
return false;
}
_latestManagerVersion =
await _managerAPI.getLatestManagerVersion() ?? currentVersion;
await _managerAPI.getLatestManagerVersion() ?? _currentManagerVersion;
if (_latestManagerVersion != currentVersion) {
if (_latestManagerVersion != _currentManagerVersion) {
return true;
}
return false;
@@ -132,13 +142,12 @@ class HomeViewModel extends BaseViewModel {
Future<bool> hasPatchesUpdates() async {
final String? latestVersion = await _managerAPI.getLatestPatchesVersion();
final String currentVersion = await _managerAPI.getCurrentPatchesVersion();
if (latestVersion != null) {
try {
final int latestVersionInt =
int.parse(latestVersion.replaceAll(RegExp('[^0-9]'), ''));
final int currentVersionInt =
int.parse(currentVersion.replaceAll(RegExp('[^0-9]'), ''));
int.parse(_currentPatchesVersion.replaceAll(RegExp('[^0-9]'), ''));
return latestVersionInt > currentVersionInt;
} on Exception catch (e) {
if (kDebugMode) {
@@ -166,22 +175,98 @@ class HomeViewModel extends BaseViewModel {
}
}
Future<void> showPatchesConsent(BuildContext context) async {
Future<void> showDownloadConsent(BuildContext context) async {
final ValueNotifier<bool> autoUpdate = ValueNotifier(true);
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: const Text('Download ReVanced Patches?'),
builder: (context) => PopScope(
canPop: false,
child: AlertDialog(
title: I18nText('homeView.downloadConsentDialogTitle'),
content: ValueListenableBuilder(
valueListenable: autoUpdate,
builder: (context, value, child) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'homeView.downloadConsentDialogText',
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: I18nText(
'homeView.downloadConsentDialogText2',
translationParams: {
'url': _managerAPI.defaultApiUrl.split('/')[2],
},
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.error,
),
),
),
),
],
);
},
),
actions: [
TextButton(
onPressed: () async {
_managerAPI.setDownloadConsent(false);
SystemNavigator.pop();
},
child: I18nText('quitButton'),
),
FilledButton(
onPressed: () async {
_managerAPI.setDownloadConsent(true);
_managerAPI.setPatchesAutoUpdate(autoUpdate.value);
Navigator.of(context).pop();
},
child: I18nText('okButton'),
),
],
),
),
);
}
void showUpdateDialog(BuildContext context, bool isPatches) {
final ValueNotifier<bool> noShow =
ValueNotifier(!_managerAPI.showUpdateDialog());
showDialog(
context: context,
builder: (innerContext) => AlertDialog(
title: I18nText('homeView.updateDialogTitle'),
content: ValueListenableBuilder(
valueListenable: autoUpdate,
valueListenable: noShow,
builder: (context, value, child) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'homeView.patchesConsentDialogText',
'homeView.updateDialogText',
translationParams: {
'file': isPatches ? 'ReVanced Patches' : 'ReVanced Manager',
'version': isPatches
? _currentPatchesVersion
: _currentManagerVersion,
},
child: Text(
'',
style: TextStyle(
@@ -191,34 +276,18 @@ class HomeViewModel extends BaseViewModel {
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: I18nText(
'homeView.patchesConsentDialogText2',
translationParams: {
'url': _managerAPI.defaultApiUrl.split('/')[2],
},
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.error,
),
),
),
),
const SizedBox(height: 10),
HapticCheckboxListTile(
value: value,
contentPadding: EdgeInsets.zero,
title: I18nText(
'homeView.patchesConsentDialogText3',
'noShowAgain',
),
subtitle: I18nText(
'homeView.patchesConsentDialogText3Sub',
'homeView.changeLaterSubtitle',
),
onChanged: (selected) {
autoUpdate.value = selected!;
noShow.value = selected!;
},
),
],
@@ -228,18 +297,18 @@ class HomeViewModel extends BaseViewModel {
actions: [
TextButton(
onPressed: () async {
await _managerAPI.setPatchesConsent(false);
SystemNavigator.pop();
_managerAPI.setShowUpdateDialog(!noShow.value);
Navigator.pop(innerContext);
},
child: I18nText('quitButton'),
child: I18nText('dismissButton'), // Decide later
),
FilledButton(
onPressed: () async {
await _managerAPI.setPatchesConsent(true);
await _managerAPI.setPatchesAutoUpdate(autoUpdate.value);
Navigator.of(context).pop();
_managerAPI.setShowUpdateDialog(!noShow.value);
Navigator.pop(innerContext);
await showUpdateConfirmationDialog(context, isPatches);
},
child: I18nText('okButton'),
child: I18nText('showUpdateButton'),
),
],
),
@@ -271,120 +340,91 @@ class HomeViewModel extends BaseViewModel {
builder: (context) => ValueListenableBuilder(
valueListenable: downloaded,
builder: (context, value, child) {
return SimpleDialog(
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
contentPadding: const EdgeInsets.all(16.0),
return AlertDialog(
title: I18nText(
!value
? 'homeView.downloadingMessage'
: 'homeView.downloadedMessage',
child: Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
),
children: [
Column(
children: [
Row(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (!value)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.new_releases_outlined,
color: Theme.of(context).colorScheme.secondary,
StreamBuilder<double>(
initialData: 0.0,
stream: _revancedAPI.managerUpdateProgress.stream,
builder: (context, snapshot) {
return LinearProgressIndicator(
value: snapshot.data! * 0.01,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.secondary,
),
);
},
),
const SizedBox(width: 8.0),
Text(
'$_latestManagerVersion',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
const SizedBox(height: 16.0),
Align(
alignment: Alignment.centerRight,
child: FilledButton(
onPressed: () {
_revancedAPI.disposeManagerUpdateProgress();
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
),
),
],
),
const SizedBox(height: 16.0),
if (!value)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StreamBuilder<double>(
initialData: 0.0,
stream: _revancedAPI.managerUpdateProgress.stream,
builder: (context, snapshot) {
return LinearProgressIndicator(
value: snapshot.data! * 0.01,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.secondary,
),
);
},
),
const SizedBox(height: 16.0),
Align(
alignment: Alignment.centerRight,
child: FilledButton(
onPressed: () {
_revancedAPI.disposeManagerUpdateProgress();
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
if (value)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'homeView.installUpdate',
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
],
),
if (value)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'homeView.installUpdate',
child: Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
const SizedBox(height: 16.0),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
),
),
),
const SizedBox(height: 16.0),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
),
const SizedBox(width: 8.0),
Align(
alignment: Alignment.centerRight,
child: FilledButton(
onPressed: () async {
await _patcherAPI.installApk(
context,
downloadedApk!.path,
);
},
child: I18nText('updateButton'),
),
const SizedBox(width: 8.0),
Align(
alignment: Alignment.centerRight,
child: FilledButton(
onPressed: () async {
await _patcherAPI.installApk(
context,
downloadedApk!.path,
);
},
child: I18nText('updateButton'),
),
),
],
),
],
),
],
),
],
),
],
),
],
),
],
),
);
},
),
@@ -436,16 +476,18 @@ class HomeViewModel extends BaseViewModel {
Future<void> showUpdateConfirmationDialog(
BuildContext parentContext,
bool isPatches,
) {
bool isPatches, [
bool changelog = false,
]) {
return showModalBottomSheet(
context: parentContext,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24.0)),
),
builder: (context) => UpdateConfirmationDialog(
builder: (context) => UpdateConfirmationSheet(
isPatches: isPatches,
changelog: changelog,
),
);
}

View File

@@ -17,6 +17,8 @@ class InstallerView extends StatelessWidget {
onViewModelReady: (model) => model.initialize(context),
viewModelBuilder: () => InstallerViewModel(),
builder: (context, model, child) => PopScope(
onPopInvoked: (bool didPop) => model.onWillPop(context),
canPop: false,
child: SafeArea(
top: false,
bottom: model.isPatching,
@@ -112,7 +114,6 @@ class InstallerView extends StatelessWidget {
),
),
),
onPopInvoked: (bool didPop) => model.onWillPop(context),
),
);
}

View File

@@ -39,6 +39,15 @@ class SettingsViewModel extends BaseViewModel {
notifyListeners();
}
bool showUpdateDialog() {
return _managerAPI.showUpdateDialog();
}
void setShowUpdateDialog(bool value) {
_managerAPI.setShowUpdateDialog(value);
notifyListeners();
}
bool isPatchesChangeEnabled() {
return _managerAPI.isPatchesChangeEnabled();
}

View File

@@ -55,17 +55,15 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
FutureBuilder<bool>(
future: model.hasManagerUpdates(),
initialData: false,
builder: (context, snapshot) => Opacity(
opacity: snapshot.hasData && snapshot.data! ? 1.0 : 0.25,
child: FilledButton(
onPressed: snapshot.hasData && snapshot.data!
? () => widget.model.showUpdateConfirmationDialog(
widget.parentContext,
false,
)
: () => {},
child: I18nText('updateButton'),
builder: (context, snapshot) => FilledButton(
onPressed: () => widget.model.showUpdateConfirmationDialog(
widget.parentContext,
false,
!snapshot.data!,
),
child: (snapshot.hasData && !snapshot.data!)
? I18nText('showChangelogButton')
: I18nText('showUpdateButton'),
),
),
],
@@ -83,7 +81,7 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text('Patches'),
const Text('ReVanced Patches'),
const SizedBox(height: 4),
Row(
children: <Widget>[
@@ -108,19 +106,17 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
),
),
FutureBuilder<bool>(
future: locator<HomeViewModel>().hasPatchesUpdates(),
future: model.hasPatchesUpdates(),
initialData: false,
builder: (context, snapshot) => Opacity(
opacity: snapshot.hasData && snapshot.data! ? 1.0 : 0.25,
child: FilledButton(
onPressed: snapshot.hasData && snapshot.data!
? () => widget.model.showUpdateConfirmationDialog(
widget.parentContext,
true,
)
: () => {},
child: I18nText('updateButton'),
builder: (context, snapshot) => FilledButton(
onPressed: () => widget.model.showUpdateConfirmationDialog(
widget.parentContext,
true,
!snapshot.data!,
),
child: (snapshot.hasData && !snapshot.data!)
? I18nText('showChangelogButton')
: I18nText('showUpdateButton'),
),
),
],

View File

@@ -4,10 +4,11 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
class UpdateConfirmationDialog extends StatelessWidget {
const UpdateConfirmationDialog({super.key, required this.isPatches});
class UpdateConfirmationSheet extends StatelessWidget {
const UpdateConfirmationSheet({super.key, required this.isPatches, this.changelog = false});
final bool isPatches;
final bool changelog;
@override
Widget build(BuildContext context) {
final HomeViewModel model = locator<HomeViewModel>();
@@ -36,6 +37,7 @@ class UpdateConfirmationDialog extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!changelog)
Padding(
padding: const EdgeInsets.only(
top: 40.0,
@@ -51,8 +53,8 @@ class UpdateConfirmationDialog extends StatelessWidget {
children: [
I18nText(
isPatches
? 'homeView.updatePatchesDialogTitle'
: 'homeView.updateDialogTitle',
? 'homeView.updatePatchesSheetTitle'
: 'homeView.updateSheetTitle',
child: const Text(
'',
style: TextStyle(
@@ -98,7 +100,7 @@ class UpdateConfirmationDialog extends StatelessWidget {
),
),
Padding(
padding: const EdgeInsets.only(left: 24.0, bottom: 12.0),
padding: const EdgeInsets.only(top: 12.0, left: 24.0, bottom: 12.0),
child: I18nText(
'homeView.updateChangelogTitle',
child: Text(

View File

@@ -7,6 +7,7 @@ import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_pa
import 'package:revanced_manager/ui/widgets/settingsView/settings_enable_patches_selection.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_require_suggested_app_version.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_show_update_dialog.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_universal_patches.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_version_compatibility_check.dart';
@@ -19,6 +20,7 @@ class SAdvancedSection extends StatelessWidget {
title: 'settingsView.advancedSectionTitle',
children: const <Widget>[
SAutoUpdatePatches(),
SShowUpdateDialog(),
SEnablePatchesSelection(),
SRequireSuggestedAppVersion(),
SVersionCompatibilityCheck(),

View File

@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_switch_list_tile.dart';
class SShowUpdateDialog extends StatefulWidget {
const SShowUpdateDialog({super.key});
@override
State<SShowUpdateDialog> createState() => _SShowUpdateDialogState();
}
final _settingsViewModel = SettingsViewModel();
class _SShowUpdateDialogState extends State<SShowUpdateDialog> {
@override
Widget build(BuildContext context) {
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.showUpdateDialogLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
),
subtitle: I18nText('settingsView.showUpdateDialogHint'),
value: _settingsViewModel.showUpdateDialog(),
onChanged: (value) {
setState(() {
_settingsViewModel.setShowUpdateDialog(value);
});
},
);
}
}

288
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,11 @@
{
"devDependencies": {
"@droidsolutions-oss/semantic-release-update-file": "^1.3.2",
"@saithodev/semantic-release-backmerge": "^4.0.1",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"conventional-changelog-conventionalcommits": "^7.0.2",
"semantic-release": "^22.0.12"
}
}

View File

@@ -4,7 +4,7 @@ homepage: https://github.com/ReVanced/revanced-manager
publish_to: 'none'
version: 1.19.0-dev.2+101900002
version: 1.19.0-dev.6+101900006
environment:
sdk: '>=3.0.0 <4.0.0'