mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2026-01-19 09:13:57 +00:00
Compare commits
36 Commits
v1.21.0-de
...
v1.21.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65feb34242 | ||
|
|
23690a98df | ||
|
|
7449d4e318 | ||
|
|
c6f9e36f4b | ||
|
|
e9cee0abe2 | ||
|
|
9440f23b55 | ||
|
|
c67b4b438c | ||
|
|
1bdb820aed | ||
|
|
a28d77bc65 | ||
|
|
d60f9aa1d8 | ||
|
|
3209c0e430 | ||
|
|
7ef8f0454b | ||
|
|
232b702789 | ||
|
|
694f2a9fae | ||
|
|
77204087bb | ||
|
|
b26760b216 | ||
|
|
3c36950aeb | ||
|
|
bbeb836923 | ||
|
|
a99406f0a9 | ||
|
|
73368b58be | ||
|
|
ca14e77ba3 | ||
|
|
cafdfcda47 | ||
|
|
5c68d513a3 | ||
|
|
fc52560244 | ||
|
|
46f6a49a7a | ||
|
|
c13827e8e1 | ||
|
|
e0a6de2c2b | ||
|
|
afdba00722 | ||
|
|
9084c71aa3 | ||
|
|
8fc5fb6a80 | ||
|
|
5f762c5442 | ||
|
|
8b21ec1ea3 | ||
|
|
e83fbb864e | ||
|
|
f03af17f71 | ||
|
|
2c3e2e639f | ||
|
|
cc85b393dc |
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -70,7 +70,7 @@ body:
|
|||||||
|
|
||||||
Before creating a new bug report, please keep the following in mind:
|
Before creating a new bug report, please keep the following in mind:
|
||||||
|
|
||||||
- **Do not submit a duplicate bug report**: You can review existing bug reports [here](https://github.com/ReVanced/revanced-manager/labels/Bug%20report).
|
- **Do not submit a duplicate bug report**: Search for existing bug reports [here](https://github.com/ReVanced/revanced-manager/issues?q=label%3A%22Bug+report%22).
|
||||||
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-manager/blob/main/CONTRIBUTING.md).
|
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-manager/blob/main/CONTRIBUTING.md).
|
||||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -99,14 +99,14 @@ body:
|
|||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: ReVanced Manager logs
|
label: ReVanced Manager logs
|
||||||
description: Export logs in ReVanced Manager settings.
|
description: Export logs from the ReVanced Manager settings.
|
||||||
render: shell
|
render: shell
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Patch logs
|
label: Patch logs
|
||||||
description: Export logs in "Patcher" screen.
|
description: Export logs from the "Patcher" screen.
|
||||||
render: shell
|
render: shell
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
@@ -116,11 +116,11 @@ body:
|
|||||||
label: Acknowledgements
|
label: Acknowledgements
|
||||||
description: Your bug report will be closed if you don't follow the checklist below.
|
description: Your bug report will be closed if you don't follow the checklist below.
|
||||||
options:
|
options:
|
||||||
- label: This issue is not a duplicate of an existing bug report.
|
- label: I have checked all open and closed bug reports and this is not a duplicate.
|
||||||
required: true
|
required: true
|
||||||
- label: I have chosen an appropriate title.
|
- label: I have chosen an appropriate title.
|
||||||
required: true
|
required: true
|
||||||
- label: All requested information has been provided properly.
|
- label: All requested information has been provided properly.
|
||||||
required: true
|
required: true
|
||||||
- label: The bug is only related to ReVanced Manager
|
- label: The bug is only related to ReVanced Manager.
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
7
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
7
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -70,7 +70,7 @@ body:
|
|||||||
|
|
||||||
Before creating a new feature request, please keep the following in mind:
|
Before creating a new feature request, please keep the following in mind:
|
||||||
|
|
||||||
- **Do not submit a duplicate feature request**: You can review existing feature requests [here](https://github.com/ReVanced/revanced-manager//labels/Feature%20request).
|
- **Do not submit a duplicate feature request**: Search for existing feature requests [here](https://github.com/ReVanced/revanced-manager/issues?q=label%3A%22Feature+request%22).
|
||||||
- **Review the contribution guidelines**: Make sure your feature request adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-manager/blob/main/CONTRIBUTING.md).
|
- **Review the contribution guidelines**: Make sure your feature request adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-manager/blob/main/CONTRIBUTING.md).
|
||||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -79,7 +79,6 @@ body:
|
|||||||
description: |
|
description: |
|
||||||
- Describe your feature in detail
|
- Describe your feature in detail
|
||||||
- Add images, videos, links, examples, references, etc. if possible
|
- Add images, videos, links, examples, references, etc. if possible
|
||||||
- Add the target application name in case you request a new patch
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Motivation
|
label: Motivation
|
||||||
@@ -98,9 +97,9 @@ body:
|
|||||||
label: Acknowledgements
|
label: Acknowledgements
|
||||||
description: Your feature request will be closed if you don't follow the checklist below.
|
description: Your feature request will be closed if you don't follow the checklist below.
|
||||||
options:
|
options:
|
||||||
- label: This issue is not a duplicate of an existing feature request.
|
- label: I have checked all open and closed feature requests and this is not a duplicate.
|
||||||
required: true
|
required: true
|
||||||
- label: I have chosen an appropriate title.
|
- label: I have chosen an appropriate title.
|
||||||
required: true
|
required: true
|
||||||
- label: The feature request is only related to ReVanced Manager
|
- label: The feature request is only related to ReVanced Manager.
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
1
.github/workflows/build_pull_request.yml
vendored
1
.github/workflows/build_pull_request.yml
vendored
@@ -61,6 +61,7 @@ jobs:
|
|||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
flutter-version: 3.22.x
|
||||||
cache: ${{ inputs.flutter-cache }}
|
cache: ${{ inputs.flutter-cache }}
|
||||||
|
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
|
|||||||
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -36,9 +36,10 @@ jobs:
|
|||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
flutter-version: 3.22.x
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm install
|
run: npm ci
|
||||||
|
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
|
|||||||
12
.github/workflows/sync_crowdin.yml
vendored
12
.github/workflows/sync_crowdin.yml
vendored
@@ -5,6 +5,7 @@ on:
|
|||||||
schedule:
|
schedule:
|
||||||
- cron: 00 12 * * 1
|
- cron: 00 12 * * 1
|
||||||
push:
|
push:
|
||||||
|
branches: dev
|
||||||
paths:
|
paths:
|
||||||
- assets/i18n/*.json
|
- assets/i18n/*.json
|
||||||
- assets/i18n/*.dart
|
- assets/i18n/*.dart
|
||||||
@@ -20,8 +21,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup Dart
|
- name: Setup Flutter
|
||||||
uses: dart-lang/setup-dart@v1
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
cache: true
|
||||||
|
flutter-version: 3.22.x
|
||||||
|
|
||||||
- name: Sync translations from Crowdin
|
- name: Sync translations from Crowdin
|
||||||
uses: crowdin/github-action@v1
|
uses: crowdin/github-action@v1
|
||||||
@@ -51,7 +55,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Validation of Translation Strings
|
- name: Validation of Translation Strings
|
||||||
run: |
|
run: |
|
||||||
dart analyze lib/gen/strings.g.dart
|
dart pub get
|
||||||
|
dart run slang
|
||||||
|
flutter analyze lib/gen/strings.g.dart --no-fatal-infos --no-fatal-warnings
|
||||||
|
|
||||||
- name: Commit translations
|
- name: Commit translations
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Some of the features ReVanced Manager provides are:
|
|||||||
|
|
||||||
## 🔽 Download
|
## 🔽 Download
|
||||||
|
|
||||||
You can download the most recent version of ReVanced Manager at [revanced.app/download](https://revanced.app/download) or from [GitHub releases](https://github.com/ReVanced/revanced-manager/releases).
|
You can download the most recent version of ReVanced Manager at [revanced.app/download](https://revanced.app/download) or from [GitHub releases](https://github.com/ReVanced/revanced-manager/releases/latest).
|
||||||
Learn how to use ReVanced Manager by following the [documentation](/docs).
|
Learn how to use ReVanced Manager by following the [documentation](/docs).
|
||||||
|
|
||||||
## 📚 Everything else
|
## 📚 Everything else
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ if (flutterVersionName == null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk flutter.compileSdkVersion
|
compileSdk 34
|
||||||
ndkVersion flutter.ndkVersion
|
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
sourceCompatibility JavaVersion.VERSION_17
|
sourceCompatibility JavaVersion.VERSION_17
|
||||||
targetCompatibility JavaVersion.VERSION_17
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
@@ -113,6 +113,7 @@ flutter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") // https://pub.dev/packages/flutter_local_notifications#gradle-setup
|
||||||
implementation("app.revanced:revanced-patcher:19.3.1")
|
implementation("app.revanced:revanced-patcher:19.3.1")
|
||||||
implementation("app.revanced:revanced-library:2.2.1")
|
implementation("app.revanced:revanced-library:2.2.1")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
|
||||||
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
|
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version "8.1.2" apply false
|
id "com.android.application" version "8.4.1" apply false
|
||||||
id "org.jetbrains.kotlin.android" version "1.9.23" apply false
|
id "org.jetbrains.kotlin.android" version "2.0.0" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
include ":app"
|
include ":app"
|
||||||
|
|||||||
@@ -4,14 +4,10 @@
|
|||||||
"dismissButton": "Dismiss",
|
"dismissButton": "Dismiss",
|
||||||
"quitButton": "Quit",
|
"quitButton": "Quit",
|
||||||
"updateButton": "Update",
|
"updateButton": "Update",
|
||||||
"enabledLabel": "Enabled",
|
|
||||||
"disabledLabel": "Disabled",
|
|
||||||
"installed": "Installed: ${version}",
|
|
||||||
"suggested": "Suggested: ${version}",
|
"suggested": "Suggested: ${version}",
|
||||||
"yesButton": "Yes",
|
"yesButton": "Yes",
|
||||||
"noButton": "No",
|
"noButton": "No",
|
||||||
"warning": "Warning",
|
"warning": "Warning",
|
||||||
"options": "Options",
|
|
||||||
"notice": "Notice",
|
"notice": "Notice",
|
||||||
"noShowAgain": "Don't show this again",
|
"noShowAgain": "Don't show this again",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
@@ -27,10 +23,10 @@
|
|||||||
"refreshSuccess": "Refreshed successfully",
|
"refreshSuccess": "Refreshed successfully",
|
||||||
"widgetTitle": "Dashboard",
|
"widgetTitle": "Dashboard",
|
||||||
"updatesSubtitle": "Updates",
|
"updatesSubtitle": "Updates",
|
||||||
"patchedSubtitle": "Patched apps",
|
"lastPatchedAppSubtitle": "Last patched app",
|
||||||
|
"patchedSubtitle": "Installed apps",
|
||||||
"changeLaterSubtitle": "You can change this in the settings at a later time.",
|
"changeLaterSubtitle": "You can change this in the settings at a later time.",
|
||||||
"noUpdates": "No updates available",
|
"noSavedAppFound": "No app found",
|
||||||
"WIP": "Work in progress...",
|
|
||||||
"noInstallations": "No patched apps installed",
|
"noInstallations": "No patched apps installed",
|
||||||
"installUpdate": "Continue to install the update?",
|
"installUpdate": "Continue to install the update?",
|
||||||
"updateSheetTitle": "Update ReVanced Manager",
|
"updateSheetTitle": "Update ReVanced Manager",
|
||||||
@@ -41,27 +37,19 @@
|
|||||||
"downloadConsentDialogTitle": "Download necessary files?",
|
"downloadConsentDialogTitle": "Download necessary files?",
|
||||||
"downloadConsentDialogText": "ReVanced Manager needs to download necessary files to work properly.",
|
"downloadConsentDialogText": "ReVanced Manager needs to download necessary files to work properly.",
|
||||||
"downloadConsentDialogText2": "This will connect you to ${url}.",
|
"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...",
|
"downloadingMessage": "Downloading update...",
|
||||||
"downloadedMessage": "Update downloaded",
|
"downloadedMessage": "Update downloaded",
|
||||||
"installingMessage": "Installing update...",
|
"installingMessage": "Installing update...",
|
||||||
"errorDownloadMessage": "Unable to download update",
|
"errorDownloadMessage": "Unable to download update",
|
||||||
"errorInstallMessage": "Unable to install update",
|
"errorInstallMessage": "Unable to install update",
|
||||||
"noConnection": "No internet connection",
|
"noConnection": "No internet connection"
|
||||||
"updatesDisabled": "Updating a patched app is currently disabled. Repatch the app again."
|
|
||||||
},
|
},
|
||||||
"applicationItem": {
|
"applicationItem": {
|
||||||
"infoButton": "Info"
|
"infoButton": "Info"
|
||||||
},
|
},
|
||||||
"latestCommitCard": {
|
"latestCommitCard": {
|
||||||
"loadingLabel": "Loading...",
|
"loadingLabel": "Loading...",
|
||||||
"timeagoLabel": "${time} ago",
|
"timeagoLabel": "${time} ago"
|
||||||
"patcherLabel": "Patcher: ",
|
|
||||||
"managerLabel": "Manager: ",
|
|
||||||
"updateButton": "Update Manager"
|
|
||||||
},
|
},
|
||||||
"patcherView": {
|
"patcherView": {
|
||||||
"widgetTitle": "Patcher",
|
"widgetTitle": "Patcher",
|
||||||
@@ -75,8 +63,6 @@
|
|||||||
"widgetTitleSelected": "Selected app",
|
"widgetTitleSelected": "Selected app",
|
||||||
"widgetSubtitle": "No app selected",
|
"widgetSubtitle": "No app selected",
|
||||||
"noAppsLabel": "No applications found",
|
"noAppsLabel": "No applications found",
|
||||||
"currentVersion": "Current",
|
|
||||||
"suggestedVersion": "Suggested",
|
|
||||||
"anyVersion": "Any version"
|
"anyVersion": "Any version"
|
||||||
},
|
},
|
||||||
"patchSelectorCard": {
|
"patchSelectorCard": {
|
||||||
@@ -118,16 +104,15 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Custom value",
|
"customValue": "Custom value",
|
||||||
"resetOptionsTooltip": "Reset patch options",
|
"setToNull": "Set to null",
|
||||||
|
"nullValue": "This option value is currently null",
|
||||||
"viewTitle": "Patch options",
|
"viewTitle": "Patch options",
|
||||||
"saveOptions": "Save",
|
"saveOptions": "Save",
|
||||||
"addOptions": "Add options",
|
"unselectPatch": "Unselect patch",
|
||||||
"deselectPatch": "Deselect patch",
|
|
||||||
"tooltip": "More input options",
|
"tooltip": "More input options",
|
||||||
"selectFilePath": "Select file path",
|
"selectFilePath": "Select file path",
|
||||||
"selectFolder": "Select folder",
|
"selectFolder": "Select folder",
|
||||||
"selectOption": "Select option",
|
"requiredOption": "Setting this option is required",
|
||||||
"requiredOption": "This option is required",
|
|
||||||
"unsupportedOption": "This option is not supported",
|
"unsupportedOption": "This option is not supported",
|
||||||
"requiredOptionNull": "The following options have to be set:\n\n${options}"
|
"requiredOptionNull": "The following options have to be set:\n\n${options}"
|
||||||
},
|
},
|
||||||
@@ -139,7 +124,6 @@
|
|||||||
"patchesChangeWarningDialogButton": "Use default selection"
|
"patchesChangeWarningDialogButton": "Use default selection"
|
||||||
},
|
},
|
||||||
"installerView": {
|
"installerView": {
|
||||||
"widgetTitle": "Installer",
|
|
||||||
"installType": "Select install type",
|
"installType": "Select install type",
|
||||||
"installTypeDescription": "Select the installation type to continue with.",
|
"installTypeDescription": "Select the installation type to continue with.",
|
||||||
"installButton": "Install",
|
"installButton": "Install",
|
||||||
@@ -148,7 +132,6 @@
|
|||||||
"warning": "Disable auto updates for the patched app to avoid unexpected issues.",
|
"warning": "Disable auto updates for the patched app to avoid unexpected issues.",
|
||||||
"pressBackAgain": "Press back again to cancel",
|
"pressBackAgain": "Press back again to cancel",
|
||||||
"openButton": "Open",
|
"openButton": "Open",
|
||||||
"shareButton": "Share file",
|
|
||||||
"notificationTitle": "ReVanced Manager is patching",
|
"notificationTitle": "ReVanced Manager is patching",
|
||||||
"notificationText": "Tap to return to the installer",
|
"notificationText": "Tap to return to the installer",
|
||||||
"exportApkButtonTooltip": "Export patched APK",
|
"exportApkButtonTooltip": "Export patched APK",
|
||||||
@@ -173,7 +156,6 @@
|
|||||||
"dynamicThemeHint": "Enjoy an experience closer to your device",
|
"dynamicThemeHint": "Enjoy an experience closer to your device",
|
||||||
"languageLabel": "Language",
|
"languageLabel": "Language",
|
||||||
"languageUpdated": "Language updated",
|
"languageUpdated": "Language updated",
|
||||||
"englishOption": "English",
|
|
||||||
"sourcesLabel": "Alternative sources",
|
"sourcesLabel": "Alternative sources",
|
||||||
"sourcesLabelHint": "Configure the alternative sources for ReVanced Patches and ReVanced Integrations",
|
"sourcesLabelHint": "Configure the alternative sources for ReVanced Patches and ReVanced Integrations",
|
||||||
"sourcesIntegrationsLabel": "Integrations source",
|
"sourcesIntegrationsLabel": "Integrations source",
|
||||||
@@ -203,6 +185,8 @@
|
|||||||
"showUpdateDialogHint": "Show a dialog when a new update is available",
|
"showUpdateDialogHint": "Show a dialog when a new update is available",
|
||||||
"universalPatchesLabel": "Show universal patches",
|
"universalPatchesLabel": "Show universal patches",
|
||||||
"universalPatchesHint": "Display all apps and universal patches (may slow down the app list)",
|
"universalPatchesHint": "Display all apps and universal patches (may slow down the app list)",
|
||||||
|
"lastPatchedAppLabel": "Save patched app",
|
||||||
|
"lastPatchedAppHint": "Save the last patch to install or export later",
|
||||||
"versionCompatibilityCheckLabel": "Version compatibility check",
|
"versionCompatibilityCheckLabel": "Version compatibility check",
|
||||||
"versionCompatibilityCheckHint": "Prevent selecting patches that are not compatible with the selected app version",
|
"versionCompatibilityCheckHint": "Prevent selecting patches that are not compatible with the selected app version",
|
||||||
"requireSuggestedAppVersionLabel": "Require suggested app version",
|
"requireSuggestedAppVersionLabel": "Require suggested app version",
|
||||||
@@ -254,18 +238,25 @@
|
|||||||
"appInfoView": {
|
"appInfoView": {
|
||||||
"widgetTitle": "App info",
|
"widgetTitle": "App info",
|
||||||
"openButton": "Open",
|
"openButton": "Open",
|
||||||
|
"installButton": "Install",
|
||||||
"uninstallButton": "Uninstall",
|
"uninstallButton": "Uninstall",
|
||||||
"unmountButton": "Unmount",
|
"unmountButton": "Unmount",
|
||||||
|
"exportButton": "Export",
|
||||||
|
"deleteButton": "Delete",
|
||||||
"rootDialogTitle": "Error",
|
"rootDialogTitle": "Error",
|
||||||
|
"lastPatchedAppDescription": "This is a backup of the app that was last patched.",
|
||||||
"unmountDialogText": "Are you sure you want to unmount this app?",
|
"unmountDialogText": "Are you sure you want to unmount this app?",
|
||||||
"uninstallDialogText": "Are you sure you want to uninstall this app?",
|
"uninstallDialogText": "Are you sure you want to uninstall this app?",
|
||||||
"rootDialogText": "App was installed with superuser permissions, but currently ReVanced Manager has no permissions.\nPlease grant superuser permissions first.",
|
"rootDialogText": "App was installed with superuser permissions, but currently ReVanced Manager has no permissions.\nPlease grant superuser permissions first.",
|
||||||
|
"removeAppDialogTitle": "Delete app?",
|
||||||
|
"removeAppDialogText": "Are you sure you want to delete this backup?",
|
||||||
"packageNameLabel": "Package name",
|
"packageNameLabel": "Package name",
|
||||||
"installTypeLabel": "Installation type",
|
"installTypeLabel": "Installation type",
|
||||||
"mountTypeLabel": "Mount",
|
"mountTypeLabel": "Mount",
|
||||||
"regularTypeLabel": "Regular",
|
"regularTypeLabel": "Regular",
|
||||||
"patchedDateLabel": "Patched date",
|
"patchedDateLabel": "Patched date",
|
||||||
"appliedPatchesLabel": "Applied patches",
|
"appliedPatchesLabel": "Applied patches",
|
||||||
|
"sizeLabel": "File size",
|
||||||
"patchedDateHint": "${date} at ${time}",
|
"patchedDateHint": "${date} at ${time}",
|
||||||
"appliedPatchesHint": "${quantity} applied patches",
|
"appliedPatchesHint": "${quantity} applied patches",
|
||||||
"updateNotImplemented": "This feature has not been implemented yet"
|
"updateNotImplemented": "This feature has not been implemented yet"
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "تخصيص القيمة",
|
"customValue": "تخصيص القيمة",
|
||||||
|
"setToNull": "تعيين إلى فارغ",
|
||||||
|
"nullValue": "قيمة هذا الخيار فارغة حاليا",
|
||||||
"resetOptionsTooltip": "إعادة تعيين خيارات التعديل",
|
"resetOptionsTooltip": "إعادة تعيين خيارات التعديل",
|
||||||
"viewTitle": "خيارات التعديل",
|
"viewTitle": "خيارات التعديل",
|
||||||
"saveOptions": "حفظ",
|
"saveOptions": "حفظ",
|
||||||
"addOptions": "إضافة خيارات",
|
"addOptions": "إضافة خيارات",
|
||||||
"deselectPatch": "إلغاء تحديد التعديل",
|
"unselectPatch": "إلغاء تحديد التصحيح",
|
||||||
"tooltip": "المزيد من خيارات الإدخال",
|
"tooltip": "المزيد من خيارات الإدخال",
|
||||||
"selectFilePath": "تحديد مسار الملف",
|
"selectFilePath": "تحديد مسار الملف",
|
||||||
"selectFolder": "تحديد مجلد",
|
"selectFolder": "تحديد مجلد",
|
||||||
"selectOption": "تحديد خيار",
|
"selectOption": "تحديد خيار",
|
||||||
"requiredOption": "هذا الخيار مطلوب",
|
"requiredOption": "إعداد هذا الخيار مطلوب",
|
||||||
"unsupportedOption": "هذا الخيار غير مدعوم",
|
"unsupportedOption": "هذا الخيار غير مدعوم",
|
||||||
"requiredOptionNull": "يجب تعيين الخيارات التالية:\n\n${options}"
|
"requiredOptionNull": "يجب تعيين الخيارات التالية:\n\n${options}"
|
||||||
},
|
},
|
||||||
@@ -143,7 +145,7 @@
|
|||||||
"installType": "تحديد نوع التثبيت",
|
"installType": "تحديد نوع التثبيت",
|
||||||
"installTypeDescription": "تحديد نوع التثبيت للمتابعة.",
|
"installTypeDescription": "تحديد نوع التثبيت للمتابعة.",
|
||||||
"installButton": "تثبيت",
|
"installButton": "تثبيت",
|
||||||
"installRootType": "تحميل",
|
"installRootType": "Mount",
|
||||||
"installNonRootType": "عادي",
|
"installNonRootType": "عادي",
|
||||||
"warning": "قم بتعطيل التحديثات التلقائية للتطبيق المعدل لتجنب المشكلات غير المتوقعة.",
|
"warning": "قم بتعطيل التحديثات التلقائية للتطبيق المعدل لتجنب المشكلات غير المتوقعة.",
|
||||||
"pressBackAgain": "اضغط رجوع مرة اخرى للإلغاء",
|
"pressBackAgain": "اضغط رجوع مرة اخرى للإلغاء",
|
||||||
@@ -255,14 +257,14 @@
|
|||||||
"widgetTitle": "معلومات التطبيق",
|
"widgetTitle": "معلومات التطبيق",
|
||||||
"openButton": "فتح",
|
"openButton": "فتح",
|
||||||
"uninstallButton": "إلغاء التثبيت",
|
"uninstallButton": "إلغاء التثبيت",
|
||||||
"unmountButton": "إلغاء التحميل",
|
"unmountButton": "Unmount",
|
||||||
"rootDialogTitle": "خطأ",
|
"rootDialogTitle": "خطأ",
|
||||||
"unmountDialogText": "هل أنت متأكد أنك تريد إلغاء تحميل هذا التطبيق؟",
|
"unmountDialogText": "هل أنت متأكد من أنك تريد Unmount لهذا التطبيق؟",
|
||||||
"uninstallDialogText": "هل أنت متأكد من أنك تريد إلغاء تثبيت هذا التطبيق؟",
|
"uninstallDialogText": "هل أنت متأكد من أنك تريد إلغاء تثبيت هذا التطبيق؟",
|
||||||
"rootDialogText": "تم تثبيت التطبيق بأذونات المستخدم المتميز، لكن ReVanced Manager ليس لديه أذونات حاليًا.\nالرجاء منح أذونات المستخدم المتميز أولاً.",
|
"rootDialogText": "تم تثبيت التطبيق بأذونات المستخدم المتميز، لكن ReVanced Manager ليس لديه أذونات حاليًا.\nالرجاء منح أذونات المستخدم المتميز أولاً.",
|
||||||
"packageNameLabel": "اسم الحُزْمَة",
|
"packageNameLabel": "اسم الحُزْمَة",
|
||||||
"installTypeLabel": "نوع التثبيت",
|
"installTypeLabel": "نوع التثبيت",
|
||||||
"mountTypeLabel": "تحميل",
|
"mountTypeLabel": "Mount",
|
||||||
"regularTypeLabel": "عادي",
|
"regularTypeLabel": "عادي",
|
||||||
"patchedDateLabel": "تاريخ التعديل",
|
"patchedDateLabel": "تاريخ التعديل",
|
||||||
"appliedPatchesLabel": "التعديلات المطبقة",
|
"appliedPatchesLabel": "التعديلات المطبقة",
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Vlastní hodnota",
|
"customValue": "Vlastní hodnota",
|
||||||
|
"setToNull": "Nastavit na null",
|
||||||
|
"nullValue": "Tato hodnota volby je v současné době null",
|
||||||
"resetOptionsTooltip": "Obnovit nastavení záplat",
|
"resetOptionsTooltip": "Obnovit nastavení záplat",
|
||||||
"viewTitle": "Nastavení záplat",
|
"viewTitle": "Nastavení záplat",
|
||||||
"saveOptions": "Uložit",
|
"saveOptions": "Uložit",
|
||||||
"addOptions": "Přidat možnosti",
|
"addOptions": "Přidat možnosti",
|
||||||
"deselectPatch": "Odznačit záplatu",
|
"unselectPatch": "Zrušit výběr patch",
|
||||||
"tooltip": "Další možnosti vstupu",
|
"tooltip": "Další možnosti vstupu",
|
||||||
"selectFilePath": "Zvolte cestu k souboru",
|
"selectFilePath": "Zvolte cestu k souboru",
|
||||||
"selectFolder": "Vybrat složku",
|
"selectFolder": "Vybrat složku",
|
||||||
"selectOption": "Vybrat možnost",
|
"selectOption": "Vybrat možnost",
|
||||||
"requiredOption": "Tato možnost je vyžadována",
|
"requiredOption": "Nastavení této možnosti je vyžadováno",
|
||||||
"unsupportedOption": "Tato možnost není podporována",
|
"unsupportedOption": "Tato možnost není podporována",
|
||||||
"requiredOptionNull": "Tyto možnosti musí být nastaveny:\n\n${options}"
|
"requiredOptionNull": "Tyto možnosti musí být nastaveny:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Tilpasset værdi",
|
"customValue": "Tilpasset værdi",
|
||||||
|
"setToNull": "Sæt til nul",
|
||||||
|
"nullValue": "Denne valgmulighed værdi er i øjeblikket nul",
|
||||||
"resetOptionsTooltip": "Nulstil patch indstillinger",
|
"resetOptionsTooltip": "Nulstil patch indstillinger",
|
||||||
"viewTitle": "Patch indstillinger",
|
"viewTitle": "Patch indstillinger",
|
||||||
"saveOptions": "Gem",
|
"saveOptions": "Gem",
|
||||||
"addOptions": "Tilføj indstillinger",
|
"addOptions": "Tilføj indstillinger",
|
||||||
"deselectPatch": "Fravælg patch",
|
"unselectPatch": "Fravælg patch",
|
||||||
"tooltip": "Flere input-indstillinger",
|
"tooltip": "Flere input-indstillinger",
|
||||||
"selectFilePath": "Vælg fil sti",
|
"selectFilePath": "Vælg fil sti",
|
||||||
"selectFolder": "Vælg mappe",
|
"selectFolder": "Vælg mappe",
|
||||||
"selectOption": "Vælg indstilling",
|
"selectOption": "Vælg indstilling",
|
||||||
"requiredOption": "Denne indstilling er påkrævet",
|
"requiredOption": "Indstilling af denne indstilling er påkrævet",
|
||||||
"unsupportedOption": "Denne indstilling understøttes ikke",
|
"unsupportedOption": "Denne indstilling understøttes ikke",
|
||||||
"requiredOptionNull": "Følgende indstillinger skal indstilles:\n\n${options}"
|
"requiredOptionNull": "Følgende indstillinger skal indstilles:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Benutzerdefinierter Wert",
|
"customValue": "Benutzerdefinierter Wert",
|
||||||
|
"setToNull": "Auf Null setzen",
|
||||||
|
"nullValue": "Dieser Optionswert ist derzeit null",
|
||||||
"resetOptionsTooltip": "Patch-Optionen zurücksetzen",
|
"resetOptionsTooltip": "Patch-Optionen zurücksetzen",
|
||||||
"viewTitle": "Patch-Optionen",
|
"viewTitle": "Patch-Optionen",
|
||||||
"saveOptions": "Speichern",
|
"saveOptions": "Speichern",
|
||||||
"addOptions": "Option hinzufügen",
|
"addOptions": "Option hinzufügen",
|
||||||
"deselectPatch": "Patch abwählen",
|
"unselectPatch": "Patch entfernen",
|
||||||
"tooltip": "Weitere Eingabeoptionen",
|
"tooltip": "Weitere Eingabeoptionen",
|
||||||
"selectFilePath": "Dateipfad auswählen",
|
"selectFilePath": "Dateipfad auswählen",
|
||||||
"selectFolder": "Ordner auswählen",
|
"selectFolder": "Ordner auswählen",
|
||||||
"selectOption": "Option auswählen",
|
"selectOption": "Option auswählen",
|
||||||
"requiredOption": "Diese Option ist erforderlich.",
|
"requiredOption": "Einstellung dieser Option ist erforderlich",
|
||||||
"unsupportedOption": "Dieser Vorgang ist nicht unterstützt.",
|
"unsupportedOption": "Dieser Vorgang ist nicht unterstützt.",
|
||||||
"requiredOptionNull": "Die folgenden Optionen müssen gesetzt sein:\n\n${options}"
|
"requiredOptionNull": "Die folgenden Optionen müssen gesetzt sein:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Προσαρμοσμένη τιμή",
|
"customValue": "Προσαρμοσμένη τιμή",
|
||||||
|
"setToNull": "Ορισμός σε null",
|
||||||
|
"nullValue": "Αυτή η επιλογή είναι κενή",
|
||||||
"resetOptionsTooltip": "Επαναφορά επιλογών τροποποιήσεων",
|
"resetOptionsTooltip": "Επαναφορά επιλογών τροποποιήσεων",
|
||||||
"viewTitle": "Επιλογές τροποποιήσεων",
|
"viewTitle": "Επιλογές τροποποιήσεων",
|
||||||
"saveOptions": "Αποθήκευση",
|
"saveOptions": "Αποθήκευση",
|
||||||
"addOptions": "Προσθήκη επιλογών",
|
"addOptions": "Προσθήκη επιλογών",
|
||||||
"deselectPatch": "Αποεπιλέξτε τροποποιήσεις",
|
"unselectPatch": "Αποεπιλογή patch",
|
||||||
"tooltip": "Περισσότερες επιλογές εισόδου",
|
"tooltip": "Περισσότερες επιλογές εισόδου",
|
||||||
"selectFilePath": "Επιλογή τοποθεσίας αρχείου",
|
"selectFilePath": "Επιλογή τοποθεσίας αρχείου",
|
||||||
"selectFolder": "Επιλογή φακέλου",
|
"selectFolder": "Επιλογή φακέλου",
|
||||||
"selectOption": "Επιλογή ρύθμισης",
|
"selectOption": "Επιλογή ρύθμισης",
|
||||||
"requiredOption": "Αυτή η επιλογή απαιτείται",
|
"requiredOption": "Απαιτείται ρύθμιση αυτής της επιλογής",
|
||||||
"unsupportedOption": "Αυτή η επιλογή δεν υποστηρίζεται",
|
"unsupportedOption": "Αυτή η επιλογή δεν υποστηρίζεται",
|
||||||
"requiredOptionNull": "Πρέπει να οριστούν οι παρακάτω επιλογές:\n\n${options}"
|
"requiredOptionNull": "Πρέπει να οριστούν οι παρακάτω επιλογές:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Valor personalizado",
|
"customValue": "Valor personalizado",
|
||||||
|
"setToNull": "Establecer a nulo",
|
||||||
|
"nullValue": "Este valor de opción es nulo actualmente",
|
||||||
"resetOptionsTooltip": "Restablecer a los valores por defecto",
|
"resetOptionsTooltip": "Restablecer a los valores por defecto",
|
||||||
"viewTitle": "Configuración\\ndel parche",
|
"viewTitle": "Configuración\\ndel parche",
|
||||||
"saveOptions": "Guardar configuración",
|
"saveOptions": "Guardar configuración",
|
||||||
"addOptions": "Agregar configuración",
|
"addOptions": "Agregar configuración",
|
||||||
"deselectPatch": "Deseleccionar parche",
|
"unselectPatch": "Deseleccionar parche",
|
||||||
"tooltip": "Más opciones de entrada",
|
"tooltip": "Más opciones de entrada",
|
||||||
"selectFilePath": "Seleccionar ruta del archivo",
|
"selectFilePath": "Seleccionar ruta del archivo",
|
||||||
"selectFolder": "Seleccionar carpeta",
|
"selectFolder": "Seleccionar carpeta",
|
||||||
"selectOption": "Seleccionar opción",
|
"selectOption": "Seleccionar opción",
|
||||||
"requiredOption": "Esta opción es requerida",
|
"requiredOption": "La configuración de esta opción es necesaria",
|
||||||
"unsupportedOption": "Esta opción no es compatible",
|
"unsupportedOption": "Esta opción no es compatible",
|
||||||
"requiredOptionNull": "Tenés que configurar las siguientes opciones:\\n\\n${options}"
|
"requiredOptionNull": "Tenés que configurar las siguientes opciones:\\n\\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Valor personalizado",
|
"customValue": "Valor personalizado",
|
||||||
|
"setToNull": "Establecer a nulo",
|
||||||
|
"nullValue": "Este valor de opción es nulo actualmente",
|
||||||
"resetOptionsTooltip": "Restablecer las opciones de parche",
|
"resetOptionsTooltip": "Restablecer las opciones de parche",
|
||||||
"viewTitle": "Opciones de parche",
|
"viewTitle": "Opciones de parche",
|
||||||
"saveOptions": "Guardar",
|
"saveOptions": "Guardar",
|
||||||
"addOptions": "Añadir opciones",
|
"addOptions": "Añadir opciones",
|
||||||
"deselectPatch": "Deseleccionar parche",
|
"unselectPatch": "Deseleccionar parche",
|
||||||
"tooltip": "Más opciones de entrada",
|
"tooltip": "Más opciones de entrada",
|
||||||
"selectFilePath": "Seleccionar ruta del archivo",
|
"selectFilePath": "Seleccionar ruta del archivo",
|
||||||
"selectFolder": "Seleccionar carpeta",
|
"selectFolder": "Seleccionar carpeta",
|
||||||
"selectOption": "Seleccionar opción",
|
"selectOption": "Seleccionar opción",
|
||||||
"requiredOption": "Esta opción es necesaria",
|
"requiredOption": "La configuración de esta opción es necesaria",
|
||||||
"unsupportedOption": "Esta opción no está disponible",
|
"unsupportedOption": "Esta opción no está disponible",
|
||||||
"requiredOptionNull": "Hay que establecer las siguientes opciones:\n\n${options}"
|
"requiredOptionNull": "Hay que establecer las siguientes opciones:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
"downloadConsentDialogTitle": "¿Descargar archivos necesarios?",
|
"downloadConsentDialogTitle": "¿Descargar archivos necesarios?",
|
||||||
"downloadConsentDialogText": "ReVanced Manager necesita descargar los archivos necesarios para funcionar correctamente.",
|
"downloadConsentDialogText": "ReVanced Manager necesita descargar los archivos necesarios para funcionar correctamente.",
|
||||||
"downloadConsentDialogText2": "Esto te conectará a ${url}.",
|
"downloadConsentDialogText2": "Esto te conectará a ${url}.",
|
||||||
"checkUpdateDialogTitle": "¿Buscar actualizaciones?",
|
"checkUpdateDialogTitle": "¿Comprobar actualizaciones?",
|
||||||
"checkUpdateDialogText": "¿Quieres que ReVanced Manager compruebe si hay actualizaciones automáticamente?",
|
"checkUpdateDialogText": "¿Quieres que ReVanced Manager compruebe si hay actualizaciones automáticamente?",
|
||||||
"notificationTitle": "Actualización descargada",
|
"notificationTitle": "Actualización descargada",
|
||||||
"notificationText": "Toca para instalar la actualización",
|
"notificationText": "Toca para instalar la actualización",
|
||||||
@@ -91,14 +91,14 @@
|
|||||||
},
|
},
|
||||||
"appSelectorView": {
|
"appSelectorView": {
|
||||||
"viewTitle": "Seleccionar una aplicación",
|
"viewTitle": "Seleccionar una aplicación",
|
||||||
"searchBarHint": "Buscar app",
|
"searchBarHint": "Buscar aplicación",
|
||||||
"storageButton": "Almacenamiento",
|
"storageButton": "Almacenamiento",
|
||||||
"selectFromStorageButton": "Seleccionar desde almacenamiento",
|
"selectFromStorageButton": "Seleccionar desde almacenamiento",
|
||||||
"errorMessage": "No se puede usar la aplicación seleccionada",
|
"errorMessage": "No se puede usar la aplicación seleccionada",
|
||||||
"downloadToast": "La función de descarga aún no está disponible",
|
"downloadToast": "La función de descarga aún no está disponible",
|
||||||
"requireSuggestedAppVersionDialogText": "La versión de la aplicación que has seleccionado no coincide con la versión sugerida, lo que podría causar errores inesperados. Por favor, utiliza la versión sugerida.\n\nVersión seleccionada: ${selected}\nVersión sugerida: ${suggested}\n\nPara continuar de todas formas, desactiva \"Requerir versión sugerida de la aplicación\" en la configuración.",
|
"requireSuggestedAppVersionDialogText": "La versión de la aplicación que has seleccionado no coincide con la versión sugerida, lo que podría causar errores inesperados. Por favor, utiliza la versión sugerida.\n\nVersión seleccionada: ${selected}\nVersión sugerida: ${suggested}\n\nPara continuar de todas formas, desactiva \"Requerir versión sugerida de la aplicación\" en la configuración.",
|
||||||
"featureNotAvailable": "Característica no implementada",
|
"featureNotAvailable": "Característica no implementada",
|
||||||
"featureNotAvailableText": "Esta aplicación es un APK dividido y solo puede ser parcheada e instalada de forma fiable mediante el montaje con permisos de root. Sin embargo, puedes parchear e instalar un APK completo seleccionándolo del almacenamiento."
|
"featureNotAvailableText": "Esta aplicación es una APK dividida y solo puede ser parcheada e instalada confiablemente al montar con permisos de root. Sin embargo, puedes parchear e instalar una APK completa seleccionándola en el almacenamiento."
|
||||||
},
|
},
|
||||||
"patchesSelectorView": {
|
"patchesSelectorView": {
|
||||||
"viewTitle": "Selecciona parches",
|
"viewTitle": "Selecciona parches",
|
||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Valor personalizado",
|
"customValue": "Valor personalizado",
|
||||||
|
"setToNull": "Establecer a nulo",
|
||||||
|
"nullValue": "Este valor de opción es nulo actualmente",
|
||||||
"resetOptionsTooltip": "Restablecer las opciones de parche",
|
"resetOptionsTooltip": "Restablecer las opciones de parche",
|
||||||
"viewTitle": "Opciones de parche",
|
"viewTitle": "Opciones de parche",
|
||||||
"saveOptions": "Guardar",
|
"saveOptions": "Guardar",
|
||||||
"addOptions": "Añadir opciones",
|
"addOptions": "Añadir opciones",
|
||||||
"deselectPatch": "Deseleccionar parche",
|
"unselectPatch": "Deseleccionar parche",
|
||||||
"tooltip": "Más opciones de entrada",
|
"tooltip": "Más opciones de entrada",
|
||||||
"selectFilePath": "Selecciona la ruta del archivo",
|
"selectFilePath": "Selecciona la ruta del archivo",
|
||||||
"selectFolder": "Selecciona la carpeta",
|
"selectFolder": "Selecciona la carpeta",
|
||||||
"selectOption": "Seleccionar opción",
|
"selectOption": "Seleccionar opción",
|
||||||
"requiredOption": "Esta opción es requerida",
|
"requiredOption": "La configuración de esta opción es necesaria",
|
||||||
"unsupportedOption": "Esta opción no está disponible",
|
"unsupportedOption": "Esta opción no está disponible",
|
||||||
"requiredOptionNull": "Hay que configurar las siguientes opciones:\n\n${options}"
|
"requiredOptionNull": "Hay que configurar las siguientes opciones:\n\n${options}"
|
||||||
},
|
},
|
||||||
@@ -196,7 +198,7 @@
|
|||||||
"enablePatchesSelectionLabel": "Permitir cambiar la selección de parches",
|
"enablePatchesSelectionLabel": "Permitir cambiar la selección de parches",
|
||||||
"enablePatchesSelectionHint": "No prevenir la selección o deselección de parches",
|
"enablePatchesSelectionHint": "No prevenir la selección o deselección de parches",
|
||||||
"enablePatchesSelectionWarningText": "Cambiar la selección de parches puede cauar problemas inespereados.\n\n¿Quieres activarlo de todas formas?",
|
"enablePatchesSelectionWarningText": "Cambiar la selección de parches puede cauar problemas inespereados.\n\n¿Quieres activarlo de todas formas?",
|
||||||
"disablePatchesSelectionWarningText": "Estás a punto de desactivar cambiar la selección de parches.\nLa selección predeterminada de parches se restaurará.\n\n¿Deshabilitar de todos modos?",
|
"disablePatchesSelectionWarningText": "Estás a punto de desactivar cambiar la selección de los parches.\nLa selección predeterminada de los parches será restaurada.\n\n¿Desactivar de todos modos?",
|
||||||
"autoUpdatePatchesLabel": "Actualizar parches automáticamente",
|
"autoUpdatePatchesLabel": "Actualizar parches automáticamente",
|
||||||
"autoUpdatePatchesHint": "Actualiza los parches a la última versión automáticamente",
|
"autoUpdatePatchesHint": "Actualiza los parches a la última versión automáticamente",
|
||||||
"showUpdateDialogLabel": "Mostrar diálogo de actualización",
|
"showUpdateDialogLabel": "Mostrar diálogo de actualización",
|
||||||
@@ -252,7 +254,7 @@
|
|||||||
"keystoreSelectorErrorMessage": "No se puede utilizar el archivo de repositorio de claves seleccionado"
|
"keystoreSelectorErrorMessage": "No se puede utilizar el archivo de repositorio de claves seleccionado"
|
||||||
},
|
},
|
||||||
"appInfoView": {
|
"appInfoView": {
|
||||||
"widgetTitle": "Informacion de la applicacion",
|
"widgetTitle": "Informacion de la aplicación",
|
||||||
"openButton": "Abrir",
|
"openButton": "Abrir",
|
||||||
"uninstallButton": "Desinstalar",
|
"uninstallButton": "Desinstalar",
|
||||||
"unmountButton": "Desmontar",
|
"unmountButton": "Desmontar",
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Oma arvo",
|
"customValue": "Oma arvo",
|
||||||
|
"setToNull": "Aseta tyhjäksi",
|
||||||
|
"nullValue": "Tämä valinta arvo on tällä hetkellä nolla",
|
||||||
"resetOptionsTooltip": "Palauta paikkausasetukset",
|
"resetOptionsTooltip": "Palauta paikkausasetukset",
|
||||||
"viewTitle": "Paikkausasetukset",
|
"viewTitle": "Paikkausasetukset",
|
||||||
"saveOptions": "Tallenna",
|
"saveOptions": "Tallenna",
|
||||||
"addOptions": "Lisää asetuksia",
|
"addOptions": "Lisää asetuksia",
|
||||||
"deselectPatch": "Poista paikkauksen valinta",
|
"unselectPatch": "Peru korjauksen valinta",
|
||||||
"tooltip": "Enemmän syöteasetuksia",
|
"tooltip": "Enemmän syöteasetuksia",
|
||||||
"selectFilePath": "Valitse tiedostosijainti",
|
"selectFilePath": "Valitse tiedostosijainti",
|
||||||
"selectFolder": "Valitse kansio",
|
"selectFolder": "Valitse kansio",
|
||||||
"selectOption": "Valitse asetus",
|
"selectOption": "Valitse asetus",
|
||||||
"requiredOption": "Tämä asetus vaaditaan",
|
"requiredOption": "Tämän asetuksen asettaminen on pakollinen",
|
||||||
"unsupportedOption": "Tätä asetusta ei tueta",
|
"unsupportedOption": "Tätä asetusta ei tueta",
|
||||||
"requiredOptionNull": "Seuraavat asetukset on määritettävä:\n\n${options}"
|
"requiredOptionNull": "Seuraavat asetukset on määritettävä:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"updatesSubtitle": "Mises à jour",
|
"updatesSubtitle": "Mises à jour",
|
||||||
"patchedSubtitle": "Applications patchées",
|
"patchedSubtitle": "Applications patchées",
|
||||||
"changeLaterSubtitle": "Vous pouvez changer cela dans les paramètres ultérieurement.",
|
"changeLaterSubtitle": "Vous pouvez changer cela dans les paramètres ultérieurement.",
|
||||||
"noUpdates": "Aucune mise à jour n'est disponible",
|
"noUpdates": "Aucune mise à jour disponible",
|
||||||
"WIP": "Bientôt disponible...",
|
"WIP": "Bientôt disponible...",
|
||||||
"noInstallations": "Aucune application patchée installée",
|
"noInstallations": "Aucune application patchée installée",
|
||||||
"installUpdate": "Continuer à installer la mise à jour ?",
|
"installUpdate": "Continuer à installer la mise à jour ?",
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
"errorDownloadMessage": "Impossible de télécharger la mise à jour",
|
"errorDownloadMessage": "Impossible de télécharger la mise à jour",
|
||||||
"errorInstallMessage": "Impossible d'installer la mise à jour",
|
"errorInstallMessage": "Impossible d'installer la mise à jour",
|
||||||
"noConnection": "Aucune connexion internet",
|
"noConnection": "Aucune connexion internet",
|
||||||
"updatesDisabled": "La mise à jour d'une application patchée est actuellement désactivée. Repatchez l'application à nouveau."
|
"updatesDisabled": "La mise à jour d'une application patchée est actuellement désactivée. Repatchez l'application."
|
||||||
},
|
},
|
||||||
"applicationItem": {
|
"applicationItem": {
|
||||||
"infoButton": "Info"
|
"infoButton": "Info"
|
||||||
@@ -82,8 +82,8 @@
|
|||||||
"patchSelectorCard": {
|
"patchSelectorCard": {
|
||||||
"widgetTitle": "Sélectionner les patchs",
|
"widgetTitle": "Sélectionner les patchs",
|
||||||
"widgetTitleSelected": "Patchs sélectionnés",
|
"widgetTitleSelected": "Patchs sélectionnés",
|
||||||
"widgetSubtitle": "Choisissez d'abord une application",
|
"widgetSubtitle": "Sélectionnez d'abord une application",
|
||||||
"widgetEmptySubtitle": "Aucun patch n'est sélectionné"
|
"widgetEmptySubtitle": "Aucun patch sélectionné"
|
||||||
},
|
},
|
||||||
"socialMediaCard": {
|
"socialMediaCard": {
|
||||||
"widgetTitle": "Réseaux sociaux",
|
"widgetTitle": "Réseaux sociaux",
|
||||||
@@ -118,24 +118,26 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Valeur personnalisée",
|
"customValue": "Valeur personnalisée",
|
||||||
|
"setToNull": "Définir à NULL",
|
||||||
|
"nullValue": "Cette valeur d'option est actuellement nulle",
|
||||||
"resetOptionsTooltip": "Réinitialiser les options de patch",
|
"resetOptionsTooltip": "Réinitialiser les options de patch",
|
||||||
"viewTitle": "Options de patch",
|
"viewTitle": "Options de patch",
|
||||||
"saveOptions": "Enregistrer",
|
"saveOptions": "Enregistrer",
|
||||||
"addOptions": "Ajouter des options",
|
"addOptions": "Ajouter des options",
|
||||||
"deselectPatch": "Désélectionner tous les patchs",
|
"unselectPatch": "Désélectionner le patch",
|
||||||
"tooltip": "Plus d'options d'entrée",
|
"tooltip": "Plus d'options d'entrée",
|
||||||
"selectFilePath": "Sélectionner l'emplacement du fichier",
|
"selectFilePath": "Sélectionner l'emplacement du fichier",
|
||||||
"selectFolder": "Sélectionner le dossier",
|
"selectFolder": "Sélectionner le dossier",
|
||||||
"selectOption": "Sélectionner une option",
|
"selectOption": "Sélectionner une option",
|
||||||
"requiredOption": "Cette option est obligatoire",
|
"requiredOption": "Définir cette option est nécessaire",
|
||||||
"unsupportedOption": "Cette option n'est pas supportée",
|
"unsupportedOption": "Cette option n'est pas prise en charge",
|
||||||
"requiredOptionNull": "Les options suivantes doivent être définies :\n\n${options}"
|
"requiredOptionNull": "Les options suivantes doivent être définies :\n\n${options}"
|
||||||
},
|
},
|
||||||
"patchItem": {
|
"patchItem": {
|
||||||
"unsupportedDialogText": "Sélectionner ce patch pourrait entrainer des erreurs dans la modification.\n\nVersion de l'application : ${packageVersion}\nVersions supportées :\n${supportedVersions}",
|
"unsupportedDialogText": "Sélectionner ce patch peut entrainer des erreurs dans la modification.\n\nVersion de l'application : ${packageVersion}\nVersions prises en charge :\n${supportedVersions}",
|
||||||
"unsupportedPatchVersion": "Le patch n'est pas supporté pour cette version de l'application.",
|
"unsupportedPatchVersion": "Le patch n'est pas pris en charge pour cette version de l'application.",
|
||||||
"unsupportedRequiredOption": "Ce patch contient une option requise qui n'est pas supporté par cette application",
|
"unsupportedRequiredOption": "Ce patch contient une option requise qui n'est pas prise en charge par cette application",
|
||||||
"patchesChangeWarningDialogText": "Il est recommandé d'utiliser les patchs par défaut ainsi que les options. Leur modification peut entraîner des problèmes inattendus.\n\nVous aurez besoin d'activer \"Autoriser la modification de la sélection du patch\" dans les paramètres avant de modifier toute sélection de patch.",
|
"patchesChangeWarningDialogText": "Il est recommandé d'utiliser les patchs et options par défaut. Leur modification peut entraîner des problèmes inattendus.\n\nVous aurez besoin d'activer « Autoriser la modification de la sélection de patchs » dans les paramètres avant de modifier toute sélection de patchs.",
|
||||||
"patchesChangeWarningDialogButton": "Utiliser la sélection par défaut"
|
"patchesChangeWarningDialogButton": "Utiliser la sélection par défaut"
|
||||||
},
|
},
|
||||||
"installerView": {
|
"installerView": {
|
||||||
@@ -193,7 +195,7 @@
|
|||||||
"contributorsHint": "Liste des contributeurs de ReVanced",
|
"contributorsHint": "Liste des contributeurs de ReVanced",
|
||||||
"logsLabel": "Partager les journaux",
|
"logsLabel": "Partager les journaux",
|
||||||
"logsHint": "Partager les logs de ReVanced Manager",
|
"logsHint": "Partager les logs de ReVanced Manager",
|
||||||
"enablePatchesSelectionLabel": "Autoriser la modification de la sélection du patch",
|
"enablePatchesSelectionLabel": "Autoriser la modification de la sélection de patchs",
|
||||||
"enablePatchesSelectionHint": "Ne pas empêcher la sélection ou la désélection des patchs",
|
"enablePatchesSelectionHint": "Ne pas empêcher la sélection ou la désélection des patchs",
|
||||||
"enablePatchesSelectionWarningText": "Le changement de sélection par défaut des patchs peut causer des problèmes inattendus \n\nActiver quand même ?",
|
"enablePatchesSelectionWarningText": "Le changement de sélection par défaut des patchs peut causer des problèmes inattendus \n\nActiver quand même ?",
|
||||||
"disablePatchesSelectionWarningText": "Vous êtes sur le point de désactiver le changement de sélection par défaut des patchs.\nLa sélection par défaut des patchs sera restaurée.\n\nDésactiver quand même ?",
|
"disablePatchesSelectionWarningText": "Vous êtes sur le point de désactiver le changement de sélection par défaut des patchs.\nLa sélection par défaut des patchs sera restaurée.\n\nDésactiver quand même ?",
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Valore personalizzato",
|
"customValue": "Valore personalizzato",
|
||||||
|
"setToNull": "Imposta a nullo",
|
||||||
|
"nullValue": "Questo valore di opzione è al momento nullo",
|
||||||
"resetOptionsTooltip": "Ripristina opzioni patch",
|
"resetOptionsTooltip": "Ripristina opzioni patch",
|
||||||
"viewTitle": "Opzioni patch",
|
"viewTitle": "Opzioni patch",
|
||||||
"saveOptions": "Salva",
|
"saveOptions": "Salva",
|
||||||
"addOptions": "Aggiungi opzioni",
|
"addOptions": "Aggiungi opzioni",
|
||||||
"deselectPatch": "Deseleziona patch",
|
"unselectPatch": "Deseleziona patch",
|
||||||
"tooltip": "Più opzioni di input",
|
"tooltip": "Più opzioni di input",
|
||||||
"selectFilePath": "Seleziona percorso file",
|
"selectFilePath": "Seleziona percorso file",
|
||||||
"selectFolder": "Seleziona cartella",
|
"selectFolder": "Seleziona cartella",
|
||||||
"selectOption": "Seleziona opzione",
|
"selectOption": "Seleziona opzione",
|
||||||
"requiredOption": "Questa opzione è richiesta",
|
"requiredOption": "L'impostazione di questa opzione è obbligatoria",
|
||||||
"unsupportedOption": "Questa opzione non è supportata",
|
"unsupportedOption": "Questa opzione non è supportata",
|
||||||
"requiredOptionNull": "È necessario impostare le seguenti opzioni:\n\n${options}"
|
"requiredOptionNull": "È necessario impostare le seguenti opzioni:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "カスタム値",
|
"customValue": "カスタム値",
|
||||||
|
"setToNull": "null に設定",
|
||||||
|
"nullValue": "このオプション値は現在nullです",
|
||||||
"resetOptionsTooltip": "パッチ設定をリセット",
|
"resetOptionsTooltip": "パッチ設定をリセット",
|
||||||
"viewTitle": "パッチ設定",
|
"viewTitle": "パッチ設定",
|
||||||
"saveOptions": "保存",
|
"saveOptions": "保存",
|
||||||
"addOptions": "オプションを追加",
|
"addOptions": "オプションを追加",
|
||||||
"deselectPatch": "パッチの選択を解除",
|
"unselectPatch": "パッチの選択を解除",
|
||||||
"tooltip": "他の入力オプション",
|
"tooltip": "他の入力オプション",
|
||||||
"selectFilePath": "ファイルパスを選択",
|
"selectFilePath": "ファイルパスを選択",
|
||||||
"selectFolder": "フォルダーを選択",
|
"selectFolder": "フォルダーを選択",
|
||||||
"selectOption": "オプションを選択",
|
"selectOption": "オプションを選択",
|
||||||
"requiredOption": "このオプションは必須です",
|
"requiredOption": "このオプションを設定する必要があります",
|
||||||
"unsupportedOption": "この設定はサポートされていません",
|
"unsupportedOption": "この設定はサポートされていません",
|
||||||
"requiredOptionNull": "以下のオプションを設定する必要があります:\n\n${options}"
|
"requiredOptionNull": "以下のオプションを設定する必要があります:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Aangepaste waarde",
|
"customValue": "Aangepaste waarde",
|
||||||
|
"setToNull": "Zet op nul",
|
||||||
|
"nullValue": "Deze optiewaarde is momenteel leeg",
|
||||||
"resetOptionsTooltip": "Reset patch opties",
|
"resetOptionsTooltip": "Reset patch opties",
|
||||||
"viewTitle": "Patch opties",
|
"viewTitle": "Patch opties",
|
||||||
"saveOptions": "Opslaan",
|
"saveOptions": "Opslaan",
|
||||||
"addOptions": "Opties toevoegen",
|
"addOptions": "Opties toevoegen",
|
||||||
"deselectPatch": "Deselecteer patch",
|
"unselectPatch": "Patch deselecteren",
|
||||||
"tooltip": "Meer invoeropties",
|
"tooltip": "Meer invoeropties",
|
||||||
"selectFilePath": "Bestandspad selecteren",
|
"selectFilePath": "Bestandspad selecteren",
|
||||||
"selectFolder": "Map selecteren",
|
"selectFolder": "Map selecteren",
|
||||||
"selectOption": "Selecteer optie",
|
"selectOption": "Selecteer optie",
|
||||||
"requiredOption": "Deze optie is vereist",
|
"requiredOption": "Het instellen van deze optie is vereist",
|
||||||
"unsupportedOption": "Deze optie wordt niet ondersteund",
|
"unsupportedOption": "Deze optie wordt niet ondersteund",
|
||||||
"requiredOptionNull": "De volgende opties moeten worden ingesteld:\n\n${options}"
|
"requiredOptionNull": "De volgende opties moeten worden ingesteld:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Niestandardowa wartość",
|
"customValue": "Niestandardowa wartość",
|
||||||
|
"setToNull": "Ustaw na zerowy",
|
||||||
|
"nullValue": "Ta opcja jest obecnie pusta",
|
||||||
"resetOptionsTooltip": "Zresetuj opcje od łatek",
|
"resetOptionsTooltip": "Zresetuj opcje od łatek",
|
||||||
"viewTitle": "Opcje łatek",
|
"viewTitle": "Opcje łatek",
|
||||||
"saveOptions": "Zapisz",
|
"saveOptions": "Zapisz",
|
||||||
"addOptions": "Dodaj opcje",
|
"addOptions": "Dodaj opcje",
|
||||||
"deselectPatch": "Odznacz łatkę",
|
"unselectPatch": "Odznacz łatkę",
|
||||||
"tooltip": "Więcej opcji wejściowych",
|
"tooltip": "Więcej opcji wejściowych",
|
||||||
"selectFilePath": "Wybierz ścieżkę pliku",
|
"selectFilePath": "Wybierz ścieżkę pliku",
|
||||||
"selectFolder": "Wybierz folder",
|
"selectFolder": "Wybierz folder",
|
||||||
"selectOption": "Wybierz opcję",
|
"selectOption": "Wybierz opcję",
|
||||||
"requiredOption": "Ta opcja jest wymagana",
|
"requiredOption": "Ustawienie tej opcji jest wymagane",
|
||||||
"unsupportedOption": "Ta opcja nie jest wspierana",
|
"unsupportedOption": "Ta opcja nie jest wspierana",
|
||||||
"requiredOptionNull": "Należy ustawić następujące opcje:\n\n${options}"
|
"requiredOptionNull": "Należy ustawić następujące opcje:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
"refreshSuccess": "Atualizado com sucesso",
|
"refreshSuccess": "Atualizado com sucesso",
|
||||||
"widgetTitle": "Painel",
|
"widgetTitle": "Painel",
|
||||||
"updatesSubtitle": "Atualizações",
|
"updatesSubtitle": "Atualizações",
|
||||||
"patchedSubtitle": "Aplicativos patcheados",
|
"patchedSubtitle": "Aplicativos patcheados ",
|
||||||
"changeLaterSubtitle": "Você pode ajustar essa opção nas configurações mais tarde.",
|
"changeLaterSubtitle": "Você pode ajustar essa opção nas configurações mais tarde.",
|
||||||
"noUpdates": "Nenhuma atualização encontrada",
|
"noUpdates": "Nenhuma atualização encontrada",
|
||||||
"WIP": "Trabalho em progresso...",
|
"WIP": "Trabalho em progresso...",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"updateDialogText": "Uma nova atualização está disponível para ${file}.\n\nA versão atualmente instalada é a ${version}.",
|
"updateDialogText": "Uma nova atualização está disponível para ${file}.\n\nA versão atualmente instalada é a ${version}.",
|
||||||
"downloadConsentDialogTitle": "Baixar os arquivos necessários?",
|
"downloadConsentDialogTitle": "Baixar os arquivos necessários?",
|
||||||
"downloadConsentDialogText": "O ReVanced Manager precisará baixar os arquivos necessários para funcionar corretamente.",
|
"downloadConsentDialogText": "O ReVanced Manager precisará baixar os arquivos necessários para funcionar corretamente.",
|
||||||
"downloadConsentDialogText2": "Isso irá te conectar em ${url}.",
|
"downloadConsentDialogText2": "Isso vai conectar você em ${url}.",
|
||||||
"checkUpdateDialogTitle": "Procurar atualizações?",
|
"checkUpdateDialogTitle": "Procurar atualizações?",
|
||||||
"checkUpdateDialogText": "Você quer que o ReVanced Manager procure atualizações automaticamente?",
|
"checkUpdateDialogText": "Você quer que o ReVanced Manager procure atualizações automaticamente?",
|
||||||
"notificationTitle": "Atualização baixada",
|
"notificationTitle": "Atualização baixada",
|
||||||
@@ -71,9 +71,9 @@
|
|||||||
"requiredOptionDialogText": "Algumas opções de patch tiveram que ser definidas."
|
"requiredOptionDialogText": "Algumas opções de patch tiveram que ser definidas."
|
||||||
},
|
},
|
||||||
"appSelectorCard": {
|
"appSelectorCard": {
|
||||||
"widgetTitle": "Selecione um aplicativo",
|
"widgetTitle": "Selecione um app",
|
||||||
"widgetTitleSelected": "Aplicativo selecionado",
|
"widgetTitleSelected": "App selecionado",
|
||||||
"widgetSubtitle": "Nenhum aplicativo selecionado",
|
"widgetSubtitle": "Nenhum app selecionado",
|
||||||
"noAppsLabel": "Nenhum aplicativo foi encontrado",
|
"noAppsLabel": "Nenhum aplicativo foi encontrado",
|
||||||
"currentVersion": "Atual",
|
"currentVersion": "Atual",
|
||||||
"suggestedVersion": "Sugeridos/sugestões",
|
"suggestedVersion": "Sugeridos/sugestões",
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
"selectFromStorageButton": "Selecionar no armazenamento",
|
"selectFromStorageButton": "Selecionar no armazenamento",
|
||||||
"errorMessage": "Não foi possível usar o app selecionado",
|
"errorMessage": "Não foi possível usar o app selecionado",
|
||||||
"downloadToast": "A função de download não está disponível no momento",
|
"downloadToast": "A função de download não está disponível no momento",
|
||||||
"requireSuggestedAppVersionDialogText": "The version of the app you have selected does not match the suggested version which can lead to unexpected issues. Please use the suggested version.\n\nSelected version: ${selected}\nSuggested version: ${suggested}\n\nTo continue anyway, disable \"Require suggested app version\" in the settings.",
|
"requireSuggestedAppVersionDialogText": "A versão do app selecionada não corresponde à versão sugerida, o que pode causar problemas inesperados. Por favor, use a versão sugerida.\n\nVersão selecionada: ${selected} \nVersão sugerida: ${suggested}\n\nPara continuar mesmo assim, desative \"Exigir versão sugerida do app\" nas configurações.",
|
||||||
"featureNotAvailable": "Recurso não implementado",
|
"featureNotAvailable": "Recurso não implementado",
|
||||||
"featureNotAvailableText": "Este aplicativo é um APK dividido e só pode ser patcheado e instalado de forma confiável ao ser montado com permissões de root. No entanto, você pode patchear e instalar um APK completo ao selecioná-lo do armazenamento."
|
"featureNotAvailableText": "Este aplicativo é um APK dividido e só pode ser patcheado e instalado de forma confiável ao ser montado com permissões de root. No entanto, você pode patchear e instalar um APK completo ao selecioná-lo do armazenamento."
|
||||||
},
|
},
|
||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Valor personalizado",
|
"customValue": "Valor personalizado",
|
||||||
"resetOptionsTooltip": "Redefinir opções de patch",
|
"setToNull": "Definir como nulo",
|
||||||
|
"nullValue": "Atualmente, este valor de opção é nulo",
|
||||||
|
"resetOptionsTooltip": "Redefinir as opções de patch",
|
||||||
"viewTitle": "Opções de patch",
|
"viewTitle": "Opções de patch",
|
||||||
"saveOptions": "Salvar",
|
"saveOptions": "Salvar",
|
||||||
"addOptions": "Adicionar opções",
|
"addOptions": "Adicionar opções",
|
||||||
"deselectPatch": "Deselecionar patch",
|
"unselectPatch": "Desmarque o patch",
|
||||||
"tooltip": "Mais opções de entrada",
|
"tooltip": "Mais opções de entrada",
|
||||||
"selectFilePath": "Selecione o caminho do arquivo",
|
"selectFilePath": "Selecione o caminho do arquivo",
|
||||||
"selectFolder": "Selecione a pasta",
|
"selectFolder": "Selecione a pasta",
|
||||||
"selectOption": "Selecione uma opção",
|
"selectOption": "Selecione uma opção",
|
||||||
"requiredOption": "Essa opção é necessária",
|
"requiredOption": "Definir esta opção é necessário",
|
||||||
"unsupportedOption": "Essa opção não é suportada",
|
"unsupportedOption": "Essa opção não é suportada",
|
||||||
"requiredOptionNull": "As seguintes opções precisam ser definidas:\n\n${options}"
|
"requiredOptionNull": "As seguintes opções precisam ser definidas:\n\n${options}"
|
||||||
},
|
},
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"sourcesLabelHint": "Conigure as fontes alternativas para ReVanced Patches e ReVanced Integrations",
|
"sourcesLabelHint": "Conigure as fontes alternativas para ReVanced Patches e ReVanced Integrations",
|
||||||
"sourcesIntegrationsLabel": "Fonte das integrações",
|
"sourcesIntegrationsLabel": "Fonte das integrações",
|
||||||
"useAlternativeSources": "Usar fontes alternativas",
|
"useAlternativeSources": "Usar fontes alternativas",
|
||||||
"useAlternativeSourcesHint": "Use alternative sources for ReVanced Patches and ReVanced Integrations instead of the API",
|
"useAlternativeSourcesHint": "Use fontes alternativas para Patches do ReVanced e Integrações do ReVanced em vez da API",
|
||||||
"sourcesResetDialogTitle": "Redefinir",
|
"sourcesResetDialogTitle": "Redefinir",
|
||||||
"sourcesResetDialogText": "Você tem certeza que deseja redefinir as fontes para os valores padrão?",
|
"sourcesResetDialogText": "Você tem certeza que deseja redefinir as fontes para os valores padrão?",
|
||||||
"apiURLResetDialogText": "Are you sure you want to reset your API URL to its default value?",
|
"apiURLResetDialogText": "Are you sure you want to reset your API URL to its default value?",
|
||||||
@@ -199,15 +201,15 @@
|
|||||||
"disablePatchesSelectionWarningText": "Você irá desabilitar a mudança da pré-seleção dos patches.\nA seleção padrão dos patches será restaurada.\n\nDesabilitar mesmo assim?",
|
"disablePatchesSelectionWarningText": "Você irá desabilitar a mudança da pré-seleção dos patches.\nA seleção padrão dos patches será restaurada.\n\nDesabilitar mesmo assim?",
|
||||||
"autoUpdatePatchesLabel": "Atualizar patches automaticamente",
|
"autoUpdatePatchesLabel": "Atualizar patches automaticamente",
|
||||||
"autoUpdatePatchesHint": "Atualize automaticamente os patches para a versão mais recente",
|
"autoUpdatePatchesHint": "Atualize automaticamente os patches para a versão mais recente",
|
||||||
"showUpdateDialogLabel": "Show update dialog",
|
"showUpdateDialogLabel": "Mostrar alerta de atualização",
|
||||||
"showUpdateDialogHint": "Show a dialog when a new update is available",
|
"showUpdateDialogHint": "Mostra um aviso quando uma nova atualização estiver disponível",
|
||||||
"universalPatchesLabel": "Mostrar patches universais",
|
"universalPatchesLabel": "Mostrar patches universais",
|
||||||
"universalPatchesHint": "Mostra todos os aplicativos e patches universais (pode deixar a lista de aplicativos mais lenta)",
|
"universalPatchesHint": "Mostra todos os aplicativos e patches universais (pode deixar a lista de aplicativos mais lenta)",
|
||||||
"versionCompatibilityCheckLabel": "Verificar compatibilidade de versão",
|
"versionCompatibilityCheckLabel": "Verificar compatibilidade de versão",
|
||||||
"versionCompatibilityCheckHint": "Prevent selecting patches that are not compatible with the selected app version",
|
"versionCompatibilityCheckHint": "Impedir a seleção de patches que não são compatíveis com a versão do app selecionado",
|
||||||
"requireSuggestedAppVersionLabel": "Requer a versão sugerida do app",
|
"requireSuggestedAppVersionLabel": "Exigir versão sugerida do app",
|
||||||
"requireSuggestedAppVersionHint": "Evite selecionar um aplicativo com uma versão diferente da sugerida",
|
"requireSuggestedAppVersionHint": "Evite selecionar um app com uma versão diferente da sugerida",
|
||||||
"requireSuggestedAppVersionDialogText": "Selecionar um aplicativo que não seja a versão sugerida pode causar problemas inesperados.\n\nVocê quer prosseguir mesmo assim?",
|
"requireSuggestedAppVersionDialogText": "Selecionar um app que não seja a versão sugerida pode causar problemas inesperados.\n\nVocê quer prosseguir mesmo assim?",
|
||||||
"aboutLabel": "Sobre",
|
"aboutLabel": "Sobre",
|
||||||
"snackbarMessage": "Copiado para a área de transferência",
|
"snackbarMessage": "Copiado para a área de transferência",
|
||||||
"restartAppForChanges": "Reinicie o aplicativo para aplicar as mudanças",
|
"restartAppForChanges": "Reinicie o aplicativo para aplicar as mudanças",
|
||||||
@@ -221,16 +223,16 @@
|
|||||||
"importPatchesLabel": "Importar seleção de patch",
|
"importPatchesLabel": "Importar seleção de patch",
|
||||||
"importPatchesHint": "Importar seleção de patch de um arquivo JSON",
|
"importPatchesHint": "Importar seleção de patch de um arquivo JSON",
|
||||||
"importedPatches": "Seleção de patch importada",
|
"importedPatches": "Seleção de patch importada",
|
||||||
"resetStoredPatchesLabel": "Redefinir seleção de patch",
|
"resetStoredPatchesLabel": "Redefinir a seleção de patch",
|
||||||
"resetStoredPatchesHint": "Redefinir a seleção de patch armazenada",
|
"resetStoredPatchesHint": "Redefinir a seleção de patch armazenada",
|
||||||
"resetStoredPatchesDialogTitle": "Redefinir seleção de patch?",
|
"resetStoredPatchesDialogTitle": "Redefinir a seleção de patch?",
|
||||||
"resetStoredPatchesDialogText": "A seleção padrão de patches será restaurada.",
|
"resetStoredPatchesDialogText": "A seleção padrão de patches será restaurada.",
|
||||||
"resetStoredPatches": "A seleção de patch foi redefinida",
|
"resetStoredPatches": "A seleção de patch foi redefinida",
|
||||||
"resetStoredOptionsLabel": "Redefinir opções de patch",
|
"resetStoredOptionsLabel": "Redefinir as opções de patch",
|
||||||
"resetStoredOptionsHint": "Resetar todas as opções de patch",
|
"resetStoredOptionsHint": "Redefinir todas as opções de patch",
|
||||||
"resetStoredOptionsDialogTitle": "Reset patch options?",
|
"resetStoredOptionsDialogTitle": "Redefinir as opções de patch?",
|
||||||
"resetStoredOptionsDialogText": "Resetting patch options will remove all saved options.",
|
"resetStoredOptionsDialogText": "Redefinir as opções de patch vai remover todas as opções salvas.",
|
||||||
"resetStoredOptions": "As opções foram resetadas",
|
"resetStoredOptions": "As opções foram redefinidas",
|
||||||
"deleteLogsLabel": "Limpar registros",
|
"deleteLogsLabel": "Limpar registros",
|
||||||
"deleteLogsHint": "Delete collected ReVanced Manager logs",
|
"deleteLogsHint": "Delete collected ReVanced Manager logs",
|
||||||
"deletedLogs": "Registros apagados",
|
"deletedLogs": "Registros apagados",
|
||||||
@@ -286,7 +288,7 @@
|
|||||||
"status_failure_incompatible": "Instalação incompatível",
|
"status_failure_incompatible": "Instalação incompatível",
|
||||||
"status_failure_timeout": "Tempo limite de instalação",
|
"status_failure_timeout": "Tempo limite de instalação",
|
||||||
"status_unknown": "Falha na instalação",
|
"status_unknown": "Falha na instalação",
|
||||||
"mount_version_mismatch_description": "A instalação falhou devido ao aplicativo instalado ser uma versão diferente do aplicativo patcheado.\n\nInstale a versão do aplicativo que você está montando e tente novamente.",
|
"mount_version_mismatch_description": "A instalação falhou porque o app instalado era de uma versão diferente do app patcheado.\n\nInstale a versão do app que você está montando e tente de novo.",
|
||||||
"mount_no_root_description": "A instalação falhou devido ao acesso root não ter sido concedido.\n\nConceda acesso root ao Gerenciador ReVanced e tente novamente.",
|
"mount_no_root_description": "A instalação falhou devido ao acesso root não ter sido concedido.\n\nConceda acesso root ao Gerenciador ReVanced e tente novamente.",
|
||||||
"mount_missing_installation_description": "A instalação falhou devido ao aplicativo não patcheado não estar instalado neste dispositivo para ser montado sobre ele.\n\nInstale o aplicativo não patcheado antes de montar e tente novamente.",
|
"mount_missing_installation_description": "A instalação falhou devido ao aplicativo não patcheado não estar instalado neste dispositivo para ser montado sobre ele.\n\nInstale o aplicativo não patcheado antes de montar e tente novamente.",
|
||||||
"status_failure_timeout_description": "A instalação demorou muito para terminar.\n\nVocê gostaria de tentar novamente?",
|
"status_failure_timeout_description": "A instalação demorou muito para terminar.\n\nVocê gostaria de tentar novamente?",
|
||||||
@@ -296,7 +298,7 @@
|
|||||||
"status_failure_conflict_description": "A instalação foi impedida por uma instalação existente do aplicativo.\n\nDesinstale o aplicativo instalado e tente novamente",
|
"status_failure_conflict_description": "A instalação foi impedida por uma instalação existente do aplicativo.\n\nDesinstale o aplicativo instalado e tente novamente",
|
||||||
"status_failure_blocked_description": "A instalação foi bloqueada por ${packageName}.\n\nAjuste suas configurações de segurança e tente novamente.",
|
"status_failure_blocked_description": "A instalação foi bloqueada por ${packageName}.\n\nAjuste suas configurações de segurança e tente novamente.",
|
||||||
"install_failed_verification_failure_description": "A instalação falhou devido a um problema de verificação.\n\nAjuste suas configurações de segurança e tente novamente.",
|
"install_failed_verification_failure_description": "A instalação falhou devido a um problema de verificação.\n\nAjuste suas configurações de segurança e tente novamente.",
|
||||||
"install_failed_version_downgrade_description": "A instalação falhou devido ao aplicativo patcheado ser uma versão mais baixa que o aplicativo instalado.\n\nDesinstale o aplicativo e tente novamente.",
|
"install_failed_version_downgrade_description": "A instalação falhou porque o app patcheado era uma versão mais baixa que o app instalado.\n\nDesinstalar o app e tentar de novo?",
|
||||||
"status_unknown_description": "A instalação falhou por um motivo desconhecido. Por favor, tente novamente."
|
"status_unknown_description": "A instalação falhou por um motivo desconhecido. Por favor, tente novamente."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"okButton": "OK",
|
"okButton": "OK",
|
||||||
"cancelButton": "Cancelar",
|
"cancelButton": "Cancelar",
|
||||||
"dismissButton": "Dispensar",
|
"dismissButton": "Ignorar",
|
||||||
"quitButton": "Sair",
|
"quitButton": "Sair",
|
||||||
"updateButton": "Atualizar",
|
"updateButton": "Atualizar",
|
||||||
"enabledLabel": "Ativado",
|
"enabledLabel": "Ativado",
|
||||||
@@ -27,11 +27,11 @@
|
|||||||
"refreshSuccess": "Atualizado com sucesso",
|
"refreshSuccess": "Atualizado com sucesso",
|
||||||
"widgetTitle": "Painel de Controlo",
|
"widgetTitle": "Painel de Controlo",
|
||||||
"updatesSubtitle": "Atualizações",
|
"updatesSubtitle": "Atualizações",
|
||||||
"patchedSubtitle": "Aplicações Modificadas",
|
"patchedSubtitle": "Apps patcheados",
|
||||||
"changeLaterSubtitle": "Podes modificar esta definição mais tarde.",
|
"changeLaterSubtitle": "Podes modificar esta definição mais tarde.",
|
||||||
"noUpdates": "Nenhuma atualização disponível",
|
"noUpdates": "Nenhuma atualização disponível",
|
||||||
"WIP": "Trabalho em progresso...",
|
"WIP": "Trabalho em progresso...",
|
||||||
"noInstallations": "Nenhuma aplicação modificada instalada",
|
"noInstallations": "Nenhum app patcheado instalado",
|
||||||
"installUpdate": "Continuar para instalar a atualização?",
|
"installUpdate": "Continuar para instalar a atualização?",
|
||||||
"updateSheetTitle": "Atualizar o ReVanced Manager",
|
"updateSheetTitle": "Atualizar o ReVanced Manager",
|
||||||
"updateDialogTitle": "Nova atualização disponível",
|
"updateDialogTitle": "Nova atualização disponível",
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
"errorDownloadMessage": "Não é possível transferir a atualização",
|
"errorDownloadMessage": "Não é possível transferir a atualização",
|
||||||
"errorInstallMessage": "Não foi possível instalar a atualização",
|
"errorInstallMessage": "Não foi possível instalar a atualização",
|
||||||
"noConnection": "Sem ligação à Internet",
|
"noConnection": "Sem ligação à Internet",
|
||||||
"updatesDisabled": "Atualizar uma aplicação modificada está atualmente desabilitado. Volta a modificar a aplicação."
|
"updatesDisabled": "A atualização de um app patcheado está desativada no momento. Repatch o app de novo."
|
||||||
},
|
},
|
||||||
"applicationItem": {
|
"applicationItem": {
|
||||||
"infoButton": "Informação"
|
"infoButton": "Informação"
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
"downloadToast": "A função de transferência não está disponível",
|
"downloadToast": "A função de transferência não está disponível",
|
||||||
"requireSuggestedAppVersionDialogText": "A versão da aplicação que selecionaste não corresponde à versão sugerida, o que pode levar a problemas inesperados. Utiliza a versão recomendada.\n\nVersão selecionada: ${selected}\nVersão recomendada: ${suggested}\n\nPara continuar na mesma, desactive a opção \"Exigir a versão recomendada da aplicação\" nas definições.",
|
"requireSuggestedAppVersionDialogText": "A versão da aplicação que selecionaste não corresponde à versão sugerida, o que pode levar a problemas inesperados. Utiliza a versão recomendada.\n\nVersão selecionada: ${selected}\nVersão recomendada: ${suggested}\n\nPara continuar na mesma, desactive a opção \"Exigir a versão recomendada da aplicação\" nas definições.",
|
||||||
"featureNotAvailable": "Recurso não implementado",
|
"featureNotAvailable": "Recurso não implementado",
|
||||||
"featureNotAvailableText": "Esta aplicação é um APK dividido e só pode ser modificado e instalado de forma fiável através da montagem com permissões root. No entanto, é possível corrigir e instalar um APK completo selecionando-o a partir do armazenamento."
|
"featureNotAvailableText": "Esse app é um APK dividido e só pode ser modificado e instalado de forma fiável através da montagem com permissões root. No entanto, é possível patchear e instalar um APK completo selecionando ele a partir do armazenamento."
|
||||||
},
|
},
|
||||||
"patchesSelectorView": {
|
"patchesSelectorView": {
|
||||||
"viewTitle": "Selecionar modificações",
|
"viewTitle": "Selecionar modificações",
|
||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Valor personalizado",
|
"customValue": "Valor personalizado",
|
||||||
|
"setToNull": "Definir como nulo",
|
||||||
|
"nullValue": "Atualmente, este valor de opção é nulo",
|
||||||
"resetOptionsTooltip": "Reiniciar as opções da modificação",
|
"resetOptionsTooltip": "Reiniciar as opções da modificação",
|
||||||
"viewTitle": "Opções de modificação",
|
"viewTitle": "Opções de modificação",
|
||||||
"saveOptions": "Guardar",
|
"saveOptions": "Guardar",
|
||||||
"addOptions": "Adicionar opções",
|
"addOptions": "Adicionar opções",
|
||||||
"deselectPatch": "Desselecionar modificação",
|
"unselectPatch": "Desmarque o patch",
|
||||||
"tooltip": "Mais opções de entrada",
|
"tooltip": "Mais opções de entrada",
|
||||||
"selectFilePath": "Selecionar caminho do arquivo",
|
"selectFilePath": "Selecionar caminho do arquivo",
|
||||||
"selectFolder": "Selecionar pasta",
|
"selectFolder": "Selecionar pasta",
|
||||||
"selectOption": "Seleccionar opção",
|
"selectOption": "Seleccionar opção",
|
||||||
"requiredOption": "Esta opção é obrigatória",
|
"requiredOption": "Definir esta opção é necessário",
|
||||||
"unsupportedOption": "Esta opção não é suportada",
|
"unsupportedOption": "Esta opção não é suportada",
|
||||||
"requiredOptionNull": "As seguintes opções devem ser definidas:\n\n${options}"
|
"requiredOptionNull": "As seguintes opções devem ser definidas:\n\n${options}"
|
||||||
},
|
},
|
||||||
@@ -145,13 +147,13 @@
|
|||||||
"installButton": "Instalar",
|
"installButton": "Instalar",
|
||||||
"installRootType": "Montar",
|
"installRootType": "Montar",
|
||||||
"installNonRootType": "Normal",
|
"installNonRootType": "Normal",
|
||||||
"warning": "Desativa as atualizações automáticas da aplicação modificada para evitar problemas inesperados.",
|
"warning": "Desative as atualizações automáticas do app patcheado para evitar problemas inesperados.",
|
||||||
"pressBackAgain": "Pressione voltar novamente para cancelar",
|
"pressBackAgain": "Pressione voltar novamente para cancelar",
|
||||||
"openButton": "Abrir",
|
"openButton": "Abrir",
|
||||||
"shareButton": "Partilhar ficheiro",
|
"shareButton": "Partilhar ficheiro",
|
||||||
"notificationTitle": "O ReVanced Manager está a fazer as modificações",
|
"notificationTitle": "O ReVanced Manager está a fazer as modificações",
|
||||||
"notificationText": "Toca para voltar ao instalador",
|
"notificationText": "Toca para voltar ao instalador",
|
||||||
"exportApkButtonTooltip": "Exportar APK modificado",
|
"exportApkButtonTooltip": "Exportar APK patcheado",
|
||||||
"exportLogButtonTooltip": "Exportar registo",
|
"exportLogButtonTooltip": "Exportar registo",
|
||||||
"screenshotDetected": "Foi detetada uma captura de ecrã. Se estiver a tentar partilhar o registo, partilhe antes uma cópia de texto.\n\nCopiar o registo para a área de transferência?",
|
"screenshotDetected": "Foi detetada uma captura de ecrã. Se estiver a tentar partilhar o registo, partilhe antes uma cópia de texto.\n\nCopiar o registo para a área de transferência?",
|
||||||
"copiedToClipboard": "Registo copiado para a área de transferência",
|
"copiedToClipboard": "Registo copiado para a área de transferência",
|
||||||
@@ -258,13 +260,13 @@
|
|||||||
"unmountButton": "Desmontar",
|
"unmountButton": "Desmontar",
|
||||||
"rootDialogTitle": "Erro",
|
"rootDialogTitle": "Erro",
|
||||||
"unmountDialogText": "Tens a certeza que queres remover as modificações desta aplicação?",
|
"unmountDialogText": "Tens a certeza que queres remover as modificações desta aplicação?",
|
||||||
"uninstallDialogText": "Tens a certeza que queres desinstalar esta aplicação?",
|
"uninstallDialogText": "Tem certeza que quer desinstalar esse app?",
|
||||||
"rootDialogText": "A aplicação foi instalada com permissões de Super-Utilizador, mas atualmente o ReVanced Manager não tem permissões.\nPor favor, conceda permissões de Super-Utilizador primeiro.",
|
"rootDialogText": "A aplicação foi instalada com permissões de Super-Utilizador, mas atualmente o ReVanced Manager não tem permissões.\nPor favor, conceda permissões de Super-Utilizador primeiro.",
|
||||||
"packageNameLabel": "Nome do pacote",
|
"packageNameLabel": "Nome do pacote",
|
||||||
"installTypeLabel": "Tipo de instalação",
|
"installTypeLabel": "Tipo de instalação",
|
||||||
"mountTypeLabel": "Montar",
|
"mountTypeLabel": "Montar",
|
||||||
"regularTypeLabel": "Normal",
|
"regularTypeLabel": "Normal",
|
||||||
"patchedDateLabel": "Data da Modificação",
|
"patchedDateLabel": "Data do patch",
|
||||||
"appliedPatchesLabel": "Modificações aplicadas",
|
"appliedPatchesLabel": "Modificações aplicadas",
|
||||||
"patchedDateHint": "${date} às ${time}",
|
"patchedDateHint": "${date} às ${time}",
|
||||||
"appliedPatchesHint": "${quantity} modificação/ões aplicada/s",
|
"appliedPatchesHint": "${quantity} modificação/ões aplicada/s",
|
||||||
@@ -293,10 +295,10 @@
|
|||||||
"status_failure_storage_description": "A instalação falhou devido ao armazenamento insuficiente.\n\nLiberta algum espaço e tenta novamente.",
|
"status_failure_storage_description": "A instalação falhou devido ao armazenamento insuficiente.\n\nLiberta algum espaço e tenta novamente.",
|
||||||
"status_failure_invalid_description": "A instalação falhou devido ao facto da aplicação modificada ser inválida.\n\nDesinstalar a aplicação e tentar novamente?",
|
"status_failure_invalid_description": "A instalação falhou devido ao facto da aplicação modificada ser inválida.\n\nDesinstalar a aplicação e tentar novamente?",
|
||||||
"status_failure_incompatible_description": "O aplicativo é incompatível com este dispositivo.\n\nEntre em contacto com o desenvolvedor da aplicação e peça suporte.",
|
"status_failure_incompatible_description": "O aplicativo é incompatível com este dispositivo.\n\nEntre em contacto com o desenvolvedor da aplicação e peça suporte.",
|
||||||
"status_failure_conflict_description": "A instalação foi impedida por uma instalação já existente da mesma aplicação.\n\nDesinstalar a aplicação instalada e tentar novamente?",
|
"status_failure_conflict_description": "A instalação foi impedida por uma instalação existente do app.\n\nDesinstalar o app instalado e tentar de novo?",
|
||||||
"status_failure_blocked_description": "A instalação foi bloqueada por ${packageName}.\n\nAjuste as suas definições de segurança e tenta novamente.",
|
"status_failure_blocked_description": "A instalação foi bloqueada por ${packageName}.\n\nAjuste as suas definições de segurança e tenta novamente.",
|
||||||
"install_failed_verification_failure_description": "A instalação falhou por problemas de verificação.\n\nAjusta as tuas definições de segurança e tenta novamente.",
|
"install_failed_verification_failure_description": "A instalação falhou por problemas de verificação.\n\nAjusta as tuas definições de segurança e tenta novamente.",
|
||||||
"install_failed_version_downgrade_description": "A instalação falhou devido ao facto da aplicação modificada ser uma versão inferior à da aplicação instalada.\n\nDesinstalar a aplicação e tentar novamente?",
|
"install_failed_version_downgrade_description": "A instalação falhou porque o app patcheado era uma versão inferior ao aplicativo instalado.\n\nDesinstalar o app e tentar de novo?",
|
||||||
"status_unknown_description": "A instalação falhou por razões desconhecidas. Por favor, tenta novamente."
|
"status_unknown_description": "A instalação falhou por razões desconhecidas. Por favor, tenta novamente."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Valoare personalizată",
|
"customValue": "Valoare personalizată",
|
||||||
|
"setToNull": "Setează ca nul",
|
||||||
|
"nullValue": "Această valoare este în prezent nulă",
|
||||||
"resetOptionsTooltip": "Resetează opțiunile patch-ului",
|
"resetOptionsTooltip": "Resetează opțiunile patch-ului",
|
||||||
"viewTitle": "Opțiuni patch",
|
"viewTitle": "Opțiuni patch",
|
||||||
"saveOptions": "Salvează",
|
"saveOptions": "Salvează",
|
||||||
"addOptions": "Adaugă opțiuni",
|
"addOptions": "Adaugă opțiuni",
|
||||||
"deselectPatch": "Deselectați toate patch-urile",
|
"unselectPatch": "Deselectează patch-ul",
|
||||||
"tooltip": "Mai multe opțiuni de intrare",
|
"tooltip": "Mai multe opțiuni de intrare",
|
||||||
"selectFilePath": "Selectați calea fișierului",
|
"selectFilePath": "Selectați calea fișierului",
|
||||||
"selectFolder": "Selectați dosarul",
|
"selectFolder": "Selectați dosarul",
|
||||||
"selectOption": "Selectați opțiunea",
|
"selectOption": "Selectați opțiunea",
|
||||||
"requiredOption": "Această opțiune este necesară",
|
"requiredOption": "Setarea acestei opțiuni este necesară",
|
||||||
"unsupportedOption": "Această opțiune nu este acceptată",
|
"unsupportedOption": "Această opțiune nu este acceptată",
|
||||||
"requiredOptionNull": "Următoarele opțiuni trebuie setate:\n\n${options}"
|
"requiredOptionNull": "Următoarele opțiuni trebuie setate:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,11 +118,13 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Пользовательское значение",
|
"customValue": "Пользовательское значение",
|
||||||
|
"setToNull": "Установить null",
|
||||||
|
"nullValue": "Значение этого параметра в настоящее время является нулевым",
|
||||||
"resetOptionsTooltip": "Сброс параметров патчей",
|
"resetOptionsTooltip": "Сброс параметров патчей",
|
||||||
"viewTitle": "Параметры патчей",
|
"viewTitle": "Параметры патчей",
|
||||||
"saveOptions": "Сохранить",
|
"saveOptions": "Сохранить",
|
||||||
"addOptions": "Добавить параметры",
|
"addOptions": "Добавить параметры",
|
||||||
"deselectPatch": "Снять выделение с патча",
|
"unselectPatch": "Отменить выбор патча",
|
||||||
"tooltip": "Другие параметры ввода",
|
"tooltip": "Другие параметры ввода",
|
||||||
"selectFilePath": "Выберите путь к файлу",
|
"selectFilePath": "Выберите путь к файлу",
|
||||||
"selectFolder": "Выберите папку",
|
"selectFolder": "Выберите папку",
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Anpassat värde",
|
"customValue": "Anpassat värde",
|
||||||
|
"setToNull": "Sätt till noll",
|
||||||
|
"nullValue": "Detta alternativ värde är för närvarande noll",
|
||||||
"resetOptionsTooltip": "Återställ patchalternativ",
|
"resetOptionsTooltip": "Återställ patchalternativ",
|
||||||
"viewTitle": "Patchalternativ",
|
"viewTitle": "Patchalternativ",
|
||||||
"saveOptions": "Spara",
|
"saveOptions": "Spara",
|
||||||
"addOptions": "Lägg till alternativ",
|
"addOptions": "Lägg till alternativ",
|
||||||
"deselectPatch": "Avmarkera patch",
|
"unselectPatch": "Avmarkera patch",
|
||||||
"tooltip": "Fler inmatningsalternativ",
|
"tooltip": "Fler inmatningsalternativ",
|
||||||
"selectFilePath": "Välj filsökväg",
|
"selectFilePath": "Välj filsökväg",
|
||||||
"selectFolder": "Välj mapp",
|
"selectFolder": "Välj mapp",
|
||||||
"selectOption": "Välj alternativ",
|
"selectOption": "Välj alternativ",
|
||||||
"requiredOption": "Detta alternativ är nödvändigt",
|
"requiredOption": "Inställning av detta alternativ krävs",
|
||||||
"unsupportedOption": "Detta alternativ stöds ej",
|
"unsupportedOption": "Detta alternativ stöds ej",
|
||||||
"requiredOptionNull": "Följande alternativ måste anges:\n\n${options}"
|
"requiredOptionNull": "Följande alternativ måste anges:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "Власне значення",
|
"customValue": "Власне значення",
|
||||||
|
"setToNull": "Встановити в null",
|
||||||
|
"nullValue": "Значення опції в даний час null",
|
||||||
"resetOptionsTooltip": "Скинути параметри патчу",
|
"resetOptionsTooltip": "Скинути параметри патчу",
|
||||||
"viewTitle": "Параметри патчу",
|
"viewTitle": "Параметри патчу",
|
||||||
"saveOptions": "Зберегти",
|
"saveOptions": "Зберегти",
|
||||||
"addOptions": "Додати параметри",
|
"addOptions": "Додати параметри",
|
||||||
"deselectPatch": "Зняти вибір патчу",
|
"unselectPatch": "Скасувати вибір патча",
|
||||||
"tooltip": "Більше варіантів вводу",
|
"tooltip": "Більше варіантів вводу",
|
||||||
"selectFilePath": "Оберіть шлях до файлу",
|
"selectFilePath": "Оберіть шлях до файлу",
|
||||||
"selectFolder": "Оберіть теку",
|
"selectFolder": "Оберіть теку",
|
||||||
"selectOption": "Вибрати параметр",
|
"selectOption": "Вибрати параметр",
|
||||||
"requiredOption": "Цей параметр є обов’язковим",
|
"requiredOption": "Встановлення цього параметра є обов'язковим",
|
||||||
"unsupportedOption": "Цей параметр не підтримується",
|
"unsupportedOption": "Цей параметр не підтримується",
|
||||||
"requiredOptionNull": "Необхідно встановити наступні параметри:\n\n${options}"
|
"requiredOptionNull": "Необхідно встановити наступні параметри:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -118,16 +118,18 @@
|
|||||||
},
|
},
|
||||||
"patchOptionsView": {
|
"patchOptionsView": {
|
||||||
"customValue": "自定义值",
|
"customValue": "自定义值",
|
||||||
|
"setToNull": "设置为为空",
|
||||||
|
"nullValue": "此选项值当前为空",
|
||||||
"resetOptionsTooltip": "重置补丁选项",
|
"resetOptionsTooltip": "重置补丁选项",
|
||||||
"viewTitle": "补丁选项",
|
"viewTitle": "补丁选项",
|
||||||
"saveOptions": "保存",
|
"saveOptions": "保存",
|
||||||
"addOptions": "添加选项",
|
"addOptions": "添加选项",
|
||||||
"deselectPatch": "取消选择补丁",
|
"unselectPatch": "取消选择补丁",
|
||||||
"tooltip": "更多输入选项",
|
"tooltip": "更多输入选项",
|
||||||
"selectFilePath": "选择文件路径",
|
"selectFilePath": "选择文件路径",
|
||||||
"selectFolder": "选择文件夹",
|
"selectFolder": "选择文件夹",
|
||||||
"selectOption": "选择选项",
|
"selectOption": "选择选项",
|
||||||
"requiredOption": "必须填写此选项",
|
"requiredOption": "设置此选项是必需的",
|
||||||
"unsupportedOption": "不支持此选项",
|
"unsupportedOption": "不支持此选项",
|
||||||
"requiredOptionNull": "必须设置以下选项:\n\n${options}"
|
"requiredOptionNull": "必须设置以下选项:\n\n${options}"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ To use ReVanced on your Android device, ReVanced Manager must be first installed
|
|||||||
|
|
||||||
## ✅ Installation steps
|
## ✅ Installation steps
|
||||||
|
|
||||||
1. Download the latest version of ReVanced Manager at [revanced.app/download](https://revanced.app/download) or from [GitHub releases](https://github.com/ReVanced/revanced-manager/releases)
|
1. Download the latest version of ReVanced Manager at [revanced.app/download](https://revanced.app/download) or from [GitHub releases](https://github.com/ReVanced/revanced-manager/releases/latest)
|
||||||
2. Install ReVanced Manager
|
2. Install ReVanced Manager
|
||||||
|
|
||||||
## ⏭️ What's next
|
## ⏭️ What's next
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ class PatchedApplication {
|
|||||||
this.isRooted = false,
|
this.isRooted = false,
|
||||||
this.isFromStorage = false,
|
this.isFromStorage = false,
|
||||||
this.appliedPatches = const [],
|
this.appliedPatches = const [],
|
||||||
|
this.patchedFilePath = '',
|
||||||
|
this.fileSize = 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory PatchedApplication.fromJson(Map<String, dynamic> json) =>
|
factory PatchedApplication.fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -33,6 +35,8 @@ class PatchedApplication {
|
|||||||
bool isRooted;
|
bool isRooted;
|
||||||
bool isFromStorage;
|
bool isFromStorage;
|
||||||
List<String> appliedPatches;
|
List<String> appliedPatches;
|
||||||
|
String patchedFilePath;
|
||||||
|
int fileSize;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$PatchedApplicationToJson(this);
|
Map<String, dynamic> toJson() => _$PatchedApplicationToJson(this);
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ 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/services/download_manager.dart';
|
import 'package:revanced_manager/services/download_manager.dart';
|
||||||
import 'package:revanced_manager/services/manager_api.dart';
|
import 'package:revanced_manager/services/manager_api.dart';
|
||||||
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
@lazySingleton
|
@lazySingleton
|
||||||
class GithubAPI {
|
class GithubAPI {
|
||||||
late final Dio _dio;
|
late final Dio _dio;
|
||||||
late final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
late final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
||||||
late final DownloadManager _downloadManager = locator<DownloadManager>();
|
late final DownloadManager _downloadManager = locator<DownloadManager>();
|
||||||
|
final Map<String, Lock> _lockMap = {};
|
||||||
|
|
||||||
Future<void> initialize(String repoUrl) async {
|
Future<void> initialize(String repoUrl) async {
|
||||||
_dio = _downloadManager.initDio(repoUrl);
|
_dio = _downloadManager.initDio(repoUrl);
|
||||||
@@ -21,11 +23,21 @@ class GithubAPI {
|
|||||||
await _downloadManager.clearAllCache();
|
await _downloadManager.clearAllCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Response> _dioGetSynchronously(String path) async {
|
||||||
|
// Create a new Lock for each path
|
||||||
|
if (!_lockMap.containsKey(path)) {
|
||||||
|
_lockMap[path] = Lock();
|
||||||
|
}
|
||||||
|
return _lockMap[path]!.synchronized(() async {
|
||||||
|
return await _dio.get(path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>?> getLatestRelease(
|
Future<Map<String, dynamic>?> getLatestRelease(
|
||||||
String repoName,
|
String repoName,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
final response = await _dio.get(
|
final response = await _dioGetSynchronously(
|
||||||
'/repos/$repoName/releases/latest',
|
'/repos/$repoName/releases/latest',
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
@@ -37,36 +49,27 @@ class GithubAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>?> getLatestManagerRelease(
|
Future<String?> getManagerChangelogs() async {
|
||||||
String repoName,
|
|
||||||
) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await _dio.get(
|
final response = await _dioGetSynchronously(
|
||||||
'/repos/$repoName/releases',
|
'/repos/${_managerAPI.defaultManagerRepo}/releases?per_page=50',
|
||||||
);
|
);
|
||||||
final Map<String, dynamic> releases = response.data[0];
|
final buffer = StringBuffer();
|
||||||
int updates = 0;
|
|
||||||
final String currentVersion =
|
final String currentVersion =
|
||||||
await _managerAPI.getCurrentManagerVersion();
|
await _managerAPI.getCurrentManagerVersion();
|
||||||
while (response.data[updates]['tag_name'] != currentVersion) {
|
for (final release in response.data) {
|
||||||
updates++;
|
if (release['tag_name'] == currentVersion) {
|
||||||
}
|
if (buffer.isEmpty) {
|
||||||
for (int i = 1; i < updates; i++) {
|
buffer.writeln(release['body']);
|
||||||
if (response.data[i]['prerelease']) {
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (release['prerelease']) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
releases.update(
|
buffer.writeln(release['body']);
|
||||||
'body',
|
|
||||||
(value) =>
|
|
||||||
value +
|
|
||||||
'\n' +
|
|
||||||
'# ' +
|
|
||||||
response.data[i]['tag_name'] +
|
|
||||||
'\n' +
|
|
||||||
response.data[i]['body'],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return releases;
|
return buffer.toString();
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print(e);
|
print(e);
|
||||||
@@ -87,7 +90,7 @@ class GithubAPI {
|
|||||||
url,
|
url,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final response = await _dio.get(
|
final response = await _dioGetSynchronously(
|
||||||
'/repos/$repoName/releases/tags/$version',
|
'/repos/$repoName/releases/tags/$version',
|
||||||
);
|
);
|
||||||
final Map<String, dynamic>? release = response.data;
|
final Map<String, dynamic>? release = response.data;
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ class ManagerAPI {
|
|||||||
final String cliRepo = 'revanced-cli';
|
final String cliRepo = 'revanced-cli';
|
||||||
late SharedPreferences _prefs;
|
late SharedPreferences _prefs;
|
||||||
List<Patch> patches = [];
|
List<Patch> patches = [];
|
||||||
List<Option> modifiedOptions = [];
|
|
||||||
List<Option> options = [];
|
List<Option> options = [];
|
||||||
Patch? selectedPatch;
|
Patch? selectedPatch;
|
||||||
BuildContext? ctx;
|
BuildContext? ctx;
|
||||||
@@ -39,6 +38,8 @@ class ManagerAPI {
|
|||||||
bool releaseBuild = false;
|
bool releaseBuild = false;
|
||||||
bool suggestedAppVersionSelected = true;
|
bool suggestedAppVersionSelected = true;
|
||||||
bool isDynamicThemeAvailable = false;
|
bool isDynamicThemeAvailable = false;
|
||||||
|
bool isScopedStorageAvailable = false;
|
||||||
|
int sdkVersion = 0;
|
||||||
String storedPatchesFile = '/selected-patches.json';
|
String storedPatchesFile = '/selected-patches.json';
|
||||||
String keystoreFile =
|
String keystoreFile =
|
||||||
'/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore';
|
'/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore';
|
||||||
@@ -56,8 +57,13 @@ class ManagerAPI {
|
|||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
_prefs = await SharedPreferences.getInstance();
|
_prefs = await SharedPreferences.getInstance();
|
||||||
isRooted = await _rootAPI.isRooted();
|
isRooted = await _rootAPI.isRooted();
|
||||||
|
if (sdkVersion == 0) {
|
||||||
|
sdkVersion = await getSdkVersion();
|
||||||
|
}
|
||||||
isDynamicThemeAvailable =
|
isDynamicThemeAvailable =
|
||||||
(await getSdkVersion()) >= 31; // ANDROID_12_SDK_VERSION = 31
|
sdkVersion >= 31; // ANDROID_12_SDK_VERSION = 31
|
||||||
|
isScopedStorageAvailable =
|
||||||
|
sdkVersion >= 30; // ANDROID_11_SDK_VERSION = 30
|
||||||
storedPatchesFile =
|
storedPatchesFile =
|
||||||
(await getApplicationDocumentsDirectory()).path + storedPatchesFile;
|
(await getApplicationDocumentsDirectory()).path + storedPatchesFile;
|
||||||
if (kReleaseMode) {
|
if (kReleaseMode) {
|
||||||
@@ -296,6 +302,14 @@ class ManagerAPI {
|
|||||||
await _prefs.setBool('requireSuggestedAppVersionEnabled', value);
|
await _prefs.setBool('requireSuggestedAppVersionEnabled', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isLastPatchedAppEnabled() {
|
||||||
|
return _prefs.getBool('lastPatchedAppEnabled') ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> enableLastPatchedAppStatus(bool value) async {
|
||||||
|
await _prefs.setBool('lastPatchedAppEnabled', value);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> setKeystorePassword(String password) async {
|
Future<void> setKeystorePassword(String password) async {
|
||||||
await _prefs.setString('keystorePassword', password);
|
await _prefs.setString('keystorePassword', password);
|
||||||
}
|
}
|
||||||
@@ -328,6 +342,34 @@ class ManagerAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatchedApplication? getLastPatchedApp() {
|
||||||
|
final String? app = _prefs.getString('lastPatchedApp');
|
||||||
|
return app != null ? PatchedApplication.fromJson(jsonDecode(app)) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteLastPatchedApp() async {
|
||||||
|
final PatchedApplication? app = getLastPatchedApp();
|
||||||
|
if (app != null) {
|
||||||
|
final File file = File(app.patchedFilePath);
|
||||||
|
await file.delete();
|
||||||
|
await _prefs.remove('lastPatchedApp');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setLastPatchedApp(
|
||||||
|
PatchedApplication app,
|
||||||
|
File outFile,
|
||||||
|
) async {
|
||||||
|
deleteLastPatchedApp();
|
||||||
|
final Directory appCache = await getApplicationSupportDirectory();
|
||||||
|
app.patchedFilePath = outFile.copySync('${appCache.path}/lastPatchedApp.apk').path;
|
||||||
|
app.fileSize = outFile.lengthSync();
|
||||||
|
await _prefs.setString(
|
||||||
|
'lastPatchedApp',
|
||||||
|
json.encode(app.toJson()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
List<PatchedApplication> getPatchedApps() {
|
List<PatchedApplication> getPatchedApps() {
|
||||||
final List<String> apps = _prefs.getStringList('patchedApps') ?? [];
|
final List<String> apps = _prefs.getStringList('patchedApps') ?? [];
|
||||||
return apps.map((a) => PatchedApplication.fromJson(jsonDecode(a))).toList();
|
return apps.map((a) => PatchedApplication.fromJson(jsonDecode(a))).toList();
|
||||||
@@ -686,6 +728,16 @@ class ManagerAPI {
|
|||||||
patchedApps.addAll(mountedApps);
|
patchedApps.addAll(mountedApps);
|
||||||
|
|
||||||
await setPatchedApps(patchedApps);
|
await setPatchedApps(patchedApps);
|
||||||
|
|
||||||
|
// Delete the saved app if the file is not found.
|
||||||
|
final PatchedApplication? lastPatchedApp = getLastPatchedApp();
|
||||||
|
if (lastPatchedApp != null) {
|
||||||
|
final File file = File(lastPatchedApp.patchedFilePath);
|
||||||
|
if (!file.existsSync()) {
|
||||||
|
deleteLastPatchedApp();
|
||||||
|
_prefs.remove('lastPatchedApp');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> isAppUninstalled(PatchedApplication app) async {
|
Future<bool> isAppUninstalled(PatchedApplication app) async {
|
||||||
@@ -780,4 +832,82 @@ class ManagerAPI {
|
|||||||
selectedPatchesFile.deleteSync();
|
selectedPatchesFile.deleteSync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> installTypeDialog(BuildContext context) async {
|
||||||
|
final ValueNotifier<int> installType = ValueNotifier(0);
|
||||||
|
if (isRooted) {
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text(t.installerView.installType),
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
icon: const Icon(Icons.file_download_outlined),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: ValueListenableBuilder(
|
||||||
|
valueListenable: installType,
|
||||||
|
builder: (context, value, child) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 10,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
t.installerView.installTypeDescription,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RadioListTile(
|
||||||
|
title: Text(t.installerView.installNonRootType),
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
value: 0,
|
||||||
|
groupValue: value,
|
||||||
|
onChanged: (selected) {
|
||||||
|
installType.value = selected!;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
RadioListTile(
|
||||||
|
title: Text(t.installerView.installRootType),
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
value: 1,
|
||||||
|
groupValue: value,
|
||||||
|
onChanged: (selected) {
|
||||||
|
installType.value = selected!;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
OutlinedButton(
|
||||||
|
child: Text(t.cancelButton),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FilledButton(
|
||||||
|
child: Text(t.installerView.installButton),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ class PatcherAPI {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
PatchedApplication patchedApp,
|
PatchedApplication patchedApp,
|
||||||
) async {
|
) async {
|
||||||
if (outFile != null) {
|
if (patchedApp.patchedFilePath != '') {
|
||||||
_managerAPI.ctx = context;
|
_managerAPI.ctx = context;
|
||||||
try {
|
try {
|
||||||
if (patchedApp.isRooted) {
|
if (patchedApp.isRooted) {
|
||||||
@@ -232,7 +232,7 @@ class PatcherAPI {
|
|||||||
return await _rootAPI.install(
|
return await _rootAPI.install(
|
||||||
patchedApp.packageName,
|
patchedApp.packageName,
|
||||||
patchedApp.apkFilePath,
|
patchedApp.apkFilePath,
|
||||||
outFile!.path,
|
patchedApp.patchedFilePath,
|
||||||
)
|
)
|
||||||
? 0
|
? 0
|
||||||
: 1;
|
: 1;
|
||||||
@@ -246,7 +246,7 @@ class PatcherAPI {
|
|||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
return await installApk(
|
return await installApk(
|
||||||
context,
|
context,
|
||||||
outFile!.path,
|
patchedApp.patchedFilePath,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,13 +368,13 @@ class PatcherAPI {
|
|||||||
return cleanInstall ? 10 : 1;
|
return cleanInstall ? 10 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exportPatchedFile(String appName, String version) {
|
void exportPatchedFile(PatchedApplication app) {
|
||||||
try {
|
try {
|
||||||
if (outFile != null) {
|
if (outFile != null) {
|
||||||
final String newName = _getFileName(appName, version);
|
final String newName = _getFileName(app.name, app.version);
|
||||||
FlutterFileDialog.saveFile(
|
FlutterFileDialog.saveFile(
|
||||||
params: SaveFileDialogParams(
|
params: SaveFileDialogParams(
|
||||||
sourceFilePath: outFile!.path,
|
sourceFilePath: app.patchedFilePath,
|
||||||
fileName: newName,
|
fileName: newName,
|
||||||
mimeTypesFilter: ['application/vnd.android.package-archive'],
|
mimeTypesFilter: ['application/vnd.android.package-archive'],
|
||||||
),
|
),
|
||||||
@@ -387,14 +387,14 @@ class PatcherAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sharePatchedFile(String appName, String version) {
|
void sharePatchedFile(PatchedApplication app) {
|
||||||
try {
|
try {
|
||||||
if (outFile != null) {
|
if (outFile != null) {
|
||||||
final String newName = _getFileName(appName, version);
|
final String newName = _getFileName(app.name, app.version);
|
||||||
final int lastSeparator = outFile!.path.lastIndexOf('/');
|
final int lastSeparator = app.patchedFilePath.lastIndexOf('/');
|
||||||
final String newPath =
|
final String newPath =
|
||||||
outFile!.path.substring(0, lastSeparator + 1) + newName;
|
app.patchedFilePath.substring(0, lastSeparator + 1) + newName;
|
||||||
final File shareFile = outFile!.copySync(newPath);
|
final File shareFile = File(app.patchedFilePath).copySync(newPath);
|
||||||
Share.shareXFiles([XFile(shareFile.path)]);
|
Share.shareXFiles([XFile(shareFile.path)]);
|
||||||
}
|
}
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ var lightCustomTheme = ThemeData(
|
|||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
colorScheme: lightCustomColorScheme,
|
colorScheme: lightCustomColorScheme,
|
||||||
navigationBarTheme: NavigationBarThemeData(
|
navigationBarTheme: NavigationBarThemeData(
|
||||||
labelTextStyle: MaterialStateProperty.all(
|
labelTextStyle: WidgetStateProperty.all(
|
||||||
TextStyle(
|
TextStyle(
|
||||||
color: lightCustomColorScheme.onSurface,
|
color: lightCustomColorScheme.onSurface,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@@ -31,7 +31,7 @@ var darkCustomTheme = ThemeData(
|
|||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
colorScheme: darkCustomColorScheme,
|
colorScheme: darkCustomColorScheme,
|
||||||
navigationBarTheme: NavigationBarThemeData(
|
navigationBarTheme: NavigationBarThemeData(
|
||||||
labelTextStyle: MaterialStateProperty.all(
|
labelTextStyle: WidgetStateProperty.all(
|
||||||
TextStyle(
|
TextStyle(
|
||||||
color: darkCustomColorScheme.onSurface,
|
color: darkCustomColorScheme.onSurface,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@@ -24,14 +24,26 @@ class DynamicThemeBuilder extends StatefulWidget {
|
|||||||
|
|
||||||
class _DynamicThemeBuilderState extends State<DynamicThemeBuilder>
|
class _DynamicThemeBuilderState extends State<DynamicThemeBuilder>
|
||||||
with WidgetsBindingObserver {
|
with WidgetsBindingObserver {
|
||||||
Brightness brightness = PlatformDispatcher.instance.platformBrightness;
|
late Brightness brightness;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
brightness = PlatformDispatcher.instance.platformBrightness;
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
if (state == AppLifecycleState.resumed) {
|
||||||
|
final systemBrightness = PlatformDispatcher.instance.platformBrightness;
|
||||||
|
if (brightness != systemBrightness) {
|
||||||
|
brightness = systemBrightness;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DynamicColorBuilder(
|
return DynamicColorBuilder(
|
||||||
@@ -39,7 +51,7 @@ class _DynamicThemeBuilderState extends State<DynamicThemeBuilder>
|
|||||||
final ThemeData lightDynamicTheme = ThemeData(
|
final ThemeData lightDynamicTheme = ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
navigationBarTheme: NavigationBarThemeData(
|
navigationBarTheme: NavigationBarThemeData(
|
||||||
labelTextStyle: MaterialStateProperty.all(
|
labelTextStyle: WidgetStateProperty.all(
|
||||||
GoogleFonts.roboto(
|
GoogleFonts.roboto(
|
||||||
color: lightColorScheme?.onSurface,
|
color: lightColorScheme?.onSurface,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@@ -53,7 +65,7 @@ class _DynamicThemeBuilderState extends State<DynamicThemeBuilder>
|
|||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
navigationBarTheme: NavigationBarThemeData(
|
navigationBarTheme: NavigationBarThemeData(
|
||||||
labelTextStyle: MaterialStateProperty.all(
|
labelTextStyle: WidgetStateProperty.all(
|
||||||
GoogleFonts.roboto(
|
GoogleFonts.roboto(
|
||||||
color: darkColorScheme?.onSurface,
|
color: darkColorScheme?.onSurface,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import 'package:revanced_manager/services/manager_api.dart';
|
|||||||
import 'package:revanced_manager/services/patcher_api.dart';
|
import 'package:revanced_manager/services/patcher_api.dart';
|
||||||
import 'package:revanced_manager/services/toast.dart';
|
import 'package:revanced_manager/services/toast.dart';
|
||||||
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
||||||
|
import 'package:revanced_manager/utils/about_info.dart';
|
||||||
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
|
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
@@ -74,11 +75,14 @@ class AppSelectorViewModel extends BaseViewModel {
|
|||||||
required String packageName,
|
required String packageName,
|
||||||
}) async {
|
}) async {
|
||||||
final String suggestedVersion = getSuggestedVersion(packageName);
|
final String suggestedVersion = getSuggestedVersion(packageName);
|
||||||
|
final String architecture = await AboutInfo.getInfo().then((info) {
|
||||||
|
return info['supportedArch'][0];
|
||||||
|
});
|
||||||
|
|
||||||
if (suggestedVersion.isNotEmpty) {
|
if (suggestedVersion.isNotEmpty) {
|
||||||
await openDefaultBrowser('$packageName apk version $suggestedVersion');
|
await openDefaultBrowser('$packageName apk version $suggestedVersion $architecture');
|
||||||
} else {
|
} else {
|
||||||
await openDefaultBrowser('$packageName apk');
|
await openDefaultBrowser('$packageName apk $architecture');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +182,6 @@ class AppSelectorViewModel extends BaseViewModel {
|
|||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
FilledButton(
|
FilledButton(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:revanced_manager/app/app.locator.dart';
|
|||||||
import 'package:revanced_manager/gen/strings.g.dart';
|
import 'package:revanced_manager/gen/strings.g.dart';
|
||||||
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/homeView/installed_apps_card.dart';
|
import 'package:revanced_manager/ui/widgets/homeView/installed_apps_card.dart';
|
||||||
|
import 'package:revanced_manager/ui/widgets/homeView/last_patched_app_card.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/homeView/latest_commit_card.dart';
|
import 'package:revanced_manager/ui/widgets/homeView/latest_commit_card.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart';
|
import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
@@ -20,7 +21,9 @@ class HomeView extends StatelessWidget {
|
|||||||
viewModelBuilder: () => locator<HomeViewModel>(),
|
viewModelBuilder: () => locator<HomeViewModel>(),
|
||||||
builder: (context, model, child) => Scaffold(
|
builder: (context, model, child) => Scaffold(
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: () => model.forceRefresh(context),
|
edgeOffset: 110.0,
|
||||||
|
displacement: 10.0,
|
||||||
|
onRefresh: () async => await model.forceRefresh(context),
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
slivers: <Widget>[
|
slivers: <Widget>[
|
||||||
CustomSliverAppBar(
|
CustomSliverAppBar(
|
||||||
@@ -44,6 +47,21 @@ class HomeView extends StatelessWidget {
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
LatestCommitCard(model: model, parentContext: context),
|
LatestCommitCard(model: model, parentContext: context),
|
||||||
const SizedBox(height: 23),
|
const SizedBox(height: 23),
|
||||||
|
Visibility(
|
||||||
|
visible: model.isLastPatchedAppEnabled(),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
t.homeView.lastPatchedAppSubtitle,
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
LastPatchedAppCard(),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
t.homeView.patchedSubtitle,
|
t.homeView.patchedSubtitle,
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
|
|||||||
@@ -35,11 +35,13 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
final Toast _toast = locator<Toast>();
|
final Toast _toast = locator<Toast>();
|
||||||
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||||
bool showUpdatableApps = false;
|
bool showUpdatableApps = false;
|
||||||
|
PatchedApplication? lastPatchedApp;
|
||||||
bool releaseBuild = false;
|
bool releaseBuild = false;
|
||||||
List<PatchedApplication> patchedInstalledApps = [];
|
List<PatchedApplication> patchedInstalledApps = [];
|
||||||
String _currentManagerVersion = '';
|
String _currentManagerVersion = '';
|
||||||
String _currentPatchesVersion = '';
|
String _currentPatchesVersion = '';
|
||||||
String? _latestManagerVersion = '';
|
String? latestManagerVersion;
|
||||||
|
String? latestPatchesVersion;
|
||||||
File? downloadedApk;
|
File? downloadedApk;
|
||||||
|
|
||||||
Future<void> initialize(BuildContext context) async {
|
Future<void> initialize(BuildContext context) async {
|
||||||
@@ -50,7 +52,6 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
await forceRefresh(context);
|
await forceRefresh(context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_latestManagerVersion = await _managerAPI.getLatestManagerVersion();
|
|
||||||
_currentPatchesVersion = await _managerAPI.getCurrentPatchesVersion();
|
_currentPatchesVersion = await _managerAPI.getCurrentPatchesVersion();
|
||||||
if (_managerAPI.showUpdateDialog() && await hasManagerUpdates()) {
|
if (_managerAPI.showUpdateDialog() && await hasManagerUpdates()) {
|
||||||
showUpdateDialog(context, false);
|
showUpdateDialog(context, false);
|
||||||
@@ -102,10 +103,10 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void navigateToAppInfo(PatchedApplication app) {
|
void navigateToAppInfo(PatchedApplication app, bool isLastPatchedApp) {
|
||||||
_navigationService.navigateTo(
|
_navigationService.navigateTo(
|
||||||
Routes.appInfoView,
|
Routes.appInfoView,
|
||||||
arguments: AppInfoViewArguments(app: app),
|
arguments: AppInfoViewArguments(app: app, isLastPatchedApp: isLastPatchedApp),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,29 +124,34 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void getPatchedApps() {
|
void getPatchedApps() {
|
||||||
|
lastPatchedApp = _managerAPI.getLastPatchedApp();
|
||||||
patchedInstalledApps = _managerAPI.getPatchedApps().toList();
|
patchedInstalledApps = _managerAPI.getPatchedApps().toList();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isLastPatchedAppEnabled() {
|
||||||
|
return _managerAPI.isLastPatchedAppEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> hasManagerUpdates() async {
|
Future<bool> hasManagerUpdates() async {
|
||||||
if (!_managerAPI.releaseBuild) {
|
if (!_managerAPI.releaseBuild) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_latestManagerVersion =
|
latestManagerVersion =
|
||||||
await _managerAPI.getLatestManagerVersion() ?? _currentManagerVersion;
|
await _managerAPI.getLatestManagerVersion() ?? _currentManagerVersion;
|
||||||
|
|
||||||
if (_latestManagerVersion != _currentManagerVersion) {
|
if (latestManagerVersion != _currentManagerVersion) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> hasPatchesUpdates() async {
|
Future<bool> hasPatchesUpdates() async {
|
||||||
final String? latestVersion = await _managerAPI.getLatestPatchesVersion();
|
latestPatchesVersion = await _managerAPI.getLatestPatchesVersion();
|
||||||
if (latestVersion != null) {
|
if (latestPatchesVersion != null) {
|
||||||
try {
|
try {
|
||||||
final int latestVersionInt =
|
final int latestVersionInt =
|
||||||
int.parse(latestVersion.replaceAll(RegExp('[^0-9]'), ''));
|
int.parse(latestPatchesVersion!.replaceAll(RegExp('[^0-9]'), ''));
|
||||||
final int currentVersionInt =
|
final int currentVersionInt =
|
||||||
int.parse(_currentPatchesVersion.replaceAll(RegExp('[^0-9]'), ''));
|
int.parse(_currentPatchesVersion.replaceAll(RegExp('[^0-9]'), ''));
|
||||||
return latestVersionInt > currentVersionInt;
|
return latestVersionInt > currentVersionInt;
|
||||||
@@ -452,10 +458,6 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatesAreDisabled() {
|
|
||||||
_toast.showBottom(t.homeView.updatesDisabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> showUpdateConfirmationDialog(
|
Future<void> showUpdateConfirmationDialog(
|
||||||
BuildContext parentContext,
|
BuildContext parentContext,
|
||||||
bool isPatches, [
|
bool isPatches, [
|
||||||
@@ -475,12 +477,14 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>?> getLatestManagerRelease() {
|
Future<String?> getManagerChangelogs() {
|
||||||
return _githubAPI.getLatestManagerRelease(_managerAPI.defaultManagerRepo);
|
return _githubAPI.getManagerChangelogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>?> getLatestPatchesRelease() {
|
Future<String?> getLatestPatchesChangelog() async {
|
||||||
return _githubAPI.getLatestRelease(_managerAPI.defaultPatchesRepo);
|
final release =
|
||||||
|
await _githubAPI.getLatestRelease(_managerAPI.defaultPatchesRepo);
|
||||||
|
return release?['body'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getLatestPatchesReleaseTime() {
|
Future<String?> getLatestPatchesReleaseTime() {
|
||||||
@@ -492,8 +496,8 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> forceRefresh(BuildContext context) async {
|
Future<void> forceRefresh(BuildContext context) async {
|
||||||
_managerAPI.clearAllData();
|
await _managerAPI.clearAllData();
|
||||||
|
await initialize(context);
|
||||||
_toast.showBottom(t.homeView.refreshSuccess);
|
_toast.showBottom(t.homeView.refreshSuccess);
|
||||||
initialize(context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
});
|
});
|
||||||
await WakelockPlus.enable();
|
await WakelockPlus.enable();
|
||||||
await handlePlatformChannelMethods();
|
await handlePlatformChannelMethods();
|
||||||
await runPatcher();
|
await runPatcher(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> handlePlatformChannelMethods() async {
|
Future<dynamic> handlePlatformChannelMethods() async {
|
||||||
@@ -182,13 +182,20 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> runPatcher() async {
|
Future<void> runPatcher(BuildContext context) async {
|
||||||
try {
|
try {
|
||||||
await _patcherAPI.runPatcher(
|
await _patcherAPI.runPatcher(
|
||||||
_app.packageName,
|
_app.packageName,
|
||||||
_app.apkFilePath,
|
_app.apkFilePath,
|
||||||
_patches,
|
_patches,
|
||||||
);
|
);
|
||||||
|
_app.appliedPatches = _patches.map((p) => p.name).toList();
|
||||||
|
if (_managerAPI.isLastPatchedAppEnabled()) {
|
||||||
|
await _managerAPI.setLastPatchedApp(_app, _patcherAPI.outFile!);
|
||||||
|
} else {
|
||||||
|
_app.patchedFilePath = _patcherAPI.outFile!.path;
|
||||||
|
}
|
||||||
|
locator<HomeViewModel>().initialize(context);
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
update(
|
update(
|
||||||
-100.0,
|
-100.0,
|
||||||
@@ -488,7 +495,7 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
Future<void> installResult(BuildContext context, bool installAsRoot) async {
|
Future<void> installResult(BuildContext context, bool installAsRoot) async {
|
||||||
isInstalling = true;
|
isInstalling = true;
|
||||||
try {
|
try {
|
||||||
_app.isRooted = installAsRoot;
|
_app.isRooted = await _managerAPI.installTypeDialog(context);
|
||||||
if (headerLogs != 'Installing...') {
|
if (headerLogs != 'Installing...') {
|
||||||
update(
|
update(
|
||||||
.85,
|
.85,
|
||||||
@@ -501,17 +508,15 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
isInstalled = true;
|
isInstalled = true;
|
||||||
_app.isFromStorage = false;
|
_app.isFromStorage = false;
|
||||||
_app.patchDate = DateTime.now();
|
_app.patchDate = DateTime.now();
|
||||||
_app.appliedPatches = _patches.map((p) => p.name).toList();
|
|
||||||
|
|
||||||
// In case a patch changed the app name or package name,
|
// In case a patch changed the app name or package name,
|
||||||
// update the app info.
|
// update the app info.
|
||||||
final app =
|
final app =
|
||||||
await DeviceApps.getAppFromStorage(_patcherAPI.outFile!.path);
|
await DeviceApps.getAppFromStorage(_patcherAPI.outFile!.path);
|
||||||
if (app != null) {
|
if (app != null) {
|
||||||
_app.name = app.appName;
|
_app.name = app.appName;
|
||||||
_app.packageName = app.packageName;
|
_app.packageName = app.packageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _managerAPI.savePatchedApp(_app);
|
await _managerAPI.savePatchedApp(_app);
|
||||||
|
|
||||||
_managerAPI
|
_managerAPI
|
||||||
@@ -544,7 +549,7 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
|
|
||||||
void exportResult() {
|
void exportResult() {
|
||||||
try {
|
try {
|
||||||
_patcherAPI.exportPatchedFile(_app.name, _app.version);
|
_patcherAPI.exportPatchedFile(_app);
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print(e);
|
print(e);
|
||||||
|
|||||||
@@ -37,79 +37,35 @@ class PatchOptionsView extends StatelessWidget {
|
|||||||
color: Theme.of(context).textTheme.titleLarge!.color,
|
color: Theme.of(context).textTheme.titleLarge!.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
|
||||||
IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
model.resetOptions();
|
|
||||||
},
|
|
||||||
icon: const Icon(
|
|
||||||
Icons.history,
|
|
||||||
),
|
|
||||||
tooltip: t.patchOptionsView.resetOptionsTooltip,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
for (final Option option in model.visibleOptions)
|
for (final Option option in model.modifiedOptions)
|
||||||
if (option.valueType == 'String' ||
|
if (option.valueType == 'String' ||
|
||||||
option.valueType == 'Int')
|
option.valueType == 'Int')
|
||||||
IntAndStringPatchOption(
|
IntAndStringPatchOption(
|
||||||
patchOption: option,
|
patchOption: option,
|
||||||
removeOption: (option) {
|
model: model,
|
||||||
model.removeOption(option);
|
|
||||||
},
|
|
||||||
onChanged: (value, option) {
|
|
||||||
model.modifyOptions(value, option);
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
else if (option.valueType == 'Boolean')
|
else if (option.valueType == 'Boolean')
|
||||||
BooleanPatchOption(
|
BooleanPatchOption(
|
||||||
patchOption: option,
|
patchOption: option,
|
||||||
removeOption: (option) {
|
model: model,
|
||||||
model.removeOption(option);
|
|
||||||
},
|
|
||||||
onChanged: (value, option) {
|
|
||||||
model.modifyOptions(value, option);
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
else if (option.valueType == 'StringArray' ||
|
else if (option.valueType == 'StringArray' ||
|
||||||
option.valueType == 'IntArray' ||
|
option.valueType == 'IntArray' ||
|
||||||
option.valueType == 'LongArray')
|
option.valueType == 'LongArray')
|
||||||
IntStringLongListPatchOption(
|
IntStringLongListPatchOption(
|
||||||
patchOption: option,
|
patchOption: option,
|
||||||
removeOption: (option) {
|
model: model,
|
||||||
model.removeOption(option);
|
|
||||||
},
|
|
||||||
onChanged: (value, option) {
|
|
||||||
model.modifyOptions(value, option);
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
UnsupportedPatchOption(
|
UnsupportedPatchOption(
|
||||||
patchOption: option,
|
patchOption: option,
|
||||||
),
|
),
|
||||||
if (model.visibleOptions.length !=
|
|
||||||
model.options.length) ...[
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
FilledButton(
|
|
||||||
onPressed: () {
|
|
||||||
model.showAddOptionDialog(context);
|
|
||||||
},
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.add),
|
|
||||||
Text(t.patchOptionsView.addOptions),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 80,
|
height: 80,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:revanced_manager/models/patch.dart';
|
|||||||
import 'package:revanced_manager/services/manager_api.dart';
|
import 'package:revanced_manager/services/manager_api.dart';
|
||||||
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
class PatchOptionsViewModel extends BaseViewModel {
|
class PatchOptionsViewModel extends BaseViewModel {
|
||||||
@@ -14,7 +13,7 @@ class PatchOptionsViewModel extends BaseViewModel {
|
|||||||
locator<PatcherViewModel>().selectedApp!.packageName;
|
locator<PatcherViewModel>().selectedApp!.packageName;
|
||||||
List<Option> options = [];
|
List<Option> options = [];
|
||||||
List<Option> savedOptions = [];
|
List<Option> savedOptions = [];
|
||||||
List<Option> visibleOptions = [];
|
List<Option> modifiedOptions = [];
|
||||||
|
|
||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
options = getDefaultOptions();
|
options = getDefaultOptions();
|
||||||
@@ -28,36 +27,18 @@ class PatchOptionsViewModel extends BaseViewModel {
|
|||||||
savedOptions.add(savedOption);
|
savedOptions.add(savedOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (savedOptions.isNotEmpty) {
|
modifiedOptions = [
|
||||||
visibleOptions = [
|
...savedOptions,
|
||||||
...savedOptions,
|
...options.where(
|
||||||
...options.where(
|
(option) => !savedOptions.any((sOption) => sOption.key == option.key),
|
||||||
(option) =>
|
),
|
||||||
option.required &&
|
];
|
||||||
!savedOptions.any((sOption) => sOption.key == option.key),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
visibleOptions = [
|
|
||||||
...options.where((option) => option.required),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void addOption(Option option) {
|
|
||||||
visibleOptions.add(option);
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeOption(Option option) {
|
|
||||||
visibleOptions.removeWhere((vOption) => vOption.key == option.key);
|
|
||||||
notifyListeners();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool saveOptions(BuildContext context) {
|
bool saveOptions(BuildContext context) {
|
||||||
final List<Option> requiredNullOptions = [];
|
final List<Option> requiredNullOptions = [];
|
||||||
for (final Option option in options) {
|
for (final Option option in options) {
|
||||||
if (!visibleOptions.any((vOption) => vOption.key == option.key)) {
|
if (modifiedOptions.any((mOption) => mOption.key == option.key)) {
|
||||||
_managerAPI.clearPatchOption(
|
_managerAPI.clearPatchOption(
|
||||||
selectedApp,
|
selectedApp,
|
||||||
_managerAPI.selectedPatch!.name,
|
_managerAPI.selectedPatch!.name,
|
||||||
@@ -65,7 +46,7 @@ class PatchOptionsViewModel extends BaseViewModel {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final Option option in visibleOptions) {
|
for (final Option option in modifiedOptions) {
|
||||||
if (option.required && option.value == null) {
|
if (option.required && option.value == null) {
|
||||||
requiredNullOptions.add(option);
|
requiredNullOptions.add(option);
|
||||||
} else {
|
} else {
|
||||||
@@ -98,11 +79,8 @@ class PatchOptionsViewModel extends BaseViewModel {
|
|||||||
required: option.required,
|
required: option.required,
|
||||||
key: option.key,
|
key: option.key,
|
||||||
);
|
);
|
||||||
visibleOptions[visibleOptions
|
modifiedOptions.removeWhere((mOption) => mOption.key == option.key);
|
||||||
.indexWhere((vOption) => vOption.key == option.key)] = modifiedOption;
|
modifiedOptions.add(modifiedOption);
|
||||||
_managerAPI.modifiedOptions
|
|
||||||
.removeWhere((mOption) => mOption.key == option.key);
|
|
||||||
_managerAPI.modifiedOptions.add(modifiedOption);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Option> getDefaultOptions() {
|
List<Option> getDefaultOptions() {
|
||||||
@@ -122,93 +100,11 @@ class PatchOptionsViewModel extends BaseViewModel {
|
|||||||
return defaultOptions;
|
return defaultOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetOptions() {
|
dynamic getDefaultValue(Option patchOption) => _managerAPI.options
|
||||||
_managerAPI.modifiedOptions.clear();
|
.firstWhere(
|
||||||
visibleOptions =
|
(option) => option.key == patchOption.key,
|
||||||
getDefaultOptions().where((option) => option.required).toList();
|
)
|
||||||
notifyListeners();
|
.value;
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> showAddOptionDialog(BuildContext context) async {
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
t.patchOptionsView.addOptions,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
FilledButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Text(t.cancelButton),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
contentPadding: const EdgeInsets.all(8),
|
|
||||||
content: Wrap(
|
|
||||||
spacing: 14,
|
|
||||||
runSpacing: 14,
|
|
||||||
children: options
|
|
||||||
.where(
|
|
||||||
(option) =>
|
|
||||||
!visibleOptions.any((vOption) => vOption.key == option.key),
|
|
||||||
)
|
|
||||||
.map((e) {
|
|
||||||
return CustomCard(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
|
||||||
onTap: () {
|
|
||||||
addOption(e);
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
e.title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
Text(
|
|
||||||
e.description,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> showRequiredOptionNullDialog(
|
Future<void> showRequiredOptionNullDialog(
|
||||||
@@ -248,7 +144,7 @@ Future<void> showRequiredOptionNullDialog(
|
|||||||
PatchesSelectorViewModel().showPatchesChangeDialog(context);
|
PatchesSelectorViewModel().showPatchesChangeDialog(context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text(t.patchOptionsView.deselectPatch),
|
child: Text(t.patchOptionsView.unselectPatch),
|
||||||
),
|
),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ class PatchesSelectorViewModel extends BaseViewModel {
|
|||||||
void navigateToPatchOptions(List<Option> setOptions, Patch patch) {
|
void navigateToPatchOptions(List<Option> setOptions, Patch patch) {
|
||||||
_managerAPI.options = setOptions;
|
_managerAPI.options = setOptions;
|
||||||
_managerAPI.selectedPatch = patch;
|
_managerAPI.selectedPatch = patch;
|
||||||
_managerAPI.modifiedOptions.clear();
|
|
||||||
_navigationService.navigateToPatchOptionsView();
|
_navigationService.navigateToPatchOptionsView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,9 +301,16 @@ class PatchesSelectorViewModel extends BaseViewModel {
|
|||||||
|
|
||||||
Future<void> loadSelectedPatches(BuildContext context) async {
|
Future<void> loadSelectedPatches(BuildContext context) async {
|
||||||
if (_managerAPI.isPatchesChangeEnabled()) {
|
if (_managerAPI.isPatchesChangeEnabled()) {
|
||||||
final List<String> selectedPatches = await _managerAPI.getSelectedPatches(
|
final List<String>? appliedPatches = _managerAPI
|
||||||
locator<PatcherViewModel>().selectedApp!.packageName,
|
.getPatchedApps()
|
||||||
);
|
.firstWhereOrNull(
|
||||||
|
(app) => app.packageName == selectedApp!.packageName,
|
||||||
|
)
|
||||||
|
?.appliedPatches;
|
||||||
|
final List<String> selectedPatches = appliedPatches ??
|
||||||
|
await _managerAPI.getSelectedPatches(
|
||||||
|
selectedApp!.packageName,
|
||||||
|
);
|
||||||
if (selectedPatches.isNotEmpty) {
|
if (selectedPatches.isNotEmpty) {
|
||||||
this.selectedPatches.clear();
|
this.selectedPatches.clear();
|
||||||
this.selectedPatches.addAll(
|
this.selectedPatches.addAll(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class SManageSources extends BaseViewModel {
|
|||||||
return showDialog(
|
return showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
|
scrollable: true,
|
||||||
title: Row(
|
title: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -39,75 +40,73 @@ class SManageSources extends BaseViewModel {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: SingleChildScrollView(
|
content: Column(
|
||||||
child: Column(
|
children: <Widget>[
|
||||||
children: <Widget>[
|
TextField(
|
||||||
TextField(
|
controller: _orgPatSourceController,
|
||||||
controller: _orgPatSourceController,
|
autocorrect: false,
|
||||||
autocorrect: false,
|
onChanged: (value) => notifyListeners(),
|
||||||
onChanged: (value) => notifyListeners(),
|
decoration: InputDecoration(
|
||||||
decoration: InputDecoration(
|
icon: Icon(
|
||||||
icon: Icon(
|
Icons.extension_outlined,
|
||||||
Icons.extension_outlined,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
labelText: t.settingsView.orgPatchesLabel,
|
|
||||||
hintText: patchesRepo.split('/')[0],
|
|
||||||
),
|
),
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
labelText: t.settingsView.orgPatchesLabel,
|
||||||
|
hintText: patchesRepo.split('/')[0],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
),
|
||||||
// Patches repository's name
|
const SizedBox(height: 8),
|
||||||
TextField(
|
// Patches repository's name
|
||||||
controller: _patSourceController,
|
TextField(
|
||||||
autocorrect: false,
|
controller: _patSourceController,
|
||||||
onChanged: (value) => notifyListeners(),
|
autocorrect: false,
|
||||||
decoration: InputDecoration(
|
onChanged: (value) => notifyListeners(),
|
||||||
icon: const Icon(
|
decoration: InputDecoration(
|
||||||
Icons.extension_outlined,
|
icon: const Icon(
|
||||||
color: Colors.transparent,
|
Icons.extension_outlined,
|
||||||
),
|
color: Colors.transparent,
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
labelText: t.settingsView.sourcesPatchesLabel,
|
|
||||||
hintText: patchesRepo.split('/')[1],
|
|
||||||
),
|
),
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
labelText: t.settingsView.sourcesPatchesLabel,
|
||||||
|
hintText: patchesRepo.split('/')[1],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
),
|
||||||
// Integrations owner's name
|
const SizedBox(height: 8),
|
||||||
TextField(
|
// Integrations owner's name
|
||||||
controller: _orgIntSourceController,
|
TextField(
|
||||||
autocorrect: false,
|
controller: _orgIntSourceController,
|
||||||
onChanged: (value) => notifyListeners(),
|
autocorrect: false,
|
||||||
decoration: InputDecoration(
|
onChanged: (value) => notifyListeners(),
|
||||||
icon: Icon(
|
decoration: InputDecoration(
|
||||||
Icons.merge_outlined,
|
icon: Icon(
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
Icons.merge_outlined,
|
||||||
),
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
labelText: t.settingsView.orgIntegrationsLabel,
|
|
||||||
hintText: integrationsRepo.split('/')[0],
|
|
||||||
),
|
),
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
labelText: t.settingsView.orgIntegrationsLabel,
|
||||||
|
hintText: integrationsRepo.split('/')[0],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
),
|
||||||
// Integrations repository's name
|
const SizedBox(height: 8),
|
||||||
TextField(
|
// Integrations repository's name
|
||||||
controller: _intSourceController,
|
TextField(
|
||||||
autocorrect: false,
|
controller: _intSourceController,
|
||||||
onChanged: (value) => notifyListeners(),
|
autocorrect: false,
|
||||||
decoration: InputDecoration(
|
onChanged: (value) => notifyListeners(),
|
||||||
icon: const Icon(
|
decoration: InputDecoration(
|
||||||
Icons.merge_outlined,
|
icon: const Icon(
|
||||||
color: Colors.transparent,
|
Icons.merge_outlined,
|
||||||
),
|
color: Colors.transparent,
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
labelText: t.settingsView.sourcesIntegrationsLabel,
|
|
||||||
hintText: integrationsRepo.split('/')[1],
|
|
||||||
),
|
),
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
labelText: t.settingsView.sourcesIntegrationsLabel,
|
||||||
|
hintText: integrationsRepo.split('/')[1],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
),
|
||||||
Text(t.settingsView.sourcesUpdateNote),
|
const SizedBox(height: 20),
|
||||||
],
|
Text(t.settingsView.sourcesUpdateNote),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:language_code/language_code.dart';
|
import 'package:language_code/language_code.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/gen/strings.g.dart';
|
import 'package:revanced_manager/gen/strings.g.dart';
|
||||||
import 'package:revanced_manager/services/manager_api.dart';
|
import 'package:revanced_manager/services/manager_api.dart';
|
||||||
import 'package:revanced_manager/services/toast.dart';
|
import 'package:revanced_manager/services/toast.dart';
|
||||||
@@ -10,8 +11,10 @@ import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
|||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart';
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.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';
|
||||||
|
|
||||||
final _settingViewModel = SettingsViewModel();
|
final _settingViewModel = SettingsViewModel();
|
||||||
|
final _navigationService = NavigationService();
|
||||||
|
|
||||||
class SUpdateLanguage extends BaseViewModel {
|
class SUpdateLanguage extends BaseViewModel {
|
||||||
final Toast _toast = locator<Toast>();
|
final Toast _toast = locator<Toast>();
|
||||||
@@ -108,10 +111,9 @@ class SUpdateLanguage extends BaseViewModel {
|
|||||||
child: Text(t.cancelButton),
|
child: Text(t.cancelButton),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
// TODO(nullcube): Translation will not update until we refresh the page.
|
|
||||||
updateLocale(selectedLanguageCode.value.languageTag);
|
updateLocale(selectedLanguageCode.value.languageTag);
|
||||||
Navigator.of(context).pop();
|
await _navigationService.navigateToNavigationView();
|
||||||
},
|
},
|
||||||
child: Text(t.okButton),
|
child: Text(t.okButton),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -141,6 +141,18 @@ class SettingsViewModel extends BaseViewModel {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isLastPatchedAppEnabled() {
|
||||||
|
return _managerAPI.isLastPatchedAppEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void useLastPatchedApp(bool value) {
|
||||||
|
_managerAPI.enableLastPatchedAppStatus(value);
|
||||||
|
if (!value) {
|
||||||
|
_managerAPI.deleteLastPatchedApp();
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
bool isVersionCompatibilityCheckEnabled() {
|
bool isVersionCompatibilityCheckEnabled() {
|
||||||
return _managerAPI.isVersionCompatibilityCheckEnabled();
|
return _managerAPI.isVersionCompatibilityCheckEnabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ class AppInfoView extends StatelessWidget {
|
|||||||
const AppInfoView({
|
const AppInfoView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.app,
|
required this.app,
|
||||||
|
required this.isLastPatchedApp,
|
||||||
});
|
});
|
||||||
final PatchedApplication app;
|
final PatchedApplication app;
|
||||||
|
final bool isLastPatchedApp;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -57,6 +59,14 @@ class AppInfoView extends StatelessWidget {
|
|||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
if (isLastPatchedApp) ...[
|
||||||
|
ListTile(
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
|
subtitle: Text(t.appInfoView.lastPatchedAppDescription),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
],
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
child: CustomCard(
|
child: CustomCard(
|
||||||
@@ -71,20 +81,26 @@ class AppInfoView extends StatelessWidget {
|
|||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(16.0),
|
borderRadius: BorderRadius.circular(16.0),
|
||||||
onTap: () => model.openApp(app),
|
onTap: () => isLastPatchedApp
|
||||||
|
? model.installApp(context, app)
|
||||||
|
: model.openApp(app),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.center,
|
MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Icon(
|
Icon(
|
||||||
Icons.open_in_new_outlined,
|
isLastPatchedApp
|
||||||
|
? Icons.download_outlined
|
||||||
|
: Icons.open_in_new_outlined,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.primary,
|
.primary,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
t.appInfoView.openButton,
|
isLastPatchedApp
|
||||||
|
? t.appInfoView.installButton
|
||||||
|
: t.appInfoView.openButton,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
@@ -108,24 +124,30 @@ class AppInfoView extends StatelessWidget {
|
|||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(16.0),
|
borderRadius: BorderRadius.circular(16.0),
|
||||||
onTap: () => model.showUninstallDialog(
|
onTap: () => isLastPatchedApp
|
||||||
context,
|
? model.exportApp(app)
|
||||||
app,
|
: model.showUninstallDialog(
|
||||||
false,
|
context,
|
||||||
),
|
app,
|
||||||
|
false,
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.center,
|
MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Icon(
|
Icon(
|
||||||
Icons.delete_outline,
|
isLastPatchedApp
|
||||||
|
? Icons.save
|
||||||
|
: Icons.delete_outline,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.primary,
|
.primary,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
t.appInfoView.uninstallButton,
|
isLastPatchedApp
|
||||||
|
? t.appInfoView.exportButton
|
||||||
|
: t.appInfoView.uninstallButton,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
@@ -144,14 +166,57 @@ class AppInfoView extends StatelessWidget {
|
|||||||
endIndent: 12.0,
|
endIndent: 12.0,
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
),
|
),
|
||||||
if (app.isRooted)
|
if (isLastPatchedApp)
|
||||||
VerticalDivider(
|
VerticalDivider(
|
||||||
color: Theme.of(context).canvasColor,
|
color: Theme.of(context).canvasColor,
|
||||||
indent: 12.0,
|
indent: 12.0,
|
||||||
endIndent: 12.0,
|
endIndent: 12.0,
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
),
|
),
|
||||||
if (app.isRooted)
|
if (isLastPatchedApp)
|
||||||
|
Expanded(
|
||||||
|
child: Material(
|
||||||
|
type: MaterialType.transparency,
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(16.0),
|
||||||
|
onTap: () => model.showDeleteDialog(
|
||||||
|
context,
|
||||||
|
app,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
Icons
|
||||||
|
.delete_forever_outlined,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
t.appInfoView.deleteButton,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!isLastPatchedApp && app.isRooted)
|
||||||
|
VerticalDivider(
|
||||||
|
color: Theme.of(context).canvasColor,
|
||||||
|
indent: 12.0,
|
||||||
|
endIndent: 12.0,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
if (!isLastPatchedApp && app.isRooted)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Material(
|
child: Material(
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
@@ -240,6 +305,23 @@ class AppInfoView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
|
if (isLastPatchedApp) ...[
|
||||||
|
ListTile(
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
|
title: Text(
|
||||||
|
t.appInfoView.sizeLabel,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
model.getFileSizeString(app.fileSize),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
],
|
||||||
ListTile(
|
ListTile(
|
||||||
contentPadding:
|
contentPadding:
|
||||||
const EdgeInsets.symmetric(horizontal: 20.0),
|
const EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// ignore_for_file: use_build_context_synchronously
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
import 'dart:math';
|
||||||
import 'package:device_apps/device_apps.dart';
|
import 'package:device_apps/device_apps.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
@@ -20,6 +21,23 @@ class AppInfoViewModel extends BaseViewModel {
|
|||||||
final RootAPI _rootAPI = RootAPI();
|
final RootAPI _rootAPI = RootAPI();
|
||||||
final Toast _toast = locator<Toast>();
|
final Toast _toast = locator<Toast>();
|
||||||
|
|
||||||
|
Future<void> installApp(
|
||||||
|
BuildContext context,
|
||||||
|
PatchedApplication app,
|
||||||
|
) async {
|
||||||
|
app.isRooted = await _managerAPI.installTypeDialog(context);
|
||||||
|
final int statusCode = await _patcherAPI.installPatchedFile(context, app);
|
||||||
|
if (statusCode == 0) {
|
||||||
|
locator<HomeViewModel>().initialize(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> exportApp(
|
||||||
|
PatchedApplication app,
|
||||||
|
) async {
|
||||||
|
_patcherAPI.exportPatchedFile(app);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> uninstallApp(
|
Future<void> uninstallApp(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
PatchedApplication app,
|
PatchedApplication app,
|
||||||
@@ -123,6 +141,34 @@ class AppInfoViewModel extends BaseViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> showDeleteDialog(
|
||||||
|
BuildContext context,
|
||||||
|
PatchedApplication app,
|
||||||
|
) async {
|
||||||
|
return showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text(t.appInfoView.removeAppDialogTitle),
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
content: Text(t.appInfoView.removeAppDialogText),
|
||||||
|
actions: <Widget>[
|
||||||
|
OutlinedButton(
|
||||||
|
child: Text(t.cancelButton),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
FilledButton(
|
||||||
|
child: Text(t.okButton),
|
||||||
|
onPressed: () => {
|
||||||
|
_managerAPI.deleteLastPatchedApp(),
|
||||||
|
Navigator.of(context)..pop()..pop(),
|
||||||
|
locator<HomeViewModel>().initialize(context),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
String getPrettyDate(BuildContext context, DateTime dateTime) {
|
String getPrettyDate(BuildContext context, DateTime dateTime) {
|
||||||
return DateFormat.yMMMMd(Localizations.localeOf(context).languageCode)
|
return DateFormat.yMMMMd(Localizations.localeOf(context).languageCode)
|
||||||
.format(dateTime);
|
.format(dateTime);
|
||||||
@@ -133,6 +179,12 @@ class AppInfoViewModel extends BaseViewModel {
|
|||||||
.format(dateTime);
|
.format(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getFileSizeString(int bytes) {
|
||||||
|
const suffixes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
final i = (log(bytes) / log(1024)).floor();
|
||||||
|
return '${(bytes / pow(1024, i)).toStringAsFixed(2)} ${suffixes[i]}';
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> showAppliedPatchesDialog(
|
Future<void> showAppliedPatchesDialog(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
PatchedApplication app,
|
PatchedApplication app,
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class InstalledAppsCard extends StatelessWidget {
|
|||||||
name: app.name,
|
name: app.name,
|
||||||
patchDate: app.patchDate,
|
patchDate: app.patchDate,
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
locator<HomeViewModel>().navigateToAppInfo(app),
|
locator<HomeViewModel>().navigateToAppInfo(app, false),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
|
|||||||
49
lib/ui/widgets/homeView/last_patched_app_card.dart
Normal file
49
lib/ui/widgets/homeView/last_patched_app_card.dart
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:revanced_manager/app/app.locator.dart';
|
||||||
|
import 'package:revanced_manager/gen/strings.g.dart';
|
||||||
|
import 'package:revanced_manager/models/patched_application.dart';
|
||||||
|
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
|
||||||
|
import 'package:revanced_manager/ui/widgets/shared/application_item.dart';
|
||||||
|
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
||||||
|
|
||||||
|
//ignore: must_be_immutable
|
||||||
|
class LastPatchedAppCard extends StatelessWidget {
|
||||||
|
LastPatchedAppCard({super.key});
|
||||||
|
PatchedApplication? app = locator<HomeViewModel>().lastPatchedApp;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return app == null
|
||||||
|
? CustomCard(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
size: 40,
|
||||||
|
Icons.update_disabled,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
t.homeView.noSavedAppFound,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: ApplicationItem(
|
||||||
|
icon: app!.icon,
|
||||||
|
name: app!.name,
|
||||||
|
patchDate: app!.patchDate,
|
||||||
|
onPressed: () =>
|
||||||
|
locator<HomeViewModel>().navigateToAppInfo(app!, true),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ class UpdateConfirmationSheet extends StatelessWidget {
|
|||||||
|
|
||||||
final bool isPatches;
|
final bool isPatches;
|
||||||
final bool changelog;
|
final bool changelog;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final HomeViewModel model = locator<HomeViewModel>();
|
final HomeViewModel model = locator<HomeViewModel>();
|
||||||
@@ -25,100 +26,99 @@ class UpdateConfirmationSheet extends StatelessWidget {
|
|||||||
builder: (_, scrollController) => SingleChildScrollView(
|
builder: (_, scrollController) => SingleChildScrollView(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: FutureBuilder<Map<String, dynamic>?>(
|
child: Column(
|
||||||
future: !isPatches
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
? model.getLatestManagerRelease()
|
children: [
|
||||||
: model.getLatestPatchesRelease(),
|
if (!changelog)
|
||||||
builder: (_, snapshot) {
|
Padding(
|
||||||
if (!snapshot.hasData) {
|
padding: const EdgeInsets.only(
|
||||||
return const SizedBox(
|
top: 40.0,
|
||||||
height: 300,
|
left: 24.0,
|
||||||
child: Center(
|
right: 24.0,
|
||||||
child: CircularProgressIndicator(),
|
bottom: 20.0,
|
||||||
),
|
),
|
||||||
);
|
child: Row(
|
||||||
}
|
children: [
|
||||||
|
Expanded(
|
||||||
return Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (!changelog)
|
Text(
|
||||||
Padding(
|
isPatches
|
||||||
padding: const EdgeInsets.only(
|
? t.homeView.updatePatchesSheetTitle
|
||||||
top: 40.0,
|
: t.homeView.updateSheetTitle,
|
||||||
left: 24.0,
|
style: const TextStyle(
|
||||||
right: 24.0,
|
fontSize: 24,
|
||||||
bottom: 20.0,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
child: Row(
|
),
|
||||||
children: [
|
const SizedBox(height: 4.0),
|
||||||
Expanded(
|
Row(
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.new_releases_outlined,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
Text(
|
Text(
|
||||||
isPatches
|
isPatches
|
||||||
? t.homeView.updatePatchesSheetTitle
|
? model.latestPatchesVersion ?? 'Unknown'
|
||||||
: t.homeView.updateSheetTitle,
|
: model.latestManagerVersion ?? 'Unknown',
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.w500,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4.0),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.new_releases_outlined,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.secondary,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8.0),
|
|
||||||
Text(
|
|
||||||
snapshot.data!['tag_name'] ?? 'Unknown',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.secondary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
FilledButton(
|
),
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
isPatches
|
|
||||||
? model.updatePatches(context)
|
|
||||||
: model.updateManager(context);
|
|
||||||
},
|
|
||||||
child: Text(t.updateButton),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
FilledButton(
|
||||||
Padding(
|
onPressed: () {
|
||||||
padding: const EdgeInsets.only(
|
Navigator.of(context).pop();
|
||||||
top: 12.0,
|
isPatches
|
||||||
left: 24.0,
|
? model.updatePatches(context)
|
||||||
bottom: 12.0,
|
: model.updateManager(context);
|
||||||
),
|
},
|
||||||
child: Text(
|
child: Text(t.updateButton),
|
||||||
t.homeView.updateChangelogTitle,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: changelog ? 24 : 20,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color:
|
|
||||||
Theme.of(context).colorScheme.onSecondaryContainer,
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
Container(
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 12.0,
|
||||||
|
left: 24.0,
|
||||||
|
bottom: 12.0,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
t.homeView.updateChangelogTitle,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: changelog ? 24 : 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FutureBuilder<String?>(
|
||||||
|
future: !isPatches
|
||||||
|
? model.getManagerChangelogs()
|
||||||
|
: model.getLatestPatchesChangelog(),
|
||||||
|
builder: (_, snapshot) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(top: changelog ? 96 : 24),
|
||||||
|
child: const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 24.0),
|
margin: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
@@ -139,12 +139,12 @@ class UpdateConfirmationSheet extends StatelessWidget {
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
padding: const EdgeInsets.all(20.0),
|
padding: const EdgeInsets.all(20.0),
|
||||||
data: snapshot.data!['body'] ?? '',
|
data: snapshot.data ?? '',
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
],
|
},
|
||||||
);
|
),
|
||||||
},
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class _PatchItemState extends State<PatchItem> {
|
|||||||
if (widget.isUnsupported &&
|
if (widget.isUnsupported &&
|
||||||
widget._managerAPI.isVersionCompatibilityCheckEnabled()) {
|
widget._managerAPI.isVersionCompatibilityCheckEnabled()) {
|
||||||
widget.isSelected = false;
|
widget.isSelected = false;
|
||||||
widget.toast.showBottom('patchItem.unsupportedPatchVersion');
|
widget.toast.showBottom(t.patchItem.unsupportedPatchVersion);
|
||||||
} else if (widget.isChangeEnabled) {
|
} else if (widget.isChangeEnabled) {
|
||||||
if (!widget.isSelected) {
|
if (!widget.isSelected) {
|
||||||
if (widget.hasUnsupportedPatchOption) {
|
if (widget.hasUnsupportedPatchOption) {
|
||||||
@@ -103,7 +103,7 @@ class _PatchItemState extends State<PatchItem> {
|
|||||||
.isVersionCompatibilityCheckEnabled()) {
|
.isVersionCompatibilityCheckEnabled()) {
|
||||||
widget.isSelected = false;
|
widget.isSelected = false;
|
||||||
widget.toast.showBottom(
|
widget.toast.showBottom(
|
||||||
'patchItem.unsupportedPatchVersion',
|
t.patchItem.unsupportedPatchVersion,
|
||||||
);
|
);
|
||||||
} else if (widget.isChangeEnabled) {
|
} else if (widget.isChangeEnabled) {
|
||||||
if (!widget.isSelected) {
|
if (!widget.isSelected) {
|
||||||
@@ -170,7 +170,7 @@ class _PatchItemState extends State<PatchItem> {
|
|||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
_showUnsupportedWarningDialog(),
|
_showUnsupportedWarningDialog(),
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
shape: MaterialStateProperty.all(
|
shape: WidgetStateProperty.all(
|
||||||
RoundedRectangleBorder(
|
RoundedRectangleBorder(
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.circular(8),
|
BorderRadius.circular(8),
|
||||||
@@ -181,12 +181,10 @@ class _PatchItemState extends State<PatchItem> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor:
|
backgroundColor: WidgetStateProperty.all(
|
||||||
MaterialStateProperty.all(
|
|
||||||
Colors.transparent,
|
Colors.transparent,
|
||||||
),
|
),
|
||||||
foregroundColor:
|
foregroundColor: WidgetStateProperty.all(
|
||||||
MaterialStateProperty.all(
|
|
||||||
Theme.of(context).colorScheme.secondary,
|
Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:revanced_manager/app/app.locator.dart';
|
||||||
import 'package:revanced_manager/gen/strings.g.dart';
|
import 'package:revanced_manager/gen/strings.g.dart';
|
||||||
import 'package:revanced_manager/models/patch.dart';
|
import 'package:revanced_manager/models/patch.dart';
|
||||||
|
import 'package:revanced_manager/services/manager_api.dart';
|
||||||
|
import 'package:revanced_manager/ui/views/patch_options/patch_options_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
||||||
|
|
||||||
class BooleanPatchOption extends StatelessWidget {
|
class BooleanPatchOption extends StatelessWidget {
|
||||||
const BooleanPatchOption({
|
const BooleanPatchOption({
|
||||||
super.key,
|
super.key,
|
||||||
required this.patchOption,
|
required this.patchOption,
|
||||||
required this.removeOption,
|
required this.model,
|
||||||
required this.onChanged,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final Option patchOption;
|
final Option patchOption;
|
||||||
final void Function(Option option) removeOption;
|
final PatchOptionsViewModel model;
|
||||||
final void Function(dynamic value, Option option) onChanged;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -30,88 +32,94 @@ class BooleanPatchOption extends StatelessWidget {
|
|||||||
value: value ?? false,
|
value: value ?? false,
|
||||||
onChanged: (bool value) {
|
onChanged: (bool value) {
|
||||||
patchOptionValue.value = value;
|
patchOptionValue.value = value;
|
||||||
onChanged(value, patchOption);
|
model.modifyOptions(value, patchOption);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
patchOption: patchOption,
|
patchOption: patchOption,
|
||||||
removeOption: (Option option) {
|
patchOptionValue: patchOptionValue,
|
||||||
removeOption(option);
|
model: model,
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IntAndStringPatchOption extends StatelessWidget {
|
class IntAndStringPatchOption extends StatefulWidget {
|
||||||
const IntAndStringPatchOption({
|
const IntAndStringPatchOption({
|
||||||
super.key,
|
super.key,
|
||||||
required this.patchOption,
|
required this.patchOption,
|
||||||
required this.removeOption,
|
required this.model,
|
||||||
required this.onChanged,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final Option patchOption;
|
final Option patchOption;
|
||||||
final void Function(Option option) removeOption;
|
final PatchOptionsViewModel model;
|
||||||
final void Function(dynamic value, Option option) onChanged;
|
|
||||||
|
@override
|
||||||
|
State<IntAndStringPatchOption> createState() =>
|
||||||
|
_IntAndStringPatchOptionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _IntAndStringPatchOptionState extends State<IntAndStringPatchOption> {
|
||||||
|
ValueNotifier? patchOptionValue;
|
||||||
|
String getKey() {
|
||||||
|
if (patchOptionValue!.value != null && widget.patchOption.values != null) {
|
||||||
|
final List values = widget.patchOption.values!.entries
|
||||||
|
.where((e) => e.value == patchOptionValue!.value)
|
||||||
|
.toList();
|
||||||
|
if (values.isNotEmpty) {
|
||||||
|
return values.first.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ValueNotifier patchOptionValue = ValueNotifier(patchOption.value);
|
patchOptionValue ??= ValueNotifier(widget.patchOption.value);
|
||||||
String getKey() {
|
|
||||||
if (patchOption.value != null && patchOption.values != null) {
|
|
||||||
final List values = patchOption.values!.entries
|
|
||||||
.where((e) => e.value == patchOption.value)
|
|
||||||
.toList();
|
|
||||||
if (values.isNotEmpty) {
|
|
||||||
return values.first.key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchOption(
|
return PatchOption(
|
||||||
widget: Column(
|
widget: ValueListenableBuilder(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
valueListenable: patchOptionValue!,
|
||||||
children: [
|
builder: (context, value, child) {
|
||||||
TextFieldForPatchOption(
|
return Column(
|
||||||
value: patchOption.value,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
values: patchOption.values,
|
children: [
|
||||||
optionType: patchOption.valueType,
|
TextFieldForPatchOption(
|
||||||
selectedKey: getKey(),
|
value: value,
|
||||||
onChanged: (value) {
|
patchOption: widget.patchOption,
|
||||||
patchOptionValue.value = value;
|
selectedKey: getKey(),
|
||||||
onChanged(value, patchOption);
|
onChanged: (value) {
|
||||||
},
|
patchOptionValue!.value = value;
|
||||||
),
|
widget.model.modifyOptions(value, widget.patchOption);
|
||||||
ValueListenableBuilder(
|
},
|
||||||
valueListenable: patchOptionValue,
|
),
|
||||||
builder: (context, value, child) {
|
if (value == null)
|
||||||
if (patchOption.required && value == null) {
|
Column(
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
t.patchOptionsView.requiredOption,
|
widget.patchOption.required
|
||||||
|
? t.patchOptionsView.requiredOption
|
||||||
|
: t.patchOptionsView.nullValue,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).colorScheme.error,
|
color: widget.patchOption.required
|
||||||
|
? Theme.of(context).colorScheme.error
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer
|
||||||
|
.withOpacity(0.6),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
),
|
||||||
} else {
|
],
|
||||||
return const SizedBox();
|
);
|
||||||
}
|
},
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
patchOption: patchOption,
|
patchOption: widget.patchOption,
|
||||||
removeOption: (Option option) {
|
patchOptionValue: patchOptionValue!,
|
||||||
removeOption(option);
|
model: widget.model,
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,13 +128,11 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
|||||||
const IntStringLongListPatchOption({
|
const IntStringLongListPatchOption({
|
||||||
super.key,
|
super.key,
|
||||||
required this.patchOption,
|
required this.patchOption,
|
||||||
required this.removeOption,
|
required this.model,
|
||||||
required this.onChanged,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final Option patchOption;
|
final Option patchOption;
|
||||||
final void Function(Option option) removeOption;
|
final PatchOptionsViewModel model;
|
||||||
final void Function(dynamic value, Option option) onChanged;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -172,8 +178,7 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
|||||||
final e = values[index];
|
final e = values[index];
|
||||||
return TextFieldForPatchOption(
|
return TextFieldForPatchOption(
|
||||||
value: e.toString(),
|
value: e.toString(),
|
||||||
values: patchOption.values,
|
patchOption: patchOption,
|
||||||
optionType: type,
|
|
||||||
selectedKey: value.length > 1 ? '' : getKey(e),
|
selectedKey: value.length > 1 ? '' : getKey(e),
|
||||||
showDropdown: index == 0,
|
showDropdown: index == 0,
|
||||||
onChanged: (newValue) {
|
onChanged: (newValue) {
|
||||||
@@ -205,13 +210,13 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
patchOptionValue.value = List.from(values);
|
patchOptionValue.value = List.from(values);
|
||||||
onChanged(values, patchOption);
|
model.modifyOptions(values, patchOption);
|
||||||
},
|
},
|
||||||
removeValue: () {
|
removeValue: () {
|
||||||
patchOptionValue.value = List.from(patchOptionValue.value)
|
patchOptionValue.value = List.from(patchOptionValue.value)
|
||||||
..removeAt(index);
|
..removeAt(index);
|
||||||
values.removeAt(index);
|
values.removeAt(index);
|
||||||
onChanged(values, patchOption);
|
model.modifyOptions(values, patchOption);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -231,7 +236,7 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
|||||||
List.from(patchOptionValue.value)..add(0);
|
List.from(patchOptionValue.value)..add(0);
|
||||||
values.add(0);
|
values.add(0);
|
||||||
}
|
}
|
||||||
onChanged(values, patchOption);
|
model.modifyOptions(values, patchOption);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@@ -254,9 +259,8 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
patchOption: patchOption,
|
patchOption: patchOption,
|
||||||
removeOption: (Option option) {
|
patchOptionValue: patchOptionValue,
|
||||||
removeOption(option);
|
model: model,
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,7 +286,8 @@ class UnsupportedPatchOption extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
patchOption: patchOption,
|
patchOption: patchOption,
|
||||||
removeOption: (_) {},
|
patchOptionValue: ValueNotifier(null),
|
||||||
|
model: PatchOptionsViewModel(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,15 +297,18 @@ class PatchOption extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.widget,
|
required this.widget,
|
||||||
required this.patchOption,
|
required this.patchOption,
|
||||||
required this.removeOption,
|
required this.patchOptionValue,
|
||||||
|
required this.model,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Widget widget;
|
final Widget widget;
|
||||||
final Option patchOption;
|
final Option patchOption;
|
||||||
final void Function(Option option) removeOption;
|
final ValueNotifier patchOptionValue;
|
||||||
|
final PatchOptionsViewModel model;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final defaultValue = model.getDefaultValue(patchOption);
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: CustomCard(
|
child: CustomCard(
|
||||||
@@ -337,11 +345,24 @@ class PatchOption extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!patchOption.required)
|
ValueListenableBuilder(
|
||||||
IconButton(
|
valueListenable: patchOptionValue,
|
||||||
onPressed: () => removeOption(patchOption),
|
builder: (context, value, child) {
|
||||||
icon: const Icon(Icons.delete),
|
if (defaultValue != patchOptionValue.value) {
|
||||||
),
|
return IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
patchOptionValue.value = defaultValue;
|
||||||
|
model.modifyOptions(
|
||||||
|
defaultValue,
|
||||||
|
patchOption,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.history),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return const SizedBox();
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
@@ -360,17 +381,15 @@ class TextFieldForPatchOption extends StatefulWidget {
|
|||||||
const TextFieldForPatchOption({
|
const TextFieldForPatchOption({
|
||||||
super.key,
|
super.key,
|
||||||
required this.value,
|
required this.value,
|
||||||
required this.values,
|
required this.patchOption,
|
||||||
this.removeValue,
|
this.removeValue,
|
||||||
required this.onChanged,
|
required this.onChanged,
|
||||||
required this.optionType,
|
|
||||||
required this.selectedKey,
|
required this.selectedKey,
|
||||||
this.showDropdown = true,
|
this.showDropdown = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String? value;
|
final String? value;
|
||||||
final Map<String, dynamic>? values;
|
final Option patchOption;
|
||||||
final String optionType;
|
|
||||||
final String selectedKey;
|
final String selectedKey;
|
||||||
final bool showDropdown;
|
final bool showDropdown;
|
||||||
final void Function()? removeValue;
|
final void Function()? removeValue;
|
||||||
@@ -382,26 +401,26 @@ class TextFieldForPatchOption extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||||
|
final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
||||||
final TextEditingController controller = TextEditingController();
|
final TextEditingController controller = TextEditingController();
|
||||||
String? selectedKey;
|
String? selectedKey;
|
||||||
String? defaultValue;
|
String? defaultValue;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final bool isStringOption = widget.optionType.contains('String');
|
final bool isStringOption = widget.patchOption.valueType.contains('String');
|
||||||
final bool isArrayOption = widget.optionType.contains('Array');
|
final bool isArrayOption = widget.patchOption.valueType.contains('Array');
|
||||||
selectedKey ??= widget.selectedKey;
|
selectedKey = selectedKey == '' ? selectedKey : widget.selectedKey;
|
||||||
controller.text = !isStringOption &&
|
final bool isValueArray = widget.value?.startsWith('[') ?? false;
|
||||||
isArrayOption &&
|
final bool shouldResetValue =
|
||||||
selectedKey == '' &&
|
!isStringOption && isArrayOption && selectedKey == '' && isValueArray;
|
||||||
(widget.value != null && widget.value.toString().startsWith('['))
|
controller.text = shouldResetValue ? '' : widget.value ?? '';
|
||||||
? ''
|
|
||||||
: widget.value ?? '';
|
|
||||||
defaultValue ??= controller.text;
|
defaultValue ??= controller.text;
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (widget.showDropdown && (widget.values?.isNotEmpty ?? false))
|
if (widget.showDropdown &&
|
||||||
|
(widget.patchOption.values?.isNotEmpty ?? false))
|
||||||
DropdownButton<String>(
|
DropdownButton<String>(
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -410,11 +429,12 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
|||||||
dropdownColor: Theme.of(context).colorScheme.secondaryContainer,
|
dropdownColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
value: selectedKey,
|
value: selectedKey,
|
||||||
items: widget.values!.entries
|
items: widget.patchOption.values!.entries
|
||||||
.map(
|
.map(
|
||||||
(e) => DropdownMenuItem(
|
(e) => DropdownMenuItem(
|
||||||
value: e.key,
|
value: e.key,
|
||||||
child: RichText(
|
child: RichText(
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
text: e.key,
|
text: e.key,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -427,7 +447,7 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
|||||||
TextSpan(
|
TextSpan(
|
||||||
text: ' ${e.value}',
|
text: ' ${e.value}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 16,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSecondaryContainer
|
.onSecondaryContainer
|
||||||
@@ -447,9 +467,7 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
|||||||
t.patchOptionsView.customValue,
|
t.patchOptionsView.customValue,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
||||||
.colorScheme
|
|
||||||
.onSecondaryContainer,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -459,9 +477,11 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
|||||||
controller.text = defaultValue!;
|
controller.text = defaultValue!;
|
||||||
widget.onChanged(controller.text);
|
widget.onChanged(controller.text);
|
||||||
} else {
|
} else {
|
||||||
controller.text = widget.values![value].toString();
|
controller.text = widget.patchOption.values![value].toString();
|
||||||
widget.onChanged(
|
widget.onChanged(
|
||||||
isArrayOption ? widget.values![value] : controller.text,
|
isArrayOption
|
||||||
|
? widget.patchOption.values![value]
|
||||||
|
: controller.text,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -472,9 +492,9 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
|||||||
if (selectedKey == '')
|
if (selectedKey == '')
|
||||||
TextFormField(
|
TextFormField(
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
if (widget.optionType.contains('Int'))
|
if (widget.patchOption.valueType.contains('Int'))
|
||||||
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
|
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
|
||||||
if (widget.optionType.contains('Long'))
|
if (widget.patchOption.valueType.contains('Long'))
|
||||||
FilteringTextInputFormatter.allow(RegExp(r'^[0-9]*\.?[0-9]*')),
|
FilteringTextInputFormatter.allow(RegExp(r'^[0-9]*\.?[0-9]*')),
|
||||||
],
|
],
|
||||||
controller: controller,
|
controller: controller,
|
||||||
@@ -487,41 +507,70 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
|||||||
return [
|
return [
|
||||||
if (isArrayOption)
|
if (isArrayOption)
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
value: t.remove,
|
value: 'remove',
|
||||||
child: Text(t.remove),
|
child: Text(t.remove),
|
||||||
),
|
),
|
||||||
if (isStringOption) ...[
|
if (isStringOption) ...[
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
value: t.patchOptionsView.selectFilePath,
|
value: 'file',
|
||||||
child: Text(t.patchOptionsView.selectFilePath),
|
child: Text(t.patchOptionsView.selectFilePath),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
value: t.patchOptionsView.selectFolder,
|
value: 'folder',
|
||||||
child: Text(t.patchOptionsView.selectFolder),
|
child: Text(t.patchOptionsView.selectFolder),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
if (!widget.patchOption.required)
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'null',
|
||||||
|
child: Text(t.patchOptionsView.setToNull),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
onSelected: (String selection) async {
|
onSelected: (String selection) async {
|
||||||
switch (selection) {
|
// manageExternalStorage permission is required for file/folder selection
|
||||||
case 'patchOptionsView.selectFilePath':
|
// otherwise, the app will not complain, but the patches will error out
|
||||||
final String? result = await FlutterFileDialog.pickFile();
|
// the same way as if the user selected an empty file/folder.
|
||||||
if (result != null) {
|
// Android 11 and above requires the manageExternalStorage permission
|
||||||
controller.text = result;
|
final Map<String, dynamic> availableActions = {
|
||||||
widget.onChanged(controller.text);
|
t.patchOptionsView.selectFilePath: () async {
|
||||||
|
if (_managerAPI.isScopedStorageAvailable) {
|
||||||
|
final permission =
|
||||||
|
await Permission.manageExternalStorage.request();
|
||||||
|
if (!permission.isGranted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
final FilePickerResult? result =
|
||||||
case 'patchOptionsView.selectFolder':
|
await FilePicker.platform.pickFiles();
|
||||||
final DirectoryLocation? result =
|
if (result == null) {
|
||||||
await FlutterFileDialog.pickDirectory();
|
return;
|
||||||
if (result != null) {
|
|
||||||
controller.text = result.toString();
|
|
||||||
widget.onChanged(controller.text);
|
|
||||||
}
|
}
|
||||||
break;
|
controller.text = result.files.single.path!;
|
||||||
case 'remove':
|
widget.onChanged(controller.text);
|
||||||
|
},
|
||||||
|
t.patchOptionsView.selectFolder: () async {
|
||||||
|
if (_managerAPI.isScopedStorageAvailable) {
|
||||||
|
final permission =
|
||||||
|
await Permission.manageExternalStorage.request();
|
||||||
|
if (!permission.isGranted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String? result =
|
||||||
|
await FilePicker.platform.getDirectoryPath();
|
||||||
|
if (result == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
controller.text = result;
|
||||||
|
widget.onChanged(controller.text);
|
||||||
|
},
|
||||||
|
t.remove: () {
|
||||||
widget.removeValue!();
|
widget.removeValue!();
|
||||||
break;
|
},
|
||||||
|
};
|
||||||
|
if (availableActions.containsKey(selection)) {
|
||||||
|
await availableActions[selection]!();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:revanced_manager/gen/strings.g.dart';
|
import 'package:revanced_manager/gen/strings.g.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_patches.dart';
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_patches.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_enable_patches_selection.dart';
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_enable_patches_selection.dart';
|
||||||
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_last_patched_app.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_require_suggested_app_version.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_section.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_show_update_dialog.dart';
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_show_update_dialog.dart';
|
||||||
@@ -24,6 +25,7 @@ class SAdvancedSection extends StatelessWidget {
|
|||||||
SRequireSuggestedAppVersion(),
|
SRequireSuggestedAppVersion(),
|
||||||
SVersionCompatibilityCheck(),
|
SVersionCompatibilityCheck(),
|
||||||
SUniversalPatches(),
|
SUniversalPatches(),
|
||||||
|
SLastPatchedApp(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
37
lib/ui/widgets/settingsView/settings_last_patched_app.dart
Normal file
37
lib/ui/widgets/settingsView/settings_last_patched_app.dart
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:revanced_manager/gen/strings.g.dart';
|
||||||
|
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
||||||
|
|
||||||
|
class SLastPatchedApp extends StatefulWidget {
|
||||||
|
const SLastPatchedApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SLastPatchedApp> createState() =>
|
||||||
|
_SLastPatchedAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
final _settingsViewModel = SettingsViewModel();
|
||||||
|
|
||||||
|
class _SLastPatchedAppState
|
||||||
|
extends State<SLastPatchedApp> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SwitchListTile(
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
|
title: Text(
|
||||||
|
t.settingsView.lastPatchedAppLabel,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: Text(t.settingsView.lastPatchedAppHint),
|
||||||
|
value: _settingsViewModel.isLastPatchedAppEnabled(),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_settingsViewModel.useLastPatchedApp(value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ class _ApplicationItemState extends State<ApplicationItem> {
|
|||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(bottom: 16.0),
|
margin: const EdgeInsets.only(bottom: 16.0),
|
||||||
child: CustomCard(
|
child: CustomCard(
|
||||||
|
onTap: widget.onPressed,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ class CustomSliverAppBar extends StatelessWidget {
|
|||||||
onPressed:
|
onPressed:
|
||||||
onBackButtonPressed ?? () => Navigator.of(context).pop(),
|
onBackButtonPressed ?? () => Navigator.of(context).pop(),
|
||||||
),
|
),
|
||||||
backgroundColor: MaterialStateColor.resolveWith(
|
backgroundColor: WidgetStateColor.resolveWith(
|
||||||
(states) => states.contains(MaterialState.scrolledUnder)
|
(states) => states.contains(WidgetState.scrolledUnder)
|
||||||
? Theme.of(context).colorScheme.surface
|
? Theme.of(context).colorScheme.surface
|
||||||
: Theme.of(context).canvasColor,
|
: Theme.of(context).canvasColor,
|
||||||
),
|
),
|
||||||
|
|||||||
763
package-lock.json
generated
763
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,6 @@
|
|||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/exec": "^6.0.3",
|
"@semantic-release/exec": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"semantic-release": "^23.0.7"
|
"semantic-release": "^23.0.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
pubspec.lock
55
pubspec.lock
@@ -306,6 +306,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "7.0.0"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "2ca051989f69d1b2ca012b2cf3ccf78c70d40144f0861ff2c063493f7c8c3d45"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.5"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -323,9 +331,9 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: "560d21c4148b53933313573e7eafca0b0eb9aadf"
|
ref: "900a81501f1f0e4996fe9e2cbf55f1ea8df08b49"
|
||||||
resolved-ref: "560d21c4148b53933313573e7eafca0b0eb9aadf"
|
resolved-ref: "900a81501f1f0e4996fe9e2cbf55f1ea8df08b49"
|
||||||
url: "https://github.com/BenjaminHalko/flutter_background"
|
url: "https://github.com/validcube/flutter_background"
|
||||||
source: git
|
source: git
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
flutter_cache_manager:
|
flutter_cache_manager:
|
||||||
@@ -385,10 +393,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: "9921f9deda326f8a885e202b1e35237eadfc1345239a0f6f0f1ff287e047547f"
|
sha256: "2e8a801b1ded5ea001a4529c97b1f213dcb11c6b20668e081cafb23468593514"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.1"
|
version: "0.7.3"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.20"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -499,10 +515,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: injectable
|
name: injectable
|
||||||
sha256: fb722c86cf8233008e4db41c696a6145721f45dc8aeba91103e3128c3d63c9c6
|
sha256: "3c8355a29d11ff28c0311bed754649761f345ef7a13ff66a714380954af51226"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.0"
|
version: "2.4.2"
|
||||||
injectable_generator:
|
injectable_generator:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@@ -732,10 +748,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_foundation
|
name: path_provider_foundation
|
||||||
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.2"
|
version: "2.4.0"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -989,10 +1005,11 @@ packages:
|
|||||||
skeletons:
|
skeletons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: skeletons
|
path: "."
|
||||||
sha256: "5b2d08ae7f908ee1f7007ca99f8dcebb4bfc1d3cb2143dec8d112a5be5a45c8f"
|
ref: "326fbb4223ac4d8a6301cc2f16b6112ecd308c71"
|
||||||
url: "https://pub.dev"
|
resolved-ref: "326fbb4223ac4d8a6301cc2f16b6112ecd308c71"
|
||||||
source: hosted
|
url: "https://github.com/Ofceab-Studio/skeletons"
|
||||||
|
source: git
|
||||||
version: "0.0.3"
|
version: "0.0.3"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
@@ -1211,10 +1228,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_ios
|
name: url_launcher_ios
|
||||||
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.5"
|
version: "6.3.0"
|
||||||
url_launcher_linux:
|
url_launcher_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1227,10 +1244,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_macos
|
name: url_launcher_macos
|
||||||
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.2.0"
|
||||||
url_launcher_platform_interface:
|
url_launcher_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1360,5 +1377,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.3.0 <4.0.0"
|
dart: ">=3.4.0 <4.0.0"
|
||||||
flutter: ">=3.19.2"
|
flutter: ">=3.22.0"
|
||||||
|
|||||||
18
pubspec.yaml
18
pubspec.yaml
@@ -4,7 +4,7 @@ homepage: https://github.com/ReVanced/revanced-manager
|
|||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 1.21.0-dev.3+101800019
|
version: 1.21.0-dev.7+101800023
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.0 <4.0.0'
|
sdk: '>=3.0.0 <4.0.0'
|
||||||
@@ -23,23 +23,24 @@ dependencies:
|
|||||||
dynamic_color: ^1.7.0
|
dynamic_color: ^1.7.0
|
||||||
dynamic_themes: ^1.1.0
|
dynamic_themes: ^1.1.0
|
||||||
expandable: ^5.0.1
|
expandable: ^5.0.1
|
||||||
|
file_picker: ^8.0.3
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_background:
|
flutter_background:
|
||||||
git: # remove once https://github.com/JulianAssmann/flutter_background/pull/79 is merged
|
git: # remove once https://github.com/JulianAssmann/flutter_background/pull/83 is merged
|
||||||
url: https://github.com/BenjaminHalko/flutter_background
|
url: https://github.com/validcube/flutter_background
|
||||||
ref: 560d21c4148b53933313573e7eafca0b0eb9aadf # Branch: specify-namespace
|
ref: 900a81501f1f0e4996fe9e2cbf55f1ea8df08b49 # Branch: specify-namespace
|
||||||
flutter_cache_manager: ^3.3.2
|
flutter_cache_manager: ^3.3.2
|
||||||
flutter_file_dialog: ^3.0.2
|
flutter_file_dialog: ^3.0.2
|
||||||
flutter_local_notifications: ^17.1.0
|
flutter_local_notifications: ^17.1.0
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_markdown: ^0.7.1
|
flutter_markdown: ^0.7.3
|
||||||
fluttertoast: ^8.2.5
|
fluttertoast: ^8.2.5
|
||||||
font_awesome_flutter: ^10.7.0
|
font_awesome_flutter: ^10.7.0
|
||||||
google_fonts: ^6.2.1
|
google_fonts: ^6.2.1
|
||||||
injectable: ^2.4.0
|
injectable: ^2.4.0
|
||||||
intl: ^0.18.1
|
intl: 0.19.0
|
||||||
json_annotation: ^4.9.0
|
json_annotation: ^4.9.0
|
||||||
language_code: ^0.5.3+2
|
language_code: ^0.5.3+2
|
||||||
logcat:
|
logcat:
|
||||||
@@ -59,7 +60,10 @@ dependencies:
|
|||||||
ref: 1a1616ac91e16cd1f3dd170a81febf27ffce3587 # Branch: master
|
ref: 1a1616ac91e16cd1f3dd170a81febf27ffce3587 # Branch: master
|
||||||
share_plus: ^9.0.0
|
share_plus: ^9.0.0
|
||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
skeletons: ^0.0.3
|
skeletons:
|
||||||
|
git: # remove once https://github.com/badjio/skeletons/pull/11 is merged
|
||||||
|
url: https://github.com/Ofceab-Studio/skeletons
|
||||||
|
ref: 326fbb4223ac4d8a6301cc2f16b6112ecd308c71 # Branch: master
|
||||||
slang: ^3.30.2
|
slang: ^3.30.2
|
||||||
slang_flutter: ^3.30.0
|
slang_flutter: ^3.30.0
|
||||||
stacked: ^3.4.2
|
stacked: ^3.4.2
|
||||||
|
|||||||
Reference in New Issue
Block a user