mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2026-01-11 21:56:17 +00:00
Compare commits
18 Commits
v1.21.0-de
...
v1.21.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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:
|
||||
|
||||
- **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).
|
||||
- **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
|
||||
@@ -99,14 +99,14 @@ body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: ReVanced Manager logs
|
||||
description: Export logs in ReVanced Manager settings.
|
||||
description: Export logs from the ReVanced Manager settings.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Patch logs
|
||||
description: Export logs in "Patcher" screen.
|
||||
description: Export logs from the "Patcher" screen.
|
||||
render: shell
|
||||
validations:
|
||||
required: false
|
||||
@@ -116,11 +116,11 @@ body:
|
||||
label: Acknowledgements
|
||||
description: Your bug report will be closed if you don't follow the checklist below.
|
||||
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
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
- label: All requested information has been provided properly.
|
||||
required: true
|
||||
- label: The bug is only related to ReVanced Manager
|
||||
- label: The bug is only related to ReVanced Manager.
|
||||
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:
|
||||
|
||||
- **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).
|
||||
- **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
|
||||
@@ -79,7 +79,6 @@ body:
|
||||
description: |
|
||||
- Describe your feature in detail
|
||||
- Add images, videos, links, examples, references, etc. if possible
|
||||
- Add the target application name in case you request a new patch
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Motivation
|
||||
@@ -98,9 +97,9 @@ body:
|
||||
label: Acknowledgements
|
||||
description: Your feature request will be closed if you don't follow the checklist below.
|
||||
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
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
- label: The feature request is only related to ReVanced Manager
|
||||
- label: The feature request is only related to ReVanced Manager.
|
||||
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
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: 3.22.x
|
||||
cache: ${{ inputs.flutter-cache }}
|
||||
|
||||
- name: Get dependencies
|
||||
|
||||
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -36,6 +36,7 @@ jobs:
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: 3.22.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
12
.github/workflows/sync_crowdin.yml
vendored
12
.github/workflows/sync_crowdin.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
schedule:
|
||||
- cron: 00 12 * * 1
|
||||
push:
|
||||
branches: dev
|
||||
paths:
|
||||
- assets/i18n/*.json
|
||||
- assets/i18n/*.dart
|
||||
@@ -20,8 +21,11 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Dart
|
||||
uses: dart-lang/setup-dart@v1
|
||||
- name: Setup Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
cache: true
|
||||
flutter-version: 3.22.x
|
||||
|
||||
- name: Sync translations from Crowdin
|
||||
uses: crowdin/github-action@v1
|
||||
@@ -51,7 +55,9 @@ jobs:
|
||||
|
||||
- name: Validation of Translation Strings
|
||||
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
|
||||
run: |
|
||||
|
||||
@@ -23,10 +23,11 @@ if (flutterVersionName == null) {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk flutter.compileSdkVersion
|
||||
compileSdk 34
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
coreLibraryDesugaringEnabled true
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
@@ -113,6 +114,7 @@ flutter {
|
||||
}
|
||||
|
||||
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-library:2.2.1")
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -18,8 +18,8 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "8.1.2" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.9.23" apply false
|
||||
id "com.android.application" version "8.4.1" apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.0.0" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Custom value",
|
||||
"setToNull": "Set to null",
|
||||
"nullValue": "This option value is currently null",
|
||||
"resetOptionsTooltip": "Reset patch options",
|
||||
"viewTitle": "Patch options",
|
||||
"saveOptions": "Save",
|
||||
"addOptions": "Add options",
|
||||
"deselectPatch": "Deselect patch",
|
||||
"unselectPatch": "Unselect patch",
|
||||
"tooltip": "More input options",
|
||||
"selectFilePath": "Select file path",
|
||||
"selectFolder": "Select folder",
|
||||
"selectOption": "Select option",
|
||||
"requiredOption": "This option is required",
|
||||
"requiredOption": "Setting this option is required",
|
||||
"unsupportedOption": "This option is not supported",
|
||||
"requiredOptionNull": "The following options have to be set:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "تخصيص القيمة",
|
||||
"setToNull": "تعيين إلى فارغ",
|
||||
"nullValue": "قيمة هذا الخيار فارغة حاليا",
|
||||
"resetOptionsTooltip": "إعادة تعيين خيارات التعديل",
|
||||
"viewTitle": "خيارات التعديل",
|
||||
"saveOptions": "حفظ",
|
||||
"addOptions": "إضافة خيارات",
|
||||
"deselectPatch": "إلغاء تحديد التعديل",
|
||||
"unselectPatch": "إلغاء تحديد التصحيح",
|
||||
"tooltip": "المزيد من خيارات الإدخال",
|
||||
"selectFilePath": "تحديد مسار الملف",
|
||||
"selectFolder": "تحديد مجلد",
|
||||
"selectOption": "تحديد خيار",
|
||||
"requiredOption": "هذا الخيار مطلوب",
|
||||
"requiredOption": "إعداد هذا الخيار مطلوب",
|
||||
"unsupportedOption": "هذا الخيار غير مدعوم",
|
||||
"requiredOptionNull": "يجب تعيين الخيارات التالية:\n\n${options}"
|
||||
},
|
||||
@@ -143,7 +145,7 @@
|
||||
"installType": "تحديد نوع التثبيت",
|
||||
"installTypeDescription": "تحديد نوع التثبيت للمتابعة.",
|
||||
"installButton": "تثبيت",
|
||||
"installRootType": "تحميل",
|
||||
"installRootType": "Mount",
|
||||
"installNonRootType": "عادي",
|
||||
"warning": "قم بتعطيل التحديثات التلقائية للتطبيق المعدل لتجنب المشكلات غير المتوقعة.",
|
||||
"pressBackAgain": "اضغط رجوع مرة اخرى للإلغاء",
|
||||
@@ -255,14 +257,14 @@
|
||||
"widgetTitle": "معلومات التطبيق",
|
||||
"openButton": "فتح",
|
||||
"uninstallButton": "إلغاء التثبيت",
|
||||
"unmountButton": "إلغاء التحميل",
|
||||
"unmountButton": "Unmount",
|
||||
"rootDialogTitle": "خطأ",
|
||||
"unmountDialogText": "هل أنت متأكد أنك تريد إلغاء تحميل هذا التطبيق؟",
|
||||
"unmountDialogText": "هل أنت متأكد من أنك تريد Unmount لهذا التطبيق؟",
|
||||
"uninstallDialogText": "هل أنت متأكد من أنك تريد إلغاء تثبيت هذا التطبيق؟",
|
||||
"rootDialogText": "تم تثبيت التطبيق بأذونات المستخدم المتميز، لكن ReVanced Manager ليس لديه أذونات حاليًا.\nالرجاء منح أذونات المستخدم المتميز أولاً.",
|
||||
"packageNameLabel": "اسم الحُزْمَة",
|
||||
"installTypeLabel": "نوع التثبيت",
|
||||
"mountTypeLabel": "تحميل",
|
||||
"mountTypeLabel": "Mount",
|
||||
"regularTypeLabel": "عادي",
|
||||
"patchedDateLabel": "تاريخ التعديل",
|
||||
"appliedPatchesLabel": "التعديلات المطبقة",
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Vlastní hodnota",
|
||||
"setToNull": "Nastavit na null",
|
||||
"nullValue": "Tato hodnota volby je v současné době null",
|
||||
"resetOptionsTooltip": "Obnovit nastavení záplat",
|
||||
"viewTitle": "Nastavení záplat",
|
||||
"saveOptions": "Uložit",
|
||||
"addOptions": "Přidat možnosti",
|
||||
"deselectPatch": "Odznačit záplatu",
|
||||
"unselectPatch": "Zrušit výběr patch",
|
||||
"tooltip": "Další možnosti vstupu",
|
||||
"selectFilePath": "Zvolte cestu k souboru",
|
||||
"selectFolder": "Vybrat složku",
|
||||
"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",
|
||||
"requiredOptionNull": "Tyto možnosti musí být nastaveny:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Tilpasset værdi",
|
||||
"setToNull": "Sæt til nul",
|
||||
"nullValue": "Denne valgmulighed værdi er i øjeblikket nul",
|
||||
"resetOptionsTooltip": "Nulstil patch indstillinger",
|
||||
"viewTitle": "Patch indstillinger",
|
||||
"saveOptions": "Gem",
|
||||
"addOptions": "Tilføj indstillinger",
|
||||
"deselectPatch": "Fravælg patch",
|
||||
"unselectPatch": "Fravælg patch",
|
||||
"tooltip": "Flere input-indstillinger",
|
||||
"selectFilePath": "Vælg fil sti",
|
||||
"selectFolder": "Vælg mappe",
|
||||
"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",
|
||||
"requiredOptionNull": "Følgende indstillinger skal indstilles:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Benutzerdefinierter Wert",
|
||||
"setToNull": "Auf Null setzen",
|
||||
"nullValue": "Dieser Optionswert ist derzeit null",
|
||||
"resetOptionsTooltip": "Patch-Optionen zurücksetzen",
|
||||
"viewTitle": "Patch-Optionen",
|
||||
"saveOptions": "Speichern",
|
||||
"addOptions": "Option hinzufügen",
|
||||
"deselectPatch": "Patch abwählen",
|
||||
"unselectPatch": "Patch entfernen",
|
||||
"tooltip": "Weitere Eingabeoptionen",
|
||||
"selectFilePath": "Dateipfad auswählen",
|
||||
"selectFolder": "Ordner auswählen",
|
||||
"selectOption": "Option auswählen",
|
||||
"requiredOption": "Diese Option ist erforderlich.",
|
||||
"requiredOption": "Einstellung dieser Option ist erforderlich",
|
||||
"unsupportedOption": "Dieser Vorgang ist nicht unterstützt.",
|
||||
"requiredOptionNull": "Die folgenden Optionen müssen gesetzt sein:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Προσαρμοσμένη τιμή",
|
||||
"setToNull": "Ορισμός σε null",
|
||||
"nullValue": "Αυτή η επιλογή είναι κενή",
|
||||
"resetOptionsTooltip": "Επαναφορά επιλογών τροποποιήσεων",
|
||||
"viewTitle": "Επιλογές τροποποιήσεων",
|
||||
"saveOptions": "Αποθήκευση",
|
||||
"addOptions": "Προσθήκη επιλογών",
|
||||
"deselectPatch": "Αποεπιλέξτε τροποποιήσεις",
|
||||
"unselectPatch": "Αποεπιλογή patch",
|
||||
"tooltip": "Περισσότερες επιλογές εισόδου",
|
||||
"selectFilePath": "Επιλογή τοποθεσίας αρχείου",
|
||||
"selectFolder": "Επιλογή φακέλου",
|
||||
"selectOption": "Επιλογή ρύθμισης",
|
||||
"requiredOption": "Αυτή η επιλογή απαιτείται",
|
||||
"requiredOption": "Απαιτείται ρύθμιση αυτής της επιλογής",
|
||||
"unsupportedOption": "Αυτή η επιλογή δεν υποστηρίζεται",
|
||||
"requiredOptionNull": "Πρέπει να οριστούν οι παρακάτω επιλογές:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Valor personalizado",
|
||||
"setToNull": "Establecer a nulo",
|
||||
"nullValue": "Este valor de opción es nulo actualmente",
|
||||
"resetOptionsTooltip": "Restablecer a los valores por defecto",
|
||||
"viewTitle": "Configuración\\ndel parche",
|
||||
"saveOptions": "Guardar configuración",
|
||||
"addOptions": "Agregar configuración",
|
||||
"deselectPatch": "Deseleccionar parche",
|
||||
"unselectPatch": "Deseleccionar parche",
|
||||
"tooltip": "Más opciones de entrada",
|
||||
"selectFilePath": "Seleccionar ruta del archivo",
|
||||
"selectFolder": "Seleccionar carpeta",
|
||||
"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",
|
||||
"requiredOptionNull": "Tenés que configurar las siguientes opciones:\\n\\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Valor personalizado",
|
||||
"setToNull": "Establecer a nulo",
|
||||
"nullValue": "Este valor de opción es nulo actualmente",
|
||||
"resetOptionsTooltip": "Restablecer las opciones de parche",
|
||||
"viewTitle": "Opciones de parche",
|
||||
"saveOptions": "Guardar",
|
||||
"addOptions": "Añadir opciones",
|
||||
"deselectPatch": "Deseleccionar parche",
|
||||
"unselectPatch": "Deseleccionar parche",
|
||||
"tooltip": "Más opciones de entrada",
|
||||
"selectFilePath": "Seleccionar ruta del archivo",
|
||||
"selectFolder": "Seleccionar carpeta",
|
||||
"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",
|
||||
"requiredOptionNull": "Hay que establecer las siguientes opciones:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"downloadConsentDialogTitle": "¿Descargar archivos necesarios?",
|
||||
"downloadConsentDialogText": "ReVanced Manager necesita descargar los archivos necesarios para funcionar correctamente.",
|
||||
"downloadConsentDialogText2": "Esto te conectará a ${url}.",
|
||||
"checkUpdateDialogTitle": "¿Buscar actualizaciones?",
|
||||
"checkUpdateDialogTitle": "¿Comprobar actualizaciones?",
|
||||
"checkUpdateDialogText": "¿Quieres que ReVanced Manager compruebe si hay actualizaciones automáticamente?",
|
||||
"notificationTitle": "Actualización descargada",
|
||||
"notificationText": "Toca para instalar la actualización",
|
||||
@@ -91,14 +91,14 @@
|
||||
},
|
||||
"appSelectorView": {
|
||||
"viewTitle": "Seleccionar una aplicación",
|
||||
"searchBarHint": "Buscar app",
|
||||
"searchBarHint": "Buscar aplicación",
|
||||
"storageButton": "Almacenamiento",
|
||||
"selectFromStorageButton": "Seleccionar desde almacenamiento",
|
||||
"errorMessage": "No se puede usar la aplicación seleccionada",
|
||||
"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.",
|
||||
"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": {
|
||||
"viewTitle": "Selecciona parches",
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Valor personalizado",
|
||||
"setToNull": "Establecer a nulo",
|
||||
"nullValue": "Este valor de opción es nulo actualmente",
|
||||
"resetOptionsTooltip": "Restablecer las opciones de parche",
|
||||
"viewTitle": "Opciones de parche",
|
||||
"saveOptions": "Guardar",
|
||||
"addOptions": "Añadir opciones",
|
||||
"deselectPatch": "Deseleccionar parche",
|
||||
"unselectPatch": "Deseleccionar parche",
|
||||
"tooltip": "Más opciones de entrada",
|
||||
"selectFilePath": "Selecciona la ruta del archivo",
|
||||
"selectFolder": "Selecciona la carpeta",
|
||||
"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",
|
||||
"requiredOptionNull": "Hay que configurar las siguientes opciones:\n\n${options}"
|
||||
},
|
||||
@@ -196,7 +198,7 @@
|
||||
"enablePatchesSelectionLabel": "Permitir cambiar la selecció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?",
|
||||
"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",
|
||||
"autoUpdatePatchesHint": "Actualiza los parches a la última versión automáticamente",
|
||||
"showUpdateDialogLabel": "Mostrar diálogo de actualización",
|
||||
@@ -252,7 +254,7 @@
|
||||
"keystoreSelectorErrorMessage": "No se puede utilizar el archivo de repositorio de claves seleccionado"
|
||||
},
|
||||
"appInfoView": {
|
||||
"widgetTitle": "Informacion de la applicacion",
|
||||
"widgetTitle": "Informacion de la aplicación",
|
||||
"openButton": "Abrir",
|
||||
"uninstallButton": "Desinstalar",
|
||||
"unmountButton": "Desmontar",
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Oma arvo",
|
||||
"setToNull": "Aseta tyhjäksi",
|
||||
"nullValue": "Tämä valinta arvo on tällä hetkellä nolla",
|
||||
"resetOptionsTooltip": "Palauta paikkausasetukset",
|
||||
"viewTitle": "Paikkausasetukset",
|
||||
"saveOptions": "Tallenna",
|
||||
"addOptions": "Lisää asetuksia",
|
||||
"deselectPatch": "Poista paikkauksen valinta",
|
||||
"unselectPatch": "Peru korjauksen valinta",
|
||||
"tooltip": "Enemmän syöteasetuksia",
|
||||
"selectFilePath": "Valitse tiedostosijainti",
|
||||
"selectFolder": "Valitse kansio",
|
||||
"selectOption": "Valitse asetus",
|
||||
"requiredOption": "Tämä asetus vaaditaan",
|
||||
"requiredOption": "Tämän asetuksen asettaminen on pakollinen",
|
||||
"unsupportedOption": "Tätä asetusta ei tueta",
|
||||
"requiredOptionNull": "Seuraavat asetukset on määritettävä:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"updatesSubtitle": "Mises à jour",
|
||||
"patchedSubtitle": "Applications patchées",
|
||||
"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...",
|
||||
"noInstallations": "Aucune application patchée installée",
|
||||
"installUpdate": "Continuer à installer la mise à jour ?",
|
||||
@@ -51,7 +51,7 @@
|
||||
"errorDownloadMessage": "Impossible de télécharger la mise à jour",
|
||||
"errorInstallMessage": "Impossible d'installer la mise à jour",
|
||||
"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": {
|
||||
"infoButton": "Info"
|
||||
@@ -82,8 +82,8 @@
|
||||
"patchSelectorCard": {
|
||||
"widgetTitle": "Sélectionner les patchs",
|
||||
"widgetTitleSelected": "Patchs sélectionnés",
|
||||
"widgetSubtitle": "Choisissez d'abord une application",
|
||||
"widgetEmptySubtitle": "Aucun patch n'est sélectionné"
|
||||
"widgetSubtitle": "Sélectionnez d'abord une application",
|
||||
"widgetEmptySubtitle": "Aucun patch sélectionné"
|
||||
},
|
||||
"socialMediaCard": {
|
||||
"widgetTitle": "Réseaux sociaux",
|
||||
@@ -118,24 +118,26 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Valeur personnalisée",
|
||||
"setToNull": "Définir à NULL",
|
||||
"nullValue": "Cette valeur d'option est actuellement nulle",
|
||||
"resetOptionsTooltip": "Réinitialiser les options de patch",
|
||||
"viewTitle": "Options de patch",
|
||||
"saveOptions": "Enregistrer",
|
||||
"addOptions": "Ajouter des options",
|
||||
"deselectPatch": "Désélectionner tous les patchs",
|
||||
"unselectPatch": "Désélectionner le patch",
|
||||
"tooltip": "Plus d'options d'entrée",
|
||||
"selectFilePath": "Sélectionner l'emplacement du fichier",
|
||||
"selectFolder": "Sélectionner le dossier",
|
||||
"selectOption": "Sélectionner une option",
|
||||
"requiredOption": "Cette option est obligatoire",
|
||||
"unsupportedOption": "Cette option n'est pas supportée",
|
||||
"requiredOption": "Définir cette option est nécessaire",
|
||||
"unsupportedOption": "Cette option n'est pas prise en charge",
|
||||
"requiredOptionNull": "Les options suivantes doivent être définies :\n\n${options}"
|
||||
},
|
||||
"patchItem": {
|
||||
"unsupportedDialogText": "Sélectionner ce patch pourrait entrainer des erreurs dans la modification.\n\nVersion de l'application : ${packageVersion}\nVersions supportées :\n${supportedVersions}",
|
||||
"unsupportedPatchVersion": "Le patch n'est pas supporté pour cette version de l'application.",
|
||||
"unsupportedRequiredOption": "Ce patch contient une option requise qui n'est pas supporté 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.",
|
||||
"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 pris en charge pour cette version de l'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 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"
|
||||
},
|
||||
"installerView": {
|
||||
@@ -193,7 +195,7 @@
|
||||
"contributorsHint": "Liste des contributeurs de ReVanced",
|
||||
"logsLabel": "Partager les journaux",
|
||||
"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",
|
||||
"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 ?",
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Valore personalizzato",
|
||||
"setToNull": "Imposta a nullo",
|
||||
"nullValue": "Questo valore di opzione è al momento nullo",
|
||||
"resetOptionsTooltip": "Ripristina opzioni patch",
|
||||
"viewTitle": "Opzioni patch",
|
||||
"saveOptions": "Salva",
|
||||
"addOptions": "Aggiungi opzioni",
|
||||
"deselectPatch": "Deseleziona patch",
|
||||
"unselectPatch": "Deseleziona patch",
|
||||
"tooltip": "Più opzioni di input",
|
||||
"selectFilePath": "Seleziona percorso file",
|
||||
"selectFolder": "Seleziona cartella",
|
||||
"selectOption": "Seleziona opzione",
|
||||
"requiredOption": "Questa opzione è richiesta",
|
||||
"requiredOption": "L'impostazione di questa opzione è obbligatoria",
|
||||
"unsupportedOption": "Questa opzione non è supportata",
|
||||
"requiredOptionNull": "È necessario impostare le seguenti opzioni:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "カスタム値",
|
||||
"setToNull": "null に設定",
|
||||
"nullValue": "このオプション値は現在nullです",
|
||||
"resetOptionsTooltip": "パッチ設定をリセット",
|
||||
"viewTitle": "パッチ設定",
|
||||
"saveOptions": "保存",
|
||||
"addOptions": "オプションを追加",
|
||||
"deselectPatch": "パッチの選択を解除",
|
||||
"unselectPatch": "パッチの選択を解除",
|
||||
"tooltip": "他の入力オプション",
|
||||
"selectFilePath": "ファイルパスを選択",
|
||||
"selectFolder": "フォルダーを選択",
|
||||
"selectOption": "オプションを選択",
|
||||
"requiredOption": "このオプションは必須です",
|
||||
"requiredOption": "このオプションを設定する必要があります",
|
||||
"unsupportedOption": "この設定はサポートされていません",
|
||||
"requiredOptionNull": "以下のオプションを設定する必要があります:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Aangepaste waarde",
|
||||
"setToNull": "Zet op nul",
|
||||
"nullValue": "Deze optiewaarde is momenteel leeg",
|
||||
"resetOptionsTooltip": "Reset patch opties",
|
||||
"viewTitle": "Patch opties",
|
||||
"saveOptions": "Opslaan",
|
||||
"addOptions": "Opties toevoegen",
|
||||
"deselectPatch": "Deselecteer patch",
|
||||
"unselectPatch": "Patch deselecteren",
|
||||
"tooltip": "Meer invoeropties",
|
||||
"selectFilePath": "Bestandspad selecteren",
|
||||
"selectFolder": "Map selecteren",
|
||||
"selectOption": "Selecteer optie",
|
||||
"requiredOption": "Deze optie is vereist",
|
||||
"requiredOption": "Het instellen van deze optie is vereist",
|
||||
"unsupportedOption": "Deze optie wordt niet ondersteund",
|
||||
"requiredOptionNull": "De volgende opties moeten worden ingesteld:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Niestandardowa wartość",
|
||||
"setToNull": "Ustaw na zerowy",
|
||||
"nullValue": "Ta opcja jest obecnie pusta",
|
||||
"resetOptionsTooltip": "Zresetuj opcje od łatek",
|
||||
"viewTitle": "Opcje łatek",
|
||||
"saveOptions": "Zapisz",
|
||||
"addOptions": "Dodaj opcje",
|
||||
"deselectPatch": "Odznacz łatkę",
|
||||
"unselectPatch": "Odznacz łatkę",
|
||||
"tooltip": "Więcej opcji wejściowych",
|
||||
"selectFilePath": "Wybierz ścieżkę pliku",
|
||||
"selectFolder": "Wybierz folder",
|
||||
"selectOption": "Wybierz opcję",
|
||||
"requiredOption": "Ta opcja jest wymagana",
|
||||
"requiredOption": "Ustawienie tej opcji jest wymagane",
|
||||
"unsupportedOption": "Ta opcja nie jest wspierana",
|
||||
"requiredOptionNull": "Należy ustawić następujące opcje:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"refreshSuccess": "Atualizado com sucesso",
|
||||
"widgetTitle": "Painel",
|
||||
"updatesSubtitle": "Atualizações",
|
||||
"patchedSubtitle": "Aplicativos patcheados",
|
||||
"patchedSubtitle": "Aplicativos patcheados ",
|
||||
"changeLaterSubtitle": "Você pode ajustar essa opção nas configurações mais tarde.",
|
||||
"noUpdates": "Nenhuma atualização encontrada",
|
||||
"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}.",
|
||||
"downloadConsentDialogTitle": "Baixar os arquivos necessários?",
|
||||
"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?",
|
||||
"checkUpdateDialogText": "Você quer que o ReVanced Manager procure atualizações automaticamente?",
|
||||
"notificationTitle": "Atualização baixada",
|
||||
@@ -71,9 +71,9 @@
|
||||
"requiredOptionDialogText": "Algumas opções de patch tiveram que ser definidas."
|
||||
},
|
||||
"appSelectorCard": {
|
||||
"widgetTitle": "Selecione um aplicativo",
|
||||
"widgetTitleSelected": "Aplicativo selecionado",
|
||||
"widgetSubtitle": "Nenhum aplicativo selecionado",
|
||||
"widgetTitle": "Selecione um app",
|
||||
"widgetTitleSelected": "App selecionado",
|
||||
"widgetSubtitle": "Nenhum app selecionado",
|
||||
"noAppsLabel": "Nenhum aplicativo foi encontrado",
|
||||
"currentVersion": "Atual",
|
||||
"suggestedVersion": "Sugeridos/sugestões",
|
||||
@@ -96,7 +96,7 @@
|
||||
"selectFromStorageButton": "Selecionar no armazenamento",
|
||||
"errorMessage": "Não foi possível usar o app selecionado",
|
||||
"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",
|
||||
"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": {
|
||||
"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",
|
||||
"saveOptions": "Salvar",
|
||||
"addOptions": "Adicionar opções",
|
||||
"deselectPatch": "Deselecionar patch",
|
||||
"unselectPatch": "Desmarque o patch",
|
||||
"tooltip": "Mais opções de entrada",
|
||||
"selectFilePath": "Selecione o caminho do arquivo",
|
||||
"selectFolder": "Selecione a pasta",
|
||||
"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",
|
||||
"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",
|
||||
"sourcesIntegrationsLabel": "Fonte das integrações",
|
||||
"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",
|
||||
"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?",
|
||||
@@ -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?",
|
||||
"autoUpdatePatchesLabel": "Atualizar patches automaticamente",
|
||||
"autoUpdatePatchesHint": "Atualize automaticamente os patches para a versão mais recente",
|
||||
"showUpdateDialogLabel": "Show update dialog",
|
||||
"showUpdateDialogHint": "Show a dialog when a new update is available",
|
||||
"showUpdateDialogLabel": "Mostrar alerta de atualização",
|
||||
"showUpdateDialogHint": "Mostra um aviso quando uma nova atualização estiver disponível",
|
||||
"universalPatchesLabel": "Mostrar patches universais",
|
||||
"universalPatchesHint": "Mostra todos os aplicativos e patches universais (pode deixar a lista de aplicativos mais lenta)",
|
||||
"versionCompatibilityCheckLabel": "Verificar compatibilidade de versão",
|
||||
"versionCompatibilityCheckHint": "Prevent selecting patches that are not compatible with the selected app version",
|
||||
"requireSuggestedAppVersionLabel": "Requer a versão sugerida do app",
|
||||
"requireSuggestedAppVersionHint": "Evite selecionar um aplicativo 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?",
|
||||
"versionCompatibilityCheckHint": "Impedir a seleção de patches que não são compatíveis com a versão do app selecionado",
|
||||
"requireSuggestedAppVersionLabel": "Exigir versão sugerida do app",
|
||||
"requireSuggestedAppVersionHint": "Evite selecionar um app com uma versão diferente da sugerida",
|
||||
"requireSuggestedAppVersionDialogText": "Selecionar um app que não seja a versão sugerida pode causar problemas inesperados.\n\nVocê quer prosseguir mesmo assim?",
|
||||
"aboutLabel": "Sobre",
|
||||
"snackbarMessage": "Copiado para a área de transferência",
|
||||
"restartAppForChanges": "Reinicie o aplicativo para aplicar as mudanças",
|
||||
@@ -221,16 +223,16 @@
|
||||
"importPatchesLabel": "Importar seleção de patch",
|
||||
"importPatchesHint": "Importar seleção de patch de um arquivo JSON",
|
||||
"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",
|
||||
"resetStoredPatchesDialogTitle": "Redefinir seleção de patch?",
|
||||
"resetStoredPatchesDialogTitle": "Redefinir a seleção de patch?",
|
||||
"resetStoredPatchesDialogText": "A seleção padrão de patches será restaurada.",
|
||||
"resetStoredPatches": "A seleção de patch foi redefinida",
|
||||
"resetStoredOptionsLabel": "Redefinir opções de patch",
|
||||
"resetStoredOptionsHint": "Resetar todas as opções de patch",
|
||||
"resetStoredOptionsDialogTitle": "Reset patch options?",
|
||||
"resetStoredOptionsDialogText": "Resetting patch options will remove all saved options.",
|
||||
"resetStoredOptions": "As opções foram resetadas",
|
||||
"resetStoredOptionsLabel": "Redefinir as opções de patch",
|
||||
"resetStoredOptionsHint": "Redefinir todas as opções de patch",
|
||||
"resetStoredOptionsDialogTitle": "Redefinir as opções de patch?",
|
||||
"resetStoredOptionsDialogText": "Redefinir as opções de patch vai remover todas as opções salvas.",
|
||||
"resetStoredOptions": "As opções foram redefinidas",
|
||||
"deleteLogsLabel": "Limpar registros",
|
||||
"deleteLogsHint": "Delete collected ReVanced Manager logs",
|
||||
"deletedLogs": "Registros apagados",
|
||||
@@ -286,7 +288,7 @@
|
||||
"status_failure_incompatible": "Instalação incompatível",
|
||||
"status_failure_timeout": "Tempo limite de 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_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?",
|
||||
@@ -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_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_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."
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"okButton": "OK",
|
||||
"cancelButton": "Cancelar",
|
||||
"dismissButton": "Dispensar",
|
||||
"dismissButton": "Ignorar",
|
||||
"quitButton": "Sair",
|
||||
"updateButton": "Atualizar",
|
||||
"enabledLabel": "Ativado",
|
||||
@@ -27,11 +27,11 @@
|
||||
"refreshSuccess": "Atualizado com sucesso",
|
||||
"widgetTitle": "Painel de Controlo",
|
||||
"updatesSubtitle": "Atualizações",
|
||||
"patchedSubtitle": "Aplicações Modificadas",
|
||||
"patchedSubtitle": "Apps patcheados",
|
||||
"changeLaterSubtitle": "Podes modificar esta definição mais tarde.",
|
||||
"noUpdates": "Nenhuma atualização disponível",
|
||||
"WIP": "Trabalho em progresso...",
|
||||
"noInstallations": "Nenhuma aplicação modificada instalada",
|
||||
"noInstallations": "Nenhum app patcheado instalado",
|
||||
"installUpdate": "Continuar para instalar a atualização?",
|
||||
"updateSheetTitle": "Atualizar o ReVanced Manager",
|
||||
"updateDialogTitle": "Nova atualização disponível",
|
||||
@@ -51,7 +51,7 @@
|
||||
"errorDownloadMessage": "Não é possível transferir a atualização",
|
||||
"errorInstallMessage": "Não foi possível instalar a atualização",
|
||||
"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": {
|
||||
"infoButton": "Informação"
|
||||
@@ -98,7 +98,7 @@
|
||||
"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.",
|
||||
"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": {
|
||||
"viewTitle": "Selecionar modificações",
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Valor personalizado",
|
||||
"setToNull": "Definir como nulo",
|
||||
"nullValue": "Atualmente, este valor de opção é nulo",
|
||||
"resetOptionsTooltip": "Reiniciar as opções da modificação",
|
||||
"viewTitle": "Opções de modificação",
|
||||
"saveOptions": "Guardar",
|
||||
"addOptions": "Adicionar opções",
|
||||
"deselectPatch": "Desselecionar modificação",
|
||||
"unselectPatch": "Desmarque o patch",
|
||||
"tooltip": "Mais opções de entrada",
|
||||
"selectFilePath": "Selecionar caminho do arquivo",
|
||||
"selectFolder": "Selecionar pasta",
|
||||
"selectOption": "Seleccionar opção",
|
||||
"requiredOption": "Esta opção é obrigatória",
|
||||
"requiredOption": "Definir esta opção é necessário",
|
||||
"unsupportedOption": "Esta opção não é suportada",
|
||||
"requiredOptionNull": "As seguintes opções devem ser definidas:\n\n${options}"
|
||||
},
|
||||
@@ -145,13 +147,13 @@
|
||||
"installButton": "Instalar",
|
||||
"installRootType": "Montar",
|
||||
"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",
|
||||
"openButton": "Abrir",
|
||||
"shareButton": "Partilhar ficheiro",
|
||||
"notificationTitle": "O ReVanced Manager está a fazer as modificações",
|
||||
"notificationText": "Toca para voltar ao instalador",
|
||||
"exportApkButtonTooltip": "Exportar APK modificado",
|
||||
"exportApkButtonTooltip": "Exportar APK patcheado",
|
||||
"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?",
|
||||
"copiedToClipboard": "Registo copiado para a área de transferência",
|
||||
@@ -258,13 +260,13 @@
|
||||
"unmountButton": "Desmontar",
|
||||
"rootDialogTitle": "Erro",
|
||||
"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.",
|
||||
"packageNameLabel": "Nome do pacote",
|
||||
"installTypeLabel": "Tipo de instalação",
|
||||
"mountTypeLabel": "Montar",
|
||||
"regularTypeLabel": "Normal",
|
||||
"patchedDateLabel": "Data da Modificação",
|
||||
"patchedDateLabel": "Data do patch",
|
||||
"appliedPatchesLabel": "Modificações aplicadas",
|
||||
"patchedDateHint": "${date} às ${time}",
|
||||
"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_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_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.",
|
||||
"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."
|
||||
}
|
||||
}
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Valoare personalizată",
|
||||
"setToNull": "Setează ca nul",
|
||||
"nullValue": "Această valoare este în prezent nulă",
|
||||
"resetOptionsTooltip": "Resetează opțiunile patch-ului",
|
||||
"viewTitle": "Opțiuni patch",
|
||||
"saveOptions": "Salvează",
|
||||
"addOptions": "Adaugă opțiuni",
|
||||
"deselectPatch": "Deselectați toate patch-urile",
|
||||
"unselectPatch": "Deselectează patch-ul",
|
||||
"tooltip": "Mai multe opțiuni de intrare",
|
||||
"selectFilePath": "Selectați calea fișierului",
|
||||
"selectFolder": "Selectați dosarul",
|
||||
"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ă",
|
||||
"requiredOptionNull": "Următoarele opțiuni trebuie setate:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,11 +118,13 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Пользовательское значение",
|
||||
"setToNull": "Установить null",
|
||||
"nullValue": "Значение этого параметра в настоящее время является нулевым",
|
||||
"resetOptionsTooltip": "Сброс параметров патчей",
|
||||
"viewTitle": "Параметры патчей",
|
||||
"saveOptions": "Сохранить",
|
||||
"addOptions": "Добавить параметры",
|
||||
"deselectPatch": "Снять выделение с патча",
|
||||
"unselectPatch": "Отменить выбор патча",
|
||||
"tooltip": "Другие параметры ввода",
|
||||
"selectFilePath": "Выберите путь к файлу",
|
||||
"selectFolder": "Выберите папку",
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Anpassat värde",
|
||||
"setToNull": "Sätt till noll",
|
||||
"nullValue": "Detta alternativ värde är för närvarande noll",
|
||||
"resetOptionsTooltip": "Återställ patchalternativ",
|
||||
"viewTitle": "Patchalternativ",
|
||||
"saveOptions": "Spara",
|
||||
"addOptions": "Lägg till alternativ",
|
||||
"deselectPatch": "Avmarkera patch",
|
||||
"unselectPatch": "Avmarkera patch",
|
||||
"tooltip": "Fler inmatningsalternativ",
|
||||
"selectFilePath": "Välj filsökväg",
|
||||
"selectFolder": "Välj mapp",
|
||||
"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",
|
||||
"requiredOptionNull": "Följande alternativ måste anges:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "Власне значення",
|
||||
"setToNull": "Встановити в null",
|
||||
"nullValue": "Значення опції в даний час null",
|
||||
"resetOptionsTooltip": "Скинути параметри патчу",
|
||||
"viewTitle": "Параметри патчу",
|
||||
"saveOptions": "Зберегти",
|
||||
"addOptions": "Додати параметри",
|
||||
"deselectPatch": "Зняти вибір патчу",
|
||||
"unselectPatch": "Скасувати вибір патча",
|
||||
"tooltip": "Більше варіантів вводу",
|
||||
"selectFilePath": "Оберіть шлях до файлу",
|
||||
"selectFolder": "Оберіть теку",
|
||||
"selectOption": "Вибрати параметр",
|
||||
"requiredOption": "Цей параметр є обов’язковим",
|
||||
"requiredOption": "Встановлення цього параметра є обов'язковим",
|
||||
"unsupportedOption": "Цей параметр не підтримується",
|
||||
"requiredOptionNull": "Необхідно встановити наступні параметри:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -118,16 +118,18 @@
|
||||
},
|
||||
"patchOptionsView": {
|
||||
"customValue": "自定义值",
|
||||
"setToNull": "设置为为空",
|
||||
"nullValue": "此选项值当前为空",
|
||||
"resetOptionsTooltip": "重置补丁选项",
|
||||
"viewTitle": "补丁选项",
|
||||
"saveOptions": "保存",
|
||||
"addOptions": "添加选项",
|
||||
"deselectPatch": "取消选择补丁",
|
||||
"unselectPatch": "取消选择补丁",
|
||||
"tooltip": "更多输入选项",
|
||||
"selectFilePath": "选择文件路径",
|
||||
"selectFolder": "选择文件夹",
|
||||
"selectOption": "选择选项",
|
||||
"requiredOption": "必须填写此选项",
|
||||
"requiredOption": "设置此选项是必需的",
|
||||
"unsupportedOption": "不支持此选项",
|
||||
"requiredOptionNull": "必须设置以下选项:\n\n${options}"
|
||||
},
|
||||
|
||||
@@ -6,12 +6,14 @@ import 'package:injectable/injectable.dart';
|
||||
import 'package:revanced_manager/app/app.locator.dart';
|
||||
import 'package:revanced_manager/services/download_manager.dart';
|
||||
import 'package:revanced_manager/services/manager_api.dart';
|
||||
import 'package:synchronized/synchronized.dart';
|
||||
|
||||
@lazySingleton
|
||||
class GithubAPI {
|
||||
late final Dio _dio;
|
||||
late final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
||||
late final DownloadManager _downloadManager = locator<DownloadManager>();
|
||||
final Map<String, Lock> _lockMap = {};
|
||||
|
||||
Future<void> initialize(String repoUrl) async {
|
||||
_dio = _downloadManager.initDio(repoUrl);
|
||||
@@ -21,11 +23,21 @@ class GithubAPI {
|
||||
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(
|
||||
String repoName,
|
||||
) async {
|
||||
try {
|
||||
final response = await _dio.get(
|
||||
final response = await _dioGetSynchronously(
|
||||
'/repos/$repoName/releases/latest',
|
||||
);
|
||||
return response.data;
|
||||
@@ -37,36 +49,27 @@ class GithubAPI {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> getLatestManagerRelease(
|
||||
String repoName,
|
||||
) async {
|
||||
Future<String?> getManagerChangelogs() async {
|
||||
try {
|
||||
final response = await _dio.get(
|
||||
'/repos/$repoName/releases',
|
||||
final response = await _dioGetSynchronously(
|
||||
'/repos/${_managerAPI.defaultManagerRepo}/releases?per_page=50',
|
||||
);
|
||||
final Map<String, dynamic> releases = response.data[0];
|
||||
int updates = 0;
|
||||
final buffer = StringBuffer();
|
||||
final String currentVersion =
|
||||
await _managerAPI.getCurrentManagerVersion();
|
||||
while (response.data[updates]['tag_name'] != currentVersion) {
|
||||
updates++;
|
||||
}
|
||||
for (int i = 1; i < updates; i++) {
|
||||
if (response.data[i]['prerelease']) {
|
||||
for (final release in response.data) {
|
||||
if (release['tag_name'] == currentVersion) {
|
||||
if (buffer.isEmpty) {
|
||||
buffer.writeln(release['body']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (release['prerelease']) {
|
||||
continue;
|
||||
}
|
||||
releases.update(
|
||||
'body',
|
||||
(value) =>
|
||||
value +
|
||||
'\n' +
|
||||
'# ' +
|
||||
response.data[i]['tag_name'] +
|
||||
'\n' +
|
||||
response.data[i]['body'],
|
||||
);
|
||||
buffer.writeln(release['body']);
|
||||
}
|
||||
return releases;
|
||||
return buffer.toString();
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
@@ -87,7 +90,7 @@ class GithubAPI {
|
||||
url,
|
||||
);
|
||||
}
|
||||
final response = await _dio.get(
|
||||
final response = await _dioGetSynchronously(
|
||||
'/repos/$repoName/releases/tags/$version',
|
||||
);
|
||||
final Map<String, dynamic>? release = response.data;
|
||||
|
||||
@@ -31,7 +31,6 @@ class ManagerAPI {
|
||||
final String cliRepo = 'revanced-cli';
|
||||
late SharedPreferences _prefs;
|
||||
List<Patch> patches = [];
|
||||
List<Option> modifiedOptions = [];
|
||||
List<Option> options = [];
|
||||
Patch? selectedPatch;
|
||||
BuildContext? ctx;
|
||||
|
||||
@@ -39,7 +39,8 @@ class HomeViewModel extends BaseViewModel {
|
||||
List<PatchedApplication> patchedInstalledApps = [];
|
||||
String _currentManagerVersion = '';
|
||||
String _currentPatchesVersion = '';
|
||||
String? _latestManagerVersion = '';
|
||||
String? latestManagerVersion;
|
||||
String? latestPatchesVersion;
|
||||
File? downloadedApk;
|
||||
|
||||
Future<void> initialize(BuildContext context) async {
|
||||
@@ -50,7 +51,6 @@ class HomeViewModel extends BaseViewModel {
|
||||
await forceRefresh(context);
|
||||
return;
|
||||
}
|
||||
_latestManagerVersion = await _managerAPI.getLatestManagerVersion();
|
||||
_currentPatchesVersion = await _managerAPI.getCurrentPatchesVersion();
|
||||
if (_managerAPI.showUpdateDialog() && await hasManagerUpdates()) {
|
||||
showUpdateDialog(context, false);
|
||||
@@ -131,21 +131,21 @@ class HomeViewModel extends BaseViewModel {
|
||||
if (!_managerAPI.releaseBuild) {
|
||||
return false;
|
||||
}
|
||||
_latestManagerVersion =
|
||||
latestManagerVersion =
|
||||
await _managerAPI.getLatestManagerVersion() ?? _currentManagerVersion;
|
||||
|
||||
if (_latestManagerVersion != _currentManagerVersion) {
|
||||
if (latestManagerVersion != _currentManagerVersion) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> hasPatchesUpdates() async {
|
||||
final String? latestVersion = await _managerAPI.getLatestPatchesVersion();
|
||||
if (latestVersion != null) {
|
||||
latestPatchesVersion = await _managerAPI.getLatestPatchesVersion();
|
||||
if (latestPatchesVersion != null) {
|
||||
try {
|
||||
final int latestVersionInt =
|
||||
int.parse(latestVersion.replaceAll(RegExp('[^0-9]'), ''));
|
||||
int.parse(latestPatchesVersion!.replaceAll(RegExp('[^0-9]'), ''));
|
||||
final int currentVersionInt =
|
||||
int.parse(_currentPatchesVersion.replaceAll(RegExp('[^0-9]'), ''));
|
||||
return latestVersionInt > currentVersionInt;
|
||||
@@ -475,12 +475,14 @@ class HomeViewModel extends BaseViewModel {
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> getLatestManagerRelease() {
|
||||
return _githubAPI.getLatestManagerRelease(_managerAPI.defaultManagerRepo);
|
||||
Future<String?> getManagerChangelogs() {
|
||||
return _githubAPI.getManagerChangelogs();
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> getLatestPatchesRelease() {
|
||||
return _githubAPI.getLatestRelease(_managerAPI.defaultPatchesRepo);
|
||||
Future<String?> getLatestPatchesChangelog() async {
|
||||
final release =
|
||||
await _githubAPI.getLatestRelease(_managerAPI.defaultPatchesRepo);
|
||||
return release?['body'];
|
||||
}
|
||||
|
||||
Future<String?> getLatestPatchesReleaseTime() {
|
||||
|
||||
@@ -37,79 +37,35 @@ class PatchOptionsView extends StatelessWidget {
|
||||
color: Theme.of(context).textTheme.titleLarge!.color,
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
model.resetOptions();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.history,
|
||||
),
|
||||
tooltip: t.patchOptionsView.resetOptionsTooltip,
|
||||
),
|
||||
],
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
for (final Option option in model.visibleOptions)
|
||||
for (final Option option in model.modifiedOptions)
|
||||
if (option.valueType == 'String' ||
|
||||
option.valueType == 'Int')
|
||||
IntAndStringPatchOption(
|
||||
patchOption: option,
|
||||
removeOption: (option) {
|
||||
model.removeOption(option);
|
||||
},
|
||||
onChanged: (value, option) {
|
||||
model.modifyOptions(value, option);
|
||||
},
|
||||
model: model,
|
||||
)
|
||||
else if (option.valueType == 'Boolean')
|
||||
BooleanPatchOption(
|
||||
patchOption: option,
|
||||
removeOption: (option) {
|
||||
model.removeOption(option);
|
||||
},
|
||||
onChanged: (value, option) {
|
||||
model.modifyOptions(value, option);
|
||||
},
|
||||
model: model,
|
||||
)
|
||||
else if (option.valueType == 'StringArray' ||
|
||||
option.valueType == 'IntArray' ||
|
||||
option.valueType == 'LongArray')
|
||||
IntStringLongListPatchOption(
|
||||
patchOption: option,
|
||||
removeOption: (option) {
|
||||
model.removeOption(option);
|
||||
},
|
||||
onChanged: (value, option) {
|
||||
model.modifyOptions(value, option);
|
||||
},
|
||||
model: model,
|
||||
)
|
||||
else
|
||||
UnsupportedPatchOption(
|
||||
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(
|
||||
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/ui/views/patcher/patcher_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';
|
||||
|
||||
class PatchOptionsViewModel extends BaseViewModel {
|
||||
@@ -14,7 +13,7 @@ class PatchOptionsViewModel extends BaseViewModel {
|
||||
locator<PatcherViewModel>().selectedApp!.packageName;
|
||||
List<Option> options = [];
|
||||
List<Option> savedOptions = [];
|
||||
List<Option> visibleOptions = [];
|
||||
List<Option> modifiedOptions = [];
|
||||
|
||||
Future<void> initialize() async {
|
||||
options = getDefaultOptions();
|
||||
@@ -28,36 +27,18 @@ class PatchOptionsViewModel extends BaseViewModel {
|
||||
savedOptions.add(savedOption);
|
||||
}
|
||||
}
|
||||
if (savedOptions.isNotEmpty) {
|
||||
visibleOptions = [
|
||||
...savedOptions,
|
||||
...options.where(
|
||||
(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();
|
||||
modifiedOptions = [
|
||||
...savedOptions,
|
||||
...options.where(
|
||||
(option) => !savedOptions.any((sOption) => sOption.key == option.key),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
bool saveOptions(BuildContext context) {
|
||||
final List<Option> requiredNullOptions = [];
|
||||
for (final Option option in options) {
|
||||
if (!visibleOptions.any((vOption) => vOption.key == option.key)) {
|
||||
if (modifiedOptions.any((mOption) => mOption.key == option.key)) {
|
||||
_managerAPI.clearPatchOption(
|
||||
selectedApp,
|
||||
_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) {
|
||||
requiredNullOptions.add(option);
|
||||
} else {
|
||||
@@ -98,11 +79,8 @@ class PatchOptionsViewModel extends BaseViewModel {
|
||||
required: option.required,
|
||||
key: option.key,
|
||||
);
|
||||
visibleOptions[visibleOptions
|
||||
.indexWhere((vOption) => vOption.key == option.key)] = modifiedOption;
|
||||
_managerAPI.modifiedOptions
|
||||
.removeWhere((mOption) => mOption.key == option.key);
|
||||
_managerAPI.modifiedOptions.add(modifiedOption);
|
||||
modifiedOptions.removeWhere((mOption) => mOption.key == option.key);
|
||||
modifiedOptions.add(modifiedOption);
|
||||
}
|
||||
|
||||
List<Option> getDefaultOptions() {
|
||||
@@ -122,93 +100,11 @@ class PatchOptionsViewModel extends BaseViewModel {
|
||||
return defaultOptions;
|
||||
}
|
||||
|
||||
void resetOptions() {
|
||||
_managerAPI.modifiedOptions.clear();
|
||||
visibleOptions =
|
||||
getDefaultOptions().where((option) => option.required).toList();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
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(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
dynamic getDefaultValue(Option patchOption) => _managerAPI.options
|
||||
.firstWhere(
|
||||
(option) => option.key == patchOption.key,
|
||||
)
|
||||
.value;
|
||||
}
|
||||
|
||||
Future<void> showRequiredOptionNullDialog(
|
||||
@@ -248,7 +144,7 @@ Future<void> showRequiredOptionNullDialog(
|
||||
PatchesSelectorViewModel().showPatchesChangeDialog(context);
|
||||
}
|
||||
},
|
||||
child: Text(t.patchOptionsView.deselectPatch),
|
||||
child: Text(t.patchOptionsView.unselectPatch),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
|
||||
@@ -61,7 +61,6 @@ class PatchesSelectorViewModel extends BaseViewModel {
|
||||
void navigateToPatchOptions(List<Option> setOptions, Patch patch) {
|
||||
_managerAPI.options = setOptions;
|
||||
_managerAPI.selectedPatch = patch;
|
||||
_managerAPI.modifiedOptions.clear();
|
||||
_navigationService.navigateToPatchOptionsView();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:language_code/language_code.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/services/manager_api.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:shared_preferences/shared_preferences.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
final _settingViewModel = SettingsViewModel();
|
||||
final _navigationService = NavigationService();
|
||||
|
||||
class SUpdateLanguage extends BaseViewModel {
|
||||
final Toast _toast = locator<Toast>();
|
||||
@@ -108,10 +111,9 @@ class SUpdateLanguage extends BaseViewModel {
|
||||
child: Text(t.cancelButton),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// TODO(nullcube): Translation will not update until we refresh the page.
|
||||
onPressed: () async {
|
||||
updateLocale(selectedLanguageCode.value.languageTag);
|
||||
Navigator.of(context).pop();
|
||||
await _navigationService.navigateToNavigationView();
|
||||
},
|
||||
child: Text(t.okButton),
|
||||
),
|
||||
|
||||
@@ -14,6 +14,7 @@ class UpdateConfirmationSheet extends StatelessWidget {
|
||||
|
||||
final bool isPatches;
|
||||
final bool changelog;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final HomeViewModel model = locator<HomeViewModel>();
|
||||
@@ -25,100 +26,99 @@ class UpdateConfirmationSheet extends StatelessWidget {
|
||||
builder: (_, scrollController) => SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
child: SafeArea(
|
||||
child: FutureBuilder<Map<String, dynamic>?>(
|
||||
future: !isPatches
|
||||
? model.getLatestManagerRelease()
|
||||
: model.getLatestPatchesRelease(),
|
||||
builder: (_, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const SizedBox(
|
||||
height: 300,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!changelog)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 40.0,
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
bottom: 20.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!changelog)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 40.0,
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
bottom: 20.0,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
isPatches
|
||||
? t.homeView.updatePatchesSheetTitle
|
||||
: t.homeView.updateSheetTitle,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4.0),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.new_releases_outlined,
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
const SizedBox(width: 8.0),
|
||||
Text(
|
||||
isPatches
|
||||
? t.homeView.updatePatchesSheetTitle
|
||||
: t.homeView.updateSheetTitle,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
? model.latestPatchesVersion ?? 'Unknown'
|
||||
: model.latestManagerVersion ?? 'Unknown',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
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),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
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,
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
isPatches
|
||||
? model.updatePatches(context)
|
||||
: model.updateManager(context);
|
||||
},
|
||||
child: Text(t.updateButton),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
@@ -139,12 +139,12 @@ class UpdateConfirmationSheet extends StatelessWidget {
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
data: snapshot.data!['body'] ?? '',
|
||||
data: snapshot.data ?? '',
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -3,19 +3,18 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
||||
import 'package:revanced_manager/gen/strings.g.dart';
|
||||
import 'package:revanced_manager/models/patch.dart';
|
||||
import 'package:revanced_manager/ui/views/patch_options/patch_options_viewmodel.dart';
|
||||
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
||||
|
||||
class BooleanPatchOption extends StatelessWidget {
|
||||
const BooleanPatchOption({
|
||||
super.key,
|
||||
required this.patchOption,
|
||||
required this.removeOption,
|
||||
required this.onChanged,
|
||||
required this.model,
|
||||
});
|
||||
|
||||
final Option patchOption;
|
||||
final void Function(Option option) removeOption;
|
||||
final void Function(dynamic value, Option option) onChanged;
|
||||
final PatchOptionsViewModel model;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -30,88 +29,94 @@ class BooleanPatchOption extends StatelessWidget {
|
||||
value: value ?? false,
|
||||
onChanged: (bool value) {
|
||||
patchOptionValue.value = value;
|
||||
onChanged(value, patchOption);
|
||||
model.modifyOptions(value, patchOption);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
patchOption: patchOption,
|
||||
removeOption: (Option option) {
|
||||
removeOption(option);
|
||||
},
|
||||
patchOptionValue: patchOptionValue,
|
||||
model: model,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class IntAndStringPatchOption extends StatelessWidget {
|
||||
class IntAndStringPatchOption extends StatefulWidget {
|
||||
const IntAndStringPatchOption({
|
||||
super.key,
|
||||
required this.patchOption,
|
||||
required this.removeOption,
|
||||
required this.onChanged,
|
||||
required this.model,
|
||||
});
|
||||
|
||||
final Option patchOption;
|
||||
final void Function(Option option) removeOption;
|
||||
final void Function(dynamic value, Option option) onChanged;
|
||||
final PatchOptionsViewModel model;
|
||||
|
||||
@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
|
||||
Widget build(BuildContext context) {
|
||||
final ValueNotifier patchOptionValue = ValueNotifier(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 '';
|
||||
}
|
||||
|
||||
patchOptionValue ??= ValueNotifier(widget.patchOption.value);
|
||||
return PatchOption(
|
||||
widget: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextFieldForPatchOption(
|
||||
value: patchOption.value,
|
||||
values: patchOption.values,
|
||||
optionType: patchOption.valueType,
|
||||
selectedKey: getKey(),
|
||||
onChanged: (value) {
|
||||
patchOptionValue.value = value;
|
||||
onChanged(value, patchOption);
|
||||
},
|
||||
),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: patchOptionValue,
|
||||
builder: (context, value, child) {
|
||||
if (patchOption.required && value == null) {
|
||||
return Column(
|
||||
widget: ValueListenableBuilder(
|
||||
valueListenable: patchOptionValue!,
|
||||
builder: (context, value, child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextFieldForPatchOption(
|
||||
value: value,
|
||||
patchOption: widget.patchOption,
|
||||
selectedKey: getKey(),
|
||||
onChanged: (value) {
|
||||
patchOptionValue!.value = value;
|
||||
widget.model.modifyOptions(value, widget.patchOption);
|
||||
},
|
||||
),
|
||||
if (value == null)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
t.patchOptionsView.requiredOption,
|
||||
widget.patchOption.required
|
||||
? t.patchOptionsView.requiredOption
|
||||
: t.patchOptionsView.nullValue,
|
||||
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,
|
||||
removeOption: (Option option) {
|
||||
removeOption(option);
|
||||
},
|
||||
patchOption: widget.patchOption,
|
||||
patchOptionValue: patchOptionValue!,
|
||||
model: widget.model,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -120,13 +125,11 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
||||
const IntStringLongListPatchOption({
|
||||
super.key,
|
||||
required this.patchOption,
|
||||
required this.removeOption,
|
||||
required this.onChanged,
|
||||
required this.model,
|
||||
});
|
||||
|
||||
final Option patchOption;
|
||||
final void Function(Option option) removeOption;
|
||||
final void Function(dynamic value, Option option) onChanged;
|
||||
final PatchOptionsViewModel model;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -172,8 +175,7 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
||||
final e = values[index];
|
||||
return TextFieldForPatchOption(
|
||||
value: e.toString(),
|
||||
values: patchOption.values,
|
||||
optionType: type,
|
||||
patchOption: patchOption,
|
||||
selectedKey: value.length > 1 ? '' : getKey(e),
|
||||
showDropdown: index == 0,
|
||||
onChanged: (newValue) {
|
||||
@@ -205,13 +207,13 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
patchOptionValue.value = List.from(values);
|
||||
onChanged(values, patchOption);
|
||||
model.modifyOptions(values, patchOption);
|
||||
},
|
||||
removeValue: () {
|
||||
patchOptionValue.value = List.from(patchOptionValue.value)
|
||||
..removeAt(index);
|
||||
values.removeAt(index);
|
||||
onChanged(values, patchOption);
|
||||
model.modifyOptions(values, patchOption);
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -231,7 +233,7 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
||||
List.from(patchOptionValue.value)..add(0);
|
||||
values.add(0);
|
||||
}
|
||||
onChanged(values, patchOption);
|
||||
model.modifyOptions(values, patchOption);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -254,9 +256,8 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
patchOption: patchOption,
|
||||
removeOption: (Option option) {
|
||||
removeOption(option);
|
||||
},
|
||||
patchOptionValue: patchOptionValue,
|
||||
model: model,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -282,7 +283,8 @@ class UnsupportedPatchOption extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
patchOption: patchOption,
|
||||
removeOption: (_) {},
|
||||
patchOptionValue: ValueNotifier(null),
|
||||
model: PatchOptionsViewModel(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -292,15 +294,18 @@ class PatchOption extends StatelessWidget {
|
||||
super.key,
|
||||
required this.widget,
|
||||
required this.patchOption,
|
||||
required this.removeOption,
|
||||
required this.patchOptionValue,
|
||||
required this.model,
|
||||
});
|
||||
|
||||
final Widget widget;
|
||||
final Option patchOption;
|
||||
final void Function(Option option) removeOption;
|
||||
final ValueNotifier patchOptionValue;
|
||||
final PatchOptionsViewModel model;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final defaultValue = model.getDefaultValue(patchOption);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: CustomCard(
|
||||
@@ -337,11 +342,24 @@ class PatchOption extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
if (!patchOption.required)
|
||||
IconButton(
|
||||
onPressed: () => removeOption(patchOption),
|
||||
icon: const Icon(Icons.delete),
|
||||
),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: patchOptionValue,
|
||||
builder: (context, value, child) {
|
||||
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),
|
||||
@@ -360,17 +378,15 @@ class TextFieldForPatchOption extends StatefulWidget {
|
||||
const TextFieldForPatchOption({
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.values,
|
||||
required this.patchOption,
|
||||
this.removeValue,
|
||||
required this.onChanged,
|
||||
required this.optionType,
|
||||
required this.selectedKey,
|
||||
this.showDropdown = true,
|
||||
});
|
||||
|
||||
final String? value;
|
||||
final Map<String, dynamic>? values;
|
||||
final String optionType;
|
||||
final Option patchOption;
|
||||
final String selectedKey;
|
||||
final bool showDropdown;
|
||||
final void Function()? removeValue;
|
||||
@@ -388,20 +404,19 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool isStringOption = widget.optionType.contains('String');
|
||||
final bool isArrayOption = widget.optionType.contains('Array');
|
||||
selectedKey ??= widget.selectedKey;
|
||||
controller.text = !isStringOption &&
|
||||
isArrayOption &&
|
||||
selectedKey == '' &&
|
||||
(widget.value != null && widget.value.toString().startsWith('['))
|
||||
? ''
|
||||
: widget.value ?? '';
|
||||
final bool isStringOption = widget.patchOption.valueType.contains('String');
|
||||
final bool isArrayOption = widget.patchOption.valueType.contains('Array');
|
||||
selectedKey = selectedKey == '' ? selectedKey : widget.selectedKey;
|
||||
final bool isValueArray = widget.value?.startsWith('[') ?? false;
|
||||
final bool shouldResetValue =
|
||||
!isStringOption && isArrayOption && selectedKey == '' && isValueArray;
|
||||
controller.text = shouldResetValue ? '' : widget.value ?? '';
|
||||
defaultValue ??= controller.text;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (widget.showDropdown && (widget.values?.isNotEmpty ?? false))
|
||||
if (widget.showDropdown &&
|
||||
(widget.patchOption.values?.isNotEmpty ?? false))
|
||||
DropdownButton<String>(
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
@@ -410,11 +425,12 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
dropdownColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||
isExpanded: true,
|
||||
value: selectedKey,
|
||||
items: widget.values!.entries
|
||||
items: widget.patchOption.values!.entries
|
||||
.map(
|
||||
(e) => DropdownMenuItem(
|
||||
value: e.key,
|
||||
child: RichText(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
text: TextSpan(
|
||||
text: e.key,
|
||||
style: TextStyle(
|
||||
@@ -427,7 +443,7 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
TextSpan(
|
||||
text: ' ${e.value}',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontSize: 16,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer
|
||||
@@ -447,9 +463,7 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
t.patchOptionsView.customValue,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -459,9 +473,11 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
controller.text = defaultValue!;
|
||||
widget.onChanged(controller.text);
|
||||
} else {
|
||||
controller.text = widget.values![value].toString();
|
||||
controller.text = widget.patchOption.values![value].toString();
|
||||
widget.onChanged(
|
||||
isArrayOption ? widget.values![value] : controller.text,
|
||||
isArrayOption
|
||||
? widget.patchOption.values![value]
|
||||
: controller.text,
|
||||
);
|
||||
}
|
||||
setState(() {
|
||||
@@ -472,9 +488,9 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
if (selectedKey == '')
|
||||
TextFormField(
|
||||
inputFormatters: [
|
||||
if (widget.optionType.contains('Int'))
|
||||
if (widget.patchOption.valueType.contains('Int'))
|
||||
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]*')),
|
||||
],
|
||||
controller: controller,
|
||||
@@ -487,31 +503,36 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
return [
|
||||
if (isArrayOption)
|
||||
PopupMenuItem(
|
||||
value: t.remove,
|
||||
value: 'remove',
|
||||
child: Text(t.remove),
|
||||
),
|
||||
if (isStringOption) ...[
|
||||
PopupMenuItem(
|
||||
value: t.patchOptionsView.selectFilePath,
|
||||
value: 'file',
|
||||
child: Text(t.patchOptionsView.selectFilePath),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: t.patchOptionsView.selectFolder,
|
||||
value: 'folder',
|
||||
child: Text(t.patchOptionsView.selectFolder),
|
||||
),
|
||||
],
|
||||
if (!widget.patchOption.required)
|
||||
PopupMenuItem(
|
||||
value: 'null',
|
||||
child: Text(t.patchOptionsView.setToNull),
|
||||
),
|
||||
];
|
||||
},
|
||||
onSelected: (String selection) async {
|
||||
switch (selection) {
|
||||
case 'patchOptionsView.selectFilePath':
|
||||
case 'file':
|
||||
final String? result = await FlutterFileDialog.pickFile();
|
||||
if (result != null) {
|
||||
controller.text = result;
|
||||
widget.onChanged(controller.text);
|
||||
}
|
||||
break;
|
||||
case 'patchOptionsView.selectFolder':
|
||||
case 'folder':
|
||||
final DirectoryLocation? result =
|
||||
await FlutterFileDialog.pickDirectory();
|
||||
if (result != null) {
|
||||
@@ -522,6 +543,10 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
case 'remove':
|
||||
widget.removeValue!();
|
||||
break;
|
||||
case 'null':
|
||||
controller.text = '';
|
||||
widget.onChanged(null);
|
||||
break;
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
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/exec": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"semantic-release": "^23.0.7"
|
||||
"semantic-release": "^23.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
55
pubspec.lock
55
pubspec.lock
@@ -323,9 +323,9 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "560d21c4148b53933313573e7eafca0b0eb9aadf"
|
||||
resolved-ref: "560d21c4148b53933313573e7eafca0b0eb9aadf"
|
||||
url: "https://github.com/BenjaminHalko/flutter_background"
|
||||
ref: "900a81501f1f0e4996fe9e2cbf55f1ea8df08b49"
|
||||
resolved-ref: "900a81501f1f0e4996fe9e2cbf55f1ea8df08b49"
|
||||
url: "https://github.com/validcube/flutter_background"
|
||||
source: git
|
||||
version: "1.2.0"
|
||||
flutter_cache_manager:
|
||||
@@ -499,10 +499,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: injectable
|
||||
sha256: fb722c86cf8233008e4db41c696a6145721f45dc8aeba91103e3128c3d63c9c6
|
||||
sha256: "3c8355a29d11ff28c0311bed754649761f345ef7a13ff66a714380954af51226"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.2"
|
||||
injectable_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -571,18 +571,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.4"
|
||||
version: "10.0.5"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.0.5"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -644,18 +644,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.0"
|
||||
version: "0.11.1"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||
sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.0"
|
||||
version: "1.14.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -732,10 +732,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
||||
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -989,10 +989,11 @@ packages:
|
||||
skeletons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: skeletons
|
||||
sha256: "5b2d08ae7f908ee1f7007ca99f8dcebb4bfc1d3cb2143dec8d112a5be5a45c8f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
path: "."
|
||||
ref: "326fbb4223ac4d8a6301cc2f16b6112ecd308c71"
|
||||
resolved-ref: "326fbb4223ac4d8a6301cc2f16b6112ecd308c71"
|
||||
url: "https://github.com/Ofceab-Studio/skeletons"
|
||||
source: git
|
||||
version: "0.0.3"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
@@ -1147,10 +1148,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||
sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
version: "0.7.1"
|
||||
timeago:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1211,10 +1212,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.5"
|
||||
version: "6.3.0"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1227,10 +1228,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
||||
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.2.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1275,10 +1276,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
sha256: "7475cb4dd713d57b6f7464c0e13f06da0d535d8b2067e188962a59bac2cf280b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.1"
|
||||
version: "14.2.2"
|
||||
wakelock_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
15
pubspec.yaml
15
pubspec.yaml
@@ -4,7 +4,7 @@ homepage: https://github.com/ReVanced/revanced-manager
|
||||
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.21.0-dev.3+101800019
|
||||
version: 1.21.0-dev.4+101800020
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
@@ -26,9 +26,9 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_background:
|
||||
git: # remove once https://github.com/JulianAssmann/flutter_background/pull/79 is merged
|
||||
url: https://github.com/BenjaminHalko/flutter_background
|
||||
ref: 560d21c4148b53933313573e7eafca0b0eb9aadf # Branch: specify-namespace
|
||||
git: # remove once https://github.com/JulianAssmann/flutter_background/pull/83 is merged
|
||||
url: https://github.com/validcube/flutter_background
|
||||
ref: 900a81501f1f0e4996fe9e2cbf55f1ea8df08b49 # Branch: specify-namespace
|
||||
flutter_cache_manager: ^3.3.2
|
||||
flutter_file_dialog: ^3.0.2
|
||||
flutter_local_notifications: ^17.1.0
|
||||
@@ -39,7 +39,7 @@ dependencies:
|
||||
font_awesome_flutter: ^10.7.0
|
||||
google_fonts: ^6.2.1
|
||||
injectable: ^2.4.0
|
||||
intl: ^0.18.1
|
||||
intl: 0.19.0
|
||||
json_annotation: ^4.9.0
|
||||
language_code: ^0.5.3+2
|
||||
logcat:
|
||||
@@ -59,7 +59,10 @@ dependencies:
|
||||
ref: 1a1616ac91e16cd1f3dd170a81febf27ffce3587 # Branch: master
|
||||
share_plus: ^9.0.0
|
||||
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_flutter: ^3.30.0
|
||||
stacked: ^3.4.2
|
||||
|
||||
Reference in New Issue
Block a user