Compare commits

..

20 Commits

Author SHA1 Message Date
semantic-release-bot
9552b2ebc5 chore(release): 1.23.0-dev.7 [skip ci]
# [1.23.0-dev.7](https://github.com/ReVanced/revanced-manager/compare/v1.23.0-dev.6...v1.23.0-dev.7) (2024-11-10)

### Features

* Use ReVanced API v4 ([7b7d91d](7b7d91d661))

### Performance Improvements

* Don't recalculate universal patches or compatible packages if not necessary ([7e3afe0](7e3afe0cb2))
2024-11-10 04:04:12 +00:00
oSumAtrIX
7e3afe0cb2 perf: Don't recalculate universal patches or compatible packages if not necessary 2024-11-10 04:53:59 +01:00
oSumAtrIX
7b7d91d661 feat: Use ReVanced API v4 2024-11-10 04:53:59 +01:00
oSumAtrIX
44b8d4ceee build: Configure output file name 2024-11-08 19:43:45 +01:00
semantic-release-bot
aaa97ebb71 chore(release): 1.23.0-dev.6 [skip ci]
# [1.23.0-dev.6](https://github.com/ReVanced/revanced-manager/compare/v1.23.0-dev.5...v1.23.0-dev.6) (2024-11-08)
2024-11-08 17:49:03 +00:00
oSumAtrIX
d99e5af384 build: Fix build 2024-11-08 18:39:02 +01:00
oSumAtrIX
c47c7c0a88 build(Needs bump): Bump dependencies 2024-11-05 20:13:08 +01:00
semantic-release-bot
3e32c0fd90 chore(release): 1.23.0-dev.5 [skip ci]
# [1.23.0-dev.5](https://github.com/ReVanced/revanced-manager/compare/v1.23.0-dev.4...v1.23.0-dev.5) (2024-11-05)

### Features

* Import and export manager settings ([#2268](https://github.com/ReVanced/revanced-manager/issues/2268)) ([a45d959](a45d9598cc))
2024-11-05 18:52:52 +00:00
aAbed
a45d9598cc feat: Import and export manager settings (#2268) 2024-11-05 19:43:35 +01:00
semantic-release-bot
8c8df698d4 chore(release): 1.23.0-dev.4 [skip ci]
# [1.23.0-dev.4](https://github.com/ReVanced/revanced-manager/compare/v1.23.0-dev.3...v1.23.0-dev.4) (2024-10-26)
2024-10-26 15:50:06 +00:00
oSumAtrIX
8d0d782ab5 build(Needs bump): Bump ReVanced Patcher (#2242)
Co-authored-by: aAbed <aabedhkhan@gmail.com>
2024-10-26 17:41:49 +02:00
semantic-release-bot
4db4789a06 chore(release): 1.23.0-dev.3 [skip ci]
# [1.23.0-dev.3](https://github.com/ReVanced/revanced-manager/compare/v1.23.0-dev.2...v1.23.0-dev.3) (2024-10-22)

### Bug Fixes

* Restore apk renaming during compile ([abdd9dc](abdd9dc430))
2024-10-22 16:16:20 +00:00
validcube
abdd9dc430 fix: Restore apk renaming during compile
Signed-off-by: validcube <pun.butrach@gmail.com>
2024-10-22 23:01:51 +07:00
semantic-release-bot
5193042e6b chore(release): 1.23.0-dev.2 [skip ci]
# [1.23.0-dev.2](https://github.com/ReVanced/revanced-manager/compare/v1.23.0-dev.1...v1.23.0-dev.2) (2024-10-21)

### Features

* Show changelogs from the latest to the last used patches version ([#2219](https://github.com/ReVanced/revanced-manager/issues/2219)) ([daba737](daba737ecb))
2024-10-21 10:27:00 +00:00
aAbed
daba737ecb feat: Show changelogs from the latest to the last used patches version (#2219) 2024-10-21 17:17:23 +07:00
ReVanced Bot
bd96701103 chore: Sync translations (#2233) 2024-10-21 17:16:15 +07:00
Pun Butrach
69c20b74cf chore: Restore format consistency 2024-10-21 04:27:53 +07:00
Pun Butrach
7297436ab4 ci: Update config 2024-10-21 03:18:21 +07:00
dependabot[bot]
a329626715 build(deps-dev): bump semantic-release from 23.1.1 to 24.1.3 (#2265)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-20 03:47:39 +07:00
Robert
50a20d0535 ci: Use semantic-release-pub for updating build number (#2263) 2024-10-19 05:34:26 +02:00
72 changed files with 1110 additions and 564 deletions

View File

@@ -17,15 +17,10 @@
"@semantic-release/changelog", "@semantic-release/changelog",
"@semantic-release/release-notes-generator", "@semantic-release/release-notes-generator",
[ [
"@droidsolutions-oss/semantic-release-update-file", "semantic-release-pub",
{ {
"files": [ "publishPub": false,
{ "updateBuildNumber": true
"path": ["pubspec.yaml"],
"type": "flutter",
"branches": ["main", "dev"]
}
]
} }
], ],
[ [
@@ -49,6 +44,8 @@
{ {
"path": "build/app/outputs/apk/release/revanced-manager*.apk" "path": "build/app/outputs/apk/release/revanced-manager*.apk"
}, },
],
"commits": [
"message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" "message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
], ],
"successComment": false "successComment": false

View File

@@ -7,7 +7,7 @@ plugins {
android { android {
namespace = "app.revanced.manager.flutter" namespace = "app.revanced.manager.flutter"
compileSdk = 34 compileSdk = 35
ndkVersion = "27.0.12077973" ndkVersion = "27.0.12077973"
compileOptions { compileOptions {
@@ -24,9 +24,19 @@ android {
defaultConfig { defaultConfig {
applicationId = "app.revanced.manager.flutter" applicationId = "app.revanced.manager.flutter"
minSdk = 26 minSdk = 26
targetSdk = 34 targetSdk = 35
versionCode = flutter.versionCode versionCode = flutter.versionCode
versionName = flutter.versionName versionName = flutter.versionName
resValue("string", "app_name", "ReVanced Manager")
}
applicationVariants.all {
outputs.all {
this as com.android.build.gradle.internal.api.ApkVariantOutputImpl
outputFileName = "revanced-manager-$versionName.apk"
}
} }
buildTypes { buildTypes {
@@ -51,19 +61,21 @@ android {
keyAlias = System.getenv("KEYSTORE_ENTRY_ALIAS") keyAlias = System.getenv("KEYSTORE_ENTRY_ALIAS")
keyPassword = System.getenv("KEYSTORE_ENTRY_PASSWORD") keyPassword = System.getenv("KEYSTORE_ENTRY_PASSWORD")
} }
resValue("string", "app_name", "ReVanced Manager")
} else { } else {
resValue("string", "app_name", "ReVanced Manager (Debug)")
applicationIdSuffix = ".debug" applicationIdSuffix = ".debug"
signingConfig = signingConfigs["debug"] signingConfig = signingConfigs["debug"]
}
resValue("string", "app_name", "ReVanced Manager") resValue("string", "app_name", "ReVanced Manager (Debug signed)")
}
} }
debug { debug {
resValue("string", "app_name", "ReVanced Manager (Debug)")
applicationIdSuffix = ".debug" applicationIdSuffix = ".debug"
resValue("string", "app_name", "ReVanced Manager (Debug)")
} }
} }
@@ -79,6 +91,7 @@ android {
} }
} }
flutter { flutter {
source = "../.." source = "../.."
} }

View File

@@ -3,7 +3,6 @@ package app.revanced.manager.flutter
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.util.Base64 import android.util.Base64
@@ -17,9 +16,8 @@ import java.security.MessageDigest
class ExportSettingsActivity : Activity() { class ExportSettingsActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val callingPackageName = getCallingPackage()!!
if (getFingerprint(callingPackageName) == getFingerprint(getPackageName())) { if (getFingerprint(callingPackage!!) == getFingerprint(packageName)) {
// Create JSON Object // Create JSON Object
val json = JSONObject() val json = JSONObject()
@@ -64,7 +62,7 @@ class ExportSettingsActivity : Activity() {
fun getFingerprint(packageName: String): String { fun getFingerprint(packageName: String): String {
// Get the signature of the app that matches the package name // Get the signature of the app that matches the package name
val packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES) val packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
val signature = packageInfo.signatures[0] val signature = packageInfo.signatures!![0]
// Get the raw certificate data // Get the raw certificate data
val rawCert = signature.toByteArray() val rawCert = signature.toByteArray()

View File

@@ -9,14 +9,15 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import app.revanced.library.ApkUtils import app.revanced.library.ApkUtils
import app.revanced.library.ApkUtils.applyTo import app.revanced.library.ApkUtils.applyTo
import app.revanced.library.installation.installer.LocalInstaller
import app.revanced.manager.flutter.utils.Aapt import app.revanced.manager.flutter.utils.Aapt
import app.revanced.manager.flutter.utils.packageInstaller.InstallerReceiver import app.revanced.manager.flutter.utils.packageInstaller.InstallerReceiver
import app.revanced.manager.flutter.utils.packageInstaller.UninstallerReceiver import app.revanced.manager.flutter.utils.packageInstaller.UninstallerReceiver
import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.PatchSet
import app.revanced.patcher.Patcher import app.revanced.patcher.Patcher
import app.revanced.patcher.PatcherConfig import app.revanced.patcher.PatcherConfig
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.loadPatchesFromDex
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
@@ -37,7 +38,7 @@ class MainActivity : FlutterActivity() {
private var cancel: Boolean = false private var cancel: Boolean = false
private var stopResult: MethodChannel.Result? = null private var stopResult: MethodChannel.Result? = null
private lateinit var patches: PatchSet private lateinit var patches: Set<Patch<*>>
override fun configureFlutterEngine(flutterEngine: FlutterEngine) { override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine) super.configureFlutterEngine(flutterEngine)
@@ -70,7 +71,6 @@ class MainActivity : FlutterActivity() {
"runPatcher" -> { "runPatcher" -> {
val inFilePath = call.argument<String>("inFilePath") val inFilePath = call.argument<String>("inFilePath")
val outFilePath = call.argument<String>("outFilePath") val outFilePath = call.argument<String>("outFilePath")
val integrationsPath = call.argument<String>("integrationsPath")
val selectedPatches = call.argument<List<String>>("selectedPatches") val selectedPatches = call.argument<List<String>>("selectedPatches")
val options = call.argument<Map<String, Map<String, Any>>>("options") val options = call.argument<Map<String, Map<String, Any>>>("options")
val tmpDirPath = call.argument<String>("tmpDirPath") val tmpDirPath = call.argument<String>("tmpDirPath")
@@ -80,7 +80,6 @@ class MainActivity : FlutterActivity() {
if ( if (
inFilePath != null && inFilePath != null &&
outFilePath != null && outFilePath != null &&
integrationsPath != null &&
selectedPatches != null && selectedPatches != null &&
options != null && options != null &&
tmpDirPath != null && tmpDirPath != null &&
@@ -92,14 +91,17 @@ class MainActivity : FlutterActivity() {
result, result,
inFilePath, inFilePath,
outFilePath, outFilePath,
integrationsPath,
selectedPatches, selectedPatches,
options, options,
tmpDirPath, tmpDirPath,
keyStoreFilePath, keyStoreFilePath,
keystorePassword keystorePassword
) )
} else result.notImplemented() } else result.error(
"INVALID_ARGUMENTS",
"Invalid arguments",
"One or more arguments are missing"
)
} }
"stopPatcher" -> { "stopPatcher" -> {
@@ -113,14 +115,16 @@ class MainActivity : FlutterActivity() {
try { try {
val patchBundleFile = File(patchBundleFilePath) val patchBundleFile = File(patchBundleFilePath)
patchBundleFile.setWritable(false) patchBundleFile.setWritable(false)
patches = PatchBundleLoader.Dex( patches = loadPatchesFromDex(
patchBundleFile, setOf(patchBundleFile),
optimizedDexDirectory = codeCacheDir optimizedDexDirectory = codeCacheDir
) )
} catch (ex: Exception) { } catch (t: Throwable) {
return@setMethodCallHandler result.notImplemented() return@setMethodCallHandler result.error(
} catch (err: Error) { "PATCH_BUNDLE_ERROR",
return@setMethodCallHandler result.notImplemented() "Failed to load patch bundle",
t.stackTraceToString()
)
} }
JSONArray().apply { JSONArray().apply {
@@ -130,13 +134,13 @@ class MainActivity : FlutterActivity() {
put("description", it.description) put("description", it.description)
put("excluded", !it.use) put("excluded", !it.use)
put("compatiblePackages", JSONArray().apply { put("compatiblePackages", JSONArray().apply {
it.compatiblePackages?.forEach { compatiblePackage -> it.compatiblePackages?.forEach { (name, versions) ->
val compatiblePackageJson = JSONObject().apply { val compatiblePackageJson = JSONObject().apply {
put("name", compatiblePackage.name) put("name", name)
put( put(
"versions", "versions",
JSONArray().apply { JSONArray().apply {
compatiblePackage.versions?.forEach { version -> versions?.forEach { version ->
put(version) put(version)
} }
}) })
@@ -172,7 +176,7 @@ class MainActivity : FlutterActivity() {
} }
}) })
} ?: put("values", null) } ?: put("values", null)
put("valueType", option.valueType) put("type", option.type)
}.let(::put) }.let(::put)
} }
}) })
@@ -211,7 +215,6 @@ class MainActivity : FlutterActivity() {
result: MethodChannel.Result, result: MethodChannel.Result,
inFilePath: String, inFilePath: String,
outFilePath: String, outFilePath: String,
integrationsPath: String,
selectedPatches: List<String>, selectedPatches: List<String>,
options: Map<String, Map<String, Any>>, options: Map<String, Map<String, Any>>,
tmpDirPath: String, tmpDirPath: String,
@@ -223,7 +226,6 @@ class MainActivity : FlutterActivity() {
inFile.setWritable(true) inFile.setWritable(true)
inFile.setReadable(true) inFile.setReadable(true)
val outFile = File(outFilePath) val outFile = File(outFilePath)
val integrations = File(integrationsPath)
val keyStoreFile = File(keyStoreFilePath) val keyStoreFile = File(keyStoreFilePath)
val tmpDir = File(tmpDirPath) val tmpDir = File(tmpDirPath)
@@ -281,7 +283,6 @@ class MainActivity : FlutterActivity() {
tmpDir, tmpDir,
Aapt.binary(applicationContext).absolutePath, Aapt.binary(applicationContext).absolutePath,
tmpDir.path, tmpDir.path,
true // TODO: Add option to disable this
) )
) )
@@ -289,8 +290,8 @@ class MainActivity : FlutterActivity() {
updateProgress(0.02, "Loading patches...", "Loading patches") updateProgress(0.02, "Loading patches...", "Loading patches")
val patches = patches.filter { patch -> val patches = patches.filter { patch ->
val isCompatible = patch.compatiblePackages?.any { val isCompatible = patch.compatiblePackages?.any { (name, _) ->
it.name == patcher.context.packageMetadata.packageName name == patcher.context.packageMetadata.packageName
} ?: false } ?: false
val compatibleOrUniversal = val compatibleOrUniversal =
@@ -307,10 +308,7 @@ class MainActivity : FlutterActivity() {
updateProgress(0.05, "Executing...", "") updateProgress(0.05, "Executing...", "")
val patcherResult = patcher.use { val patcherResult = patcher.use {
patcher.apply { it += patches
acceptIntegrations(setOf(integrations))
acceptPatches(patches)
}
runBlocking { runBlocking {
// Update the progress bar every time a patch is executed from 0.15 to 0.7 // Update the progress bar every time a patch is executed from 0.15 to 0.7
@@ -318,7 +316,7 @@ class MainActivity : FlutterActivity() {
val progressStep = 0.55 / totalPatchesCount val progressStep = 0.55 / totalPatchesCount
var progress = 0.05 var progress = 0.05
patcher.apply(false).collect(FlowCollector { patchResult: PatchResult -> patcher().collect(FlowCollector { patchResult: PatchResult ->
if (cancel(patcher::close)) return@FlowCollector if (cancel(patcher::close)) return@FlowCollector
val msg = patchResult.exception?.let { val msg = patchResult.exception?.let {
@@ -346,10 +344,11 @@ class MainActivity : FlutterActivity() {
if (cancel(patcher::close)) return@Thread if (cancel(patcher::close)) return@Thread
ApkUtils.sign( ApkUtils.signApk(
inFile, inFile,
outFile, outFile,
ApkUtils.SigningOptions( "ReVanced",
ApkUtils.KeyStoreDetails(
keyStoreFile, keyStoreFile,
keystorePassword, keystorePassword,
"alias", "alias",

View File

@@ -1,4 +1,5 @@
import com.android.build.api.dsl.CommonExtension import com.android.build.api.dsl.CommonExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
allprojects { allprojects {
repositories { repositories {
@@ -17,11 +18,20 @@ allprojects {
layout.buildDirectory = File("../build") layout.buildDirectory = File("../build")
project(":screenshot_callback") {
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "17"
}
}
}
subprojects { subprojects {
afterEvaluate { afterEvaluate {
extensions.findByName("android")?.let { extensions.findByName("android")?.let {
it as CommonExtension<*, *, *, *, *, *> it as CommonExtension<*, *, *, *, *, *>
it.compileSdk = 34 if (it.compileSdk != null && it.compileSdk!! < 31)
it.compileSdk = 34
} }
} }

View File

@@ -3,6 +3,5 @@ android.useAndroidX=true
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.caching=true org.gradle.caching=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false android.nonTransitiveRClass=false
android.nonFinalResIds=false android.nonFinalResIds=false

View File

@@ -1,7 +1,7 @@
[versions] [versions]
revanced-patcher = "19.3.1" # TODO: Update to non-dev revanced-patcher = "21.0.0"
revanced-library = "2.2.1" revanced-library = "3.0.2"
desugar_jdk_libs = "2.1.2" desugar_jdk_libs = "2.1.3"
[libraries] [libraries]
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" } revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }

View File

@@ -17,7 +17,7 @@ pluginManagement {
plugins { plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.0" apply false id("com.android.application") version "8.7.2" apply false
id("org.jetbrains.kotlin.android") version "2.0.20" apply false id("org.jetbrains.kotlin.android") version "2.0.20" apply false
} }

View File

@@ -158,20 +158,18 @@
"languageLabel": "Language", "languageLabel": "Language",
"languageUpdated": "Language updated", "languageUpdated": "Language updated",
"sourcesLabel": "Alternative sources", "sourcesLabel": "Alternative sources",
"sourcesLabelHint": "Configure the alternative sources for ReVanced Patches and ReVanced Integrations", "sourcesLabelHint": "Configure the alternative sources for ReVanced Patches",
"sourcesIntegrationsLabel": "Integrations source",
"useAlternativeSources": "Use alternative sources", "useAlternativeSources": "Use alternative sources",
"useAlternativeSourcesHint": "Use alternative sources for ReVanced Patches and ReVanced Integrations instead of the API", "useAlternativeSourcesHint": "Use alternative sources for ReVanced Patches instead of the API",
"sourcesResetDialogTitle": "Reset", "sourcesResetDialogTitle": "Reset",
"sourcesResetDialogText": "Are you sure you want to reset your sources to their default values?", "sourcesResetDialogText": "Are you sure you want to reset your sources to their default values?",
"apiURLResetDialogText": "Are you sure you want to reset your API URL to its default value?", "apiURLResetDialogText": "Are you sure you want to reset your API URL to its default value?",
"sourcesUpdateNote": "Note: This will automatically download ReVanced Patches and ReVanced Integrations from the alternative sources.\n\nThis will connect you to the alternative source.", "sourcesUpdateNote": "Note: This will automatically download ReVanced Patches from the alternative sources.\n\nThis will connect you to the alternative source.",
"apiURLLabel": "API URL", "apiURLLabel": "API URL",
"apiURLHint": "Configure the API URL of ReVanced Manager", "apiURLHint": "Configure the API URL of ReVanced Manager",
"selectApiURL": "API URL", "selectApiURL": "API URL",
"orgPatchesLabel": "Patches organization", "orgPatchesLabel": "Patches organization",
"sourcesPatchesLabel": "Patches source", "sourcesPatchesLabel": "Patches source",
"orgIntegrationsLabel": "Integrations organization",
"contributorsLabel": "Contributors", "contributorsLabel": "Contributors",
"contributorsHint": "A list of contributors of ReVanced", "contributorsHint": "A list of contributors of ReVanced",
"logsLabel": "Share logs", "logsLabel": "Share logs",
@@ -199,6 +197,12 @@
"deleteTempDirLabel": "Delete temporary files", "deleteTempDirLabel": "Delete temporary files",
"deleteTempDirHint": "Delete unused temporary files", "deleteTempDirHint": "Delete unused temporary files",
"deletedTempDir": "Temporary files deleted", "deletedTempDir": "Temporary files deleted",
"exportSettingsLabel": "Export settings",
"exportSettingsHint": "Export settings to a JSON file",
"exportedSettings": "Settings exported",
"importSettingsLabel": "Import settings",
"importSettingsHint": "Import settings from a JSON file",
"importedSettings": "Settings imported",
"exportPatchesLabel": "Export patch selection", "exportPatchesLabel": "Export patch selection",
"exportPatchesHint": "Export patch selection to a JSON file", "exportPatchesHint": "Export patch selection to a JSON file",
"exportedPatches": "Patch selection exported", "exportedPatches": "Patch selection exported",

View File

@@ -55,7 +55,8 @@
"widgetTitle": "المُعَّدِّل", "widgetTitle": "المُعَّدِّل",
"patchButton": "تعديل", "patchButton": "تعديل",
"incompatibleArchWarningDialogText": "لم يتم دعم التعديلات الخاصة بهذه البنية حتى الآن وقد تفشل. هل تريد المتابعة على أي حال؟", "incompatibleArchWarningDialogText": "لم يتم دعم التعديلات الخاصة بهذه البنية حتى الآن وقد تفشل. هل تريد المتابعة على أي حال؟",
"removedPatchesWarningDialogText": "تم إزالة التعديلات التالية منذ آخر مرة استخدمتها فيها.\n\n${patches}\n\n${newPatches}تابع على أي حال؟", "removedPatchesWarningDialogText": "تمت إزالة التعديلات منذ آخر مرة قمت فيها بتعديل هذا التطبيق:\n\n${patches}\n\n${newPatches}هل تريد المتابعة على أي حال؟",
"addedPatchesDialogText": "تمت إضافة التعديلات منذ آخر مرة قمت فيها بتعديل هذا التطبيق:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "يجب ضبط بعض خيارات التعديل." "requiredOptionDialogText": "يجب ضبط بعض خيارات التعديل."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Yamaqlayıcı", "widgetTitle": "Yamaqlayıcı",
"patchButton": "Yamaqla", "patchButton": "Yamaqla",
"incompatibleArchWarningDialogText": "Bu quruluşda yamaqlama hələ dəstəklənmir və uğursuz ola bilər. Yenə də davam edilsin?", "incompatibleArchWarningDialogText": "Bu quruluşda yamaqlama hələ dəstəklənmir və uğursuz ola bilər. Yenə də davam edilsin?",
"removedPatchesWarningDialogText": "Aşağıdakı yamaqlar son istifadənizdən bəri silindi.\n\n${patches}\n\n${newPatches}Yenə də davam edilsin?", "removedPatchesWarningDialogText": "Bu tətbiqi son yamaqladığınız müddətdən bəri silinmiş yamaqlar:\n\n${patches}\n\n${newPatches}Yenə də davam edilsin?",
"addedPatchesDialogText": "Bu tətbiqi son yamaqladığınız müddətdən bəri əlavə edilən yamaqlar:\n\n${addedPatches}",
"requiredOptionDialogText": "Bəzi yamaq seçimləri təyin edilməlidir." "requiredOptionDialogText": "Bəzi yamaq seçimləri təyin edilməlidir."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,6 @@
"widgetTitle": "Праграма выпраўлення", "widgetTitle": "Праграма выпраўлення",
"patchButton": "Выправіць", "patchButton": "Выправіць",
"incompatibleArchWarningDialogText": "Выпраўленні на гэтай архітэктуры пакуль не падтрымліваюцца і могуць не працаваць. Працягнуць?", "incompatibleArchWarningDialogText": "Выпраўленні на гэтай архітэктуры пакуль не падтрымліваюцца і могуць не працаваць. Працягнуць?",
"removedPatchesWarningDialogText": "Наступныя выпраўленні былі выдалены з моманту іх апошняга выкарыстання.\n\n${patches}\n\n${newPatches}Усё роўна працягнуць?",
"requiredOptionDialogText": "Неабходна задаць некаторыя параметры выпраўленняў." "requiredOptionDialogText": "Неабходна задаць некаторыя параметры выпраўленняў."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Модификатор", "widgetTitle": "Модификатор",
"patchButton": "Модифицирайте", "patchButton": "Модифицирайте",
"incompatibleArchWarningDialogText": "Процесът на модифициране в момента не се поддържа на устройства с тази архитектура и може да се провали. Ще продължите ли?", "incompatibleArchWarningDialogText": "Процесът на модифициране в момента не се поддържа на устройства с тази архитектура и може да се провали. Ще продължите ли?",
"removedPatchesWarningDialogText": "Следните модификации са били премахнати след като са били употребени за последно от вас.\n\n${patches}\n\n${newPatches}Продължете въпреки това?", "removedPatchesWarningDialogText": "Премахнати пачове след последната корекция на приложението:\n\n${patches}\n\n${newPatches}Да продължа ли все пак?",
"addedPatchesDialogText": "След последната промяна на това приложение бяха добавени следните модификации:\n\n${addedPatches}",
"requiredOptionDialogText": "Опциите на някои модификации трябва да бъдат зададени." "requiredOptionDialogText": "Опциите на някои модификации трябва да бъдат зададени."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,6 @@
"widgetTitle": "প্যাচার", "widgetTitle": "প্যাচার",
"patchButton": "প্যাচ", "patchButton": "প্যাচ",
"incompatibleArchWarningDialogText": "এই আর্কিটেকচারে প্যাচিং এখনো সমর্থিত নয় এবং সফল নাও হতে পারে। যেকোন ভাবে এগিয়ে যেতে চান?", "incompatibleArchWarningDialogText": "এই আর্কিটেকচারে প্যাচিং এখনো সমর্থিত নয় এবং সফল নাও হতে পারে। যেকোন ভাবে এগিয়ে যেতে চান?",
"removedPatchesWarningDialogText": "আপনি এর আগে যখন ব্যবহার করেছিলেন তারপর এই প্যাচগুলো অপসারণ করা হয়।\n\n${patches}\n\n${newPatches}যেকোন ভাবে এগিয়ে যেতে চান?",
"requiredOptionDialogText": "কিছু প্যাচ অপশন সেট করতে হবে।" "requiredOptionDialogText": "কিছু প্যাচ অপশন সেট করতে হবে।"
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Záplatovač", "widgetTitle": "Záplatovač",
"patchButton": "Záplatovat", "patchButton": "Záplatovat",
"incompatibleArchWarningDialogText": "Úprava této architektury není zatím podporována a může selhat. Přesto pokračovat?", "incompatibleArchWarningDialogText": "Úprava této architektury není zatím podporována a může selhat. Přesto pokračovat?",
"removedPatchesWarningDialogText": "Následující záplaty byly odstraněny od doby, kdy jste je naposledy použili.\n\n${patches}\n\n${newPatches}Přesto pokračovat?", "removedPatchesWarningDialogText": "Odstranili jste záplaty od poslední úpravy této aplikace:\n\n${patches}\n\n${newPatches}Pokračovat?",
"addedPatchesDialogText": "Přidány záplaty od poslední úpravy této aplikace:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Je třeba nastavit některé možnosti záplat." "requiredOptionDialogText": "Je třeba nastavit některé možnosti záplat."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Patch", "patchButton": "Patch",
"incompatibleArchWarningDialogText": "Patching på denne arkitektur understøttes endnu ikke og kan mislykkes. Fortsæt alligevel?", "incompatibleArchWarningDialogText": "Patching på denne arkitektur understøttes endnu ikke og kan mislykkes. Fortsæt alligevel?",
"removedPatchesWarningDialogText": "Følgende patches er blevet fjernet siden sidste gang du brugte dem.\n\n${patches}\n\n${newPatches}Fortsæt alligevel?", "removedPatchesWarningDialogText": "Fjernede rettelser siden sidste gang du lappede denne app:\n\n${patches}\n\n${newPatches}Fortsæt alligevel?",
"addedPatchesDialogText": "Tilføjet rettelser siden sidste gang du lappede denne app:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Nogle patch muligheder skal indstilles." "requiredOptionDialogText": "Nogle patch muligheder skal indstilles."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Patchen", "patchButton": "Patchen",
"incompatibleArchWarningDialogText": "Patches auf dieser Architektur werden noch nicht unterstützt und könnten fehlschlagen. Trotzdem fortfahren?", "incompatibleArchWarningDialogText": "Patches auf dieser Architektur werden noch nicht unterstützt und könnten fehlschlagen. Trotzdem fortfahren?",
"removedPatchesWarningDialogText": "Die folgenden Patches wurden seit der letzten Verwendung entfernt.\n\n${patches}\n\n${newPatches}Trotzdem fortfahren?", "removedPatchesWarningDialogText": "Patches seit dem letzten Mal, dass Sie diese App gepatcht haben, entfernt:\n\n${patches}\n\n${newPatches}Trotzdem fortfahren?",
"addedPatchesDialogText": "Patches seit dem letzten Mal, dass Sie diese App gepatcht haben:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Einige Patch-Optionen müssen gesetzt werden." "requiredOptionDialogText": "Einige Patch-Optionen müssen gesetzt werden."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Τροποποιητής", "widgetTitle": "Τροποποιητής",
"patchButton": "Τροποποίηση", "patchButton": "Τροποποίηση",
"incompatibleArchWarningDialogText": "Η διαδικασία της τροποποίησης δεν υποστηρίζεται προς το παρόν σε συσκευές της συγκεκριμένης αρχιτεκτονικής και μπορεί να αποτύχει. Συνέχεια παρόλα αυτά;", "incompatibleArchWarningDialogText": "Η διαδικασία της τροποποίησης δεν υποστηρίζεται προς το παρόν σε συσκευές της συγκεκριμένης αρχιτεκτονικής και μπορεί να αποτύχει. Συνέχεια παρόλα αυτά;",
"removedPatchesWarningDialogText": "Οι παρακάτω τροποποιήσεις αφαιρέθηκαν από την τελευταία φορά που τις χρησιμοποιήσατε.\n\n${patches}\n\n${newPatches}Συνέχεια παρόλα αυτά;", "removedPatchesWarningDialogText": "Από την τελευταία φορά που τροποποιήσατε αυτή την εφαρμογή, έχουν αφαιρεθεί οι εξής τροποποιήσεις:\n\n${patches}\n\n${newPatches}Συνέχεια παρ' όλα αυτά;",
"addedPatchesDialogText": "Από την τελευταία φορά που τροποποιήσατε αυτή την εφαρμογή, έχουν προστεθεί οι εξής τροποποιήσεις:\n\n${addedPatches}",
"requiredOptionDialogText": "Κάποιες επιλογές τροποποιήσεων πρέπει να οριστούν." "requiredOptionDialogText": "Κάποιες επιλογές τροποποιήσεων πρέπει να οριστούν."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Parcheador", "widgetTitle": "Parcheador",
"patchButton": "Parchear", "patchButton": "Parchear",
"incompatibleArchWarningDialogText": "El parche en esta arquitectura aún no está soportado y podría fallar. ¿Continuar de todos modos?", "incompatibleArchWarningDialogText": "El parche en esta arquitectura aún no está soportado y podría fallar. ¿Continuar de todos modos?",
"removedPatchesWarningDialogText": "Los siguientes parches han sido eliminados desde la última vez que los usaste.\n\n${patches}\n\n${newPatches}¿Continuar de todos modos?", "removedPatchesWarningDialogText": "Eliminados parches desde la última vez que parcheaste esta aplicación:\n\n${patches}\n\n${newPatches}¿Continuar de todos modos?",
"addedPatchesDialogText": "Añadidos parches desde la última vez que parcheaste esta aplicación:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Deben establecerse algunas opciones de parche." "requiredOptionDialogText": "Deben establecerse algunas opciones de parche."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -51,7 +51,6 @@
"patcherView": { "patcherView": {
"widgetTitle": "Parandaja", "widgetTitle": "Parandaja",
"patchButton": "Parandus", "patchButton": "Parandus",
"removedPatchesWarningDialogText": "Väljatoodud parandused on vahepeal eemaldatud.\n\n${patches}\n\n${newPatches}Jätka ikkagi? ",
"requiredOptionDialogText": "Mõned paranduste sätted on vaja valida. " "requiredOptionDialogText": "Mõned paranduste sätted on vaja valida. "
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,7 @@
"widgetTitle": "Paikkaaja", "widgetTitle": "Paikkaaja",
"patchButton": "Paikkaa", "patchButton": "Paikkaa",
"incompatibleArchWarningDialogText": "Paikkaamista ei vielä tueta tällä kokoonpanolla, ja se saattaa epäonnistua. Jatketaanko silti?", "incompatibleArchWarningDialogText": "Paikkaamista ei vielä tueta tällä kokoonpanolla, ja se saattaa epäonnistua. Jatketaanko silti?",
"removedPatchesWarningDialogText": "Seuraavat paikkaukset on poistettu edellisen käyttökerran jälkeen.\n\n${patches}\n\n${newPatches}Jatketaanko silti?", "removedPatchesWarningDialogText": "Poistetut paikat viimeisen laastariesi jälkeen tämän sovelluksen:\n\n${patches}\n\n${newPatches}Jatka joka tapauksessa?",
"requiredOptionDialogText": "Joitakin paikkausasetuksia on määritettävä." "requiredOptionDialogText": "Joitakin paikkausasetuksia on määritettävä."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -52,7 +52,6 @@
"patcherView": { "patcherView": {
"widgetTitle": "Tagapagtapal", "widgetTitle": "Tagapagtapal",
"patchButton": "Tapalan", "patchButton": "Tapalan",
"removedPatchesWarningDialogText": "Ang mga sumusunod na patches ay tinanggal mula noong huling beses mong gamitin ang mga ito.\n\n${patches}\n\n${newPatches}Ituloy pa rin ba?",
"requiredOptionDialogText": "Kailangan mo i-set ang ilang mga opsyon para sa patch." "requiredOptionDialogText": "Kailangan mo i-set ang ilang mga opsyon para sa patch."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patcheur", "widgetTitle": "Patcheur",
"patchButton": "Patcher", "patchButton": "Patcher",
"incompatibleArchWarningDialogText": "La correction sur cette architecture n'est pas encore prise en charge et pourrait échouer. Continuer quand même ?", "incompatibleArchWarningDialogText": "La correction sur cette architecture n'est pas encore prise en charge et pourrait échouer. Continuer quand même ?",
"removedPatchesWarningDialogText": "Les patchs suivants ont été supprimés depuis la dernière fois que vous les avez utilisés.\n\n${patches}\n\n${newPatches}Continuer quand même ?", "removedPatchesWarningDialogText": "Les patchs supprimés depuis la dernière fois que vous avez patché cette application :\n\n${patches}\n\n${newPatches}Continuer quand même ?",
"addedPatchesDialogText": "Ajout de correctifs depuis la dernière fois que vous avez patché cette application :\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Certaines options de patch doivent être définies." "requiredOptionDialogText": "Certaines options de patch doivent être définies."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,6 @@
"widgetTitle": "Paisteálaí", "widgetTitle": "Paisteálaí",
"patchButton": "Paiste", "patchButton": "Paiste",
"incompatibleArchWarningDialogText": "Níl paisteáil ar an ailtireacht seo tacaítear leis go fóill agus dfhéadfadh sé teip. Lean ar aghaidh fós?", "incompatibleArchWarningDialogText": "Níl paisteáil ar an ailtireacht seo tacaítear leis go fóill agus dfhéadfadh sé teip. Lean ar aghaidh fós?",
"removedPatchesWarningDialogText": "Baineadh na paistí seo a leanas ón uair dheireanach a d'úsáid tú iad.\n\n${patches}\n\n${newPatches}Lean ar aghaidh fós?",
"requiredOptionDialogText": "Caithfear roinnt roghanna paiste a shocrú." "requiredOptionDialogText": "Caithfear roinnt roghanna paiste a shocrú."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -51,7 +51,6 @@
"patcherView": { "patcherView": {
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "תיקון", "patchButton": "תיקון",
"removedPatchesWarningDialogText": "התיקונים הבאים הוסרו מאז הפעם האחרונה שהשתמשת בהם.\n\n${patches}\n\n${newPatches}להמשיך בכל זאת?",
"requiredOptionDialogText": "כמה אפשרויות תיקון חייבות להיקבע." "requiredOptionDialogText": "כמה אפשרויות תיקון חייבות להיקבע."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patchelő", "widgetTitle": "Patchelő",
"patchButton": "Patch", "patchButton": "Patch",
"incompatibleArchWarningDialogText": "Ezen az architektúrán a patchelés még nem támogatott, és sikertelen lehet. Mégis folytatod?", "incompatibleArchWarningDialogText": "Ezen az architektúrán a patchelés még nem támogatott, és sikertelen lehet. Mégis folytatod?",
"removedPatchesWarningDialogText": "A következő patcheket a legutóbbi használatuk óta eltávolították.\n\n${patches}\n\n${newPatches}Mindenképpen folytatja?", "removedPatchesWarningDialogText": "Az alkalmazás legutóbbi javítása óta eltávolított javítások:\n\n${patches}\n\n${newPatches}Amúgy folytatja?",
"addedPatchesDialogText": "Javítások hozzáadva az alkalmazás legutóbbi javítása óta:\n\n${addedPatches}",
"requiredOptionDialogText": "Néhány patch lehetőséget be kell állítani." "requiredOptionDialogText": "Néhány patch lehetőséget be kell állítani."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -29,13 +29,13 @@
"noSavedAppFound": "App tidak ditemukan", "noSavedAppFound": "App tidak ditemukan",
"noInstallations": "Aplikasi tertambal tidak terpasang", "noInstallations": "Aplikasi tertambal tidak terpasang",
"installUpdate": "Lanjutkan untuk mengunduh pembaruan?", "installUpdate": "Lanjutkan untuk mengunduh pembaruan?",
"updateSheetTitle": "Perbarui Manajer ReVanced", "updateSheetTitle": "Perbarui ReVanced Manager",
"updateDialogTitle": "Pembaruan terkini telah tersedia", "updateDialogTitle": "Pembaruan baru telah tersedia",
"updatePatchesSheetTitle": "Perbarui Tambalan ReVanced", "updatePatchesSheetTitle": "Perbarui Tambalan ReVanced",
"updateChangelogTitle": "Catatan perubahan", "updateChangelogTitle": "Catatan perubahan",
"updateDialogText": "Pembaruan telah tersedia untuk ${file}.\n\nVersi yang diinstal saat ini adalah ${version}.", "updateDialogText": "Pembaruan telah tersedia untuk ${file}.\n\nVersi yang dipasang saat ini adalah ${version}.",
"downloadConsentDialogTitle": "Unduh file yang diperlukan?", "downloadConsentDialogTitle": "Unduh file yang diperlukan?",
"downloadConsentDialogText": "Manajer ReVanced perlu mengunduh file yang diperlukan agar berfungsi dengan baik.", "downloadConsentDialogText": "ReVanced Manager perlu mengunduh berkas yang diperlukan agar berfungsi dengan baik.",
"downloadConsentDialogText2": "Ini akan menghubungkan Anda ke ${url}.", "downloadConsentDialogText2": "Ini akan menghubungkan Anda ke ${url}.",
"downloadingMessage": "Mengunduh pembaruan...", "downloadingMessage": "Mengunduh pembaruan...",
"downloadedMessage": "Pembaruan telah diunduh", "downloadedMessage": "Pembaruan telah diunduh",
@@ -55,7 +55,8 @@
"widgetTitle": "Penambal", "widgetTitle": "Penambal",
"patchButton": "Tambalan", "patchButton": "Tambalan",
"incompatibleArchWarningDialogText": "Menambal pada arsitektur ini belum didukung dan kemungkinan gagal. Lanjutkan saja?", "incompatibleArchWarningDialogText": "Menambal pada arsitektur ini belum didukung dan kemungkinan gagal. Lanjutkan saja?",
"removedPatchesWarningDialogText": "Tambalan berikut telah dihapus sejak terakhir kali Anda menggunakannya.\n\n${patches}\n\n${newPatches}Tetap lanjut?", "removedPatchesWarningDialogText": "Tambalan yang dihapus sejak terakhir kali Anda menambal aplikasi ini:\n\n${patches}\n\n${newPatches}Tetap lanjutkan?",
"addedPatchesDialogText": "Tambalan yang ditambahkan sejak terakhir kali Anda menambal aplikasi ini:\n\n${addedPatches}",
"requiredOptionDialogText": "Beberapa pilihan tambalan harus diatur." "requiredOptionDialogText": "Beberapa pilihan tambalan harus diatur."
}, },
"appSelectorCard": { "appSelectorCard": {
@@ -63,7 +64,7 @@
"widgetTitleSelected": "Aplikasi yang dipilih", "widgetTitleSelected": "Aplikasi yang dipilih",
"widgetSubtitle": "Tidak ada aplikasi yang dipilih", "widgetSubtitle": "Tidak ada aplikasi yang dipilih",
"noAppsLabel": "Aplikasi tidak ditemukan", "noAppsLabel": "Aplikasi tidak ditemukan",
"anyVersion": "Versi apa saja" "anyVersion": "Versi apapun"
}, },
"patchSelectorCard": { "patchSelectorCard": {
"widgetTitle": "Pilih tambalan", "widgetTitle": "Pilih tambalan",
@@ -83,7 +84,7 @@
"errorMessage": "Tidak dapat menggunakan aplikasi yang dipilih", "errorMessage": "Tidak dapat menggunakan aplikasi yang dipilih",
"downloadToast": "Fungsi mengunduh belum tersedia", "downloadToast": "Fungsi mengunduh belum tersedia",
"requireSuggestedAppVersionDialogText": "Versi aplikasi yang Anda pilih tidak sesuai dengan versi yang disarankan yang dapat menyebabkan masalah yang tidak diharapkan. Silakan gunakan versi yang disarankan.\n\nVersi yang dipilih: ${selected}\nVersi yang disarankan: ${suggested}\n\nUntuk melanjutkan, nonaktifkan \"Memerlukan versi aplikasi yang disarankan\" di pengaturan.", "requireSuggestedAppVersionDialogText": "Versi aplikasi yang Anda pilih tidak sesuai dengan versi yang disarankan yang dapat menyebabkan masalah yang tidak diharapkan. Silakan gunakan versi yang disarankan.\n\nVersi yang dipilih: ${selected}\nVersi yang disarankan: ${suggested}\n\nUntuk melanjutkan, nonaktifkan \"Memerlukan versi aplikasi yang disarankan\" di pengaturan.",
"featureNotAvailable": "Fitur tidak diimplementasi", "featureNotAvailable": "Fitur belum diterapkan",
"featureNotAvailableText": "Aplikasi ini adalah APK terpisah yang hanya dapat ditambal dan dipasang melalui cara mount dengan izin root. Namun, Anda dapat menambal dan memasang APK lengkap dengan memilihnya dari penyimpanan." "featureNotAvailableText": "Aplikasi ini adalah APK terpisah yang hanya dapat ditambal dan dipasang melalui cara mount dengan izin root. Namun, Anda dapat menambal dan memasang APK lengkap dengan memilihnya dari penyimpanan."
}, },
"patchesSelectorView": { "patchesSelectorView": {
@@ -99,11 +100,11 @@
"noneTooltip": "Batalkan semua tambalan", "noneTooltip": "Batalkan semua tambalan",
"loadPatchesSelection": "Muat tambalan terpilih", "loadPatchesSelection": "Muat tambalan terpilih",
"noSavedPatches": "Tidak ada pilihan tambalan yang disimpan untuk aplikasi yang dipilih.\nTekan Selesai untuk menyimpan pilihan saat ini.", "noSavedPatches": "Tidak ada pilihan tambalan yang disimpan untuk aplikasi yang dipilih.\nTekan Selesai untuk menyimpan pilihan saat ini.",
"noPatchesFound": "Tidak ada tambalan untuk aplikasi", "noPatchesFound": "Tidak ada tambalan untuk aplikasi terpilih",
"setRequiredOption": "Beberapa tambalan memerlukan pilihan untuk diatur:\n\n${patches}\n\nAturlah sebelum melanjutkan." "setRequiredOption": "Beberapa tambalan memerlukan pilihan untuk diatur:\n\n${patches}\n\nAturlah sebelum melanjutkan."
}, },
"patchOptionsView": { "patchOptionsView": {
"customValue": "Nilai kustom", "customValue": "Nilai khusus",
"setToNull": "Setel ke null", "setToNull": "Setel ke null",
"nullValue": "Nilai pilihan ini saat ini adalah null", "nullValue": "Nilai pilihan ini saat ini adalah null",
"viewTitle": "Pilihan tambalan", "viewTitle": "Pilihan tambalan",
@@ -112,14 +113,14 @@
"tooltip": "Pilihan masukan lainnya", "tooltip": "Pilihan masukan lainnya",
"selectFilePath": "Pilih lokasi berkas", "selectFilePath": "Pilih lokasi berkas",
"selectFolder": "Pilih folder", "selectFolder": "Pilih folder",
"requiredOption": "Pengaturan opsi ini diperlukan", "requiredOption": "Pengaturan pilihan ini diperlukan",
"unsupportedOption": "Pilihan ini tidak didukung", "unsupportedOption": "Pilihan ini tidak didukung",
"requiredOptionNull": "Pilihan ini harus terpilih:\n\n${options}" "requiredOptionNull": "Pilihan ini harus terpilih:\n\n${options}"
}, },
"patchItem": { "patchItem": {
"unsupportedDialogText": "Memilih tambalan ini akan menyebabkan kegagalan tambal.\n\nVersi apli: ${packageVersion}\nVersi anjuran:\n${supportedVersions}", "unsupportedDialogText": "Memilih tambalan ini mungkin menyebabkan kegagalan tambal.\n\nVersi aplikasi: ${packageVersion}\nVersi yang didukung:\n${supportedVersions}",
"unsupportedPatchVersion": "Tambalan ini tidak mendukung versi aplikasi ini.", "unsupportedPatchVersion": "Tambalan ini tidak mendukung versi aplikasi ini.",
"unsupportedRequiredOption": "Tambalan ini berisi opsi wajib yang tidak didukung oleh aplikasi ini", "unsupportedRequiredOption": "Tambalan ini berisi pilihan wajib yang tidak didukung oleh aplikasi ini",
"patchesChangeWarningDialogText": "Direkomendasikan untuk menggunakan pilihan dan opsi tambalan bawaan. Mengubahnya dapat mengakibatkan masalah yang tidak diharapkan.\n\nAnda harus mengaktifkan \"Izinkan perubahan pilihan tambalan\" dalam pengaturan sebelum mengubah pilihan tambalan.", "patchesChangeWarningDialogText": "Direkomendasikan untuk menggunakan pilihan dan opsi tambalan bawaan. Mengubahnya dapat mengakibatkan masalah yang tidak diharapkan.\n\nAnda harus mengaktifkan \"Izinkan perubahan pilihan tambalan\" dalam pengaturan sebelum mengubah pilihan tambalan.",
"patchesChangeWarningDialogButton": "Gunakan pemilihan bawaan" "patchesChangeWarningDialogButton": "Gunakan pemilihan bawaan"
}, },
@@ -129,13 +130,13 @@
"installButton": "Pasang", "installButton": "Pasang",
"installRootType": "Mount", "installRootType": "Mount",
"installNonRootType": "Reguler", "installNonRootType": "Reguler",
"warning": "Nonaktifkan pembaruan pada aplikasi tertambal untuk menghindari isu.", "warning": "Nonaktifkan pembaruan pada aplikasi tertambal untuk menghindari masalah.",
"pressBackAgain": "Tekan tombol balik lagi untuk membatalkan", "pressBackAgain": "Tekan tombol kembali untuk membatalkan",
"openButton": "Buka", "openButton": "Buka",
"notificationTitle": "ReVanced Manager sedang menambal", "notificationTitle": "ReVanced Manager sedang menambal",
"notificationText": "Ketuk untuk kembali ke pemasang", "notificationText": "Ketuk untuk kembali ke pemasang",
"exportApkButtonTooltip": "Ekspor APK yang ditambal", "exportApkButtonTooltip": "Ekspor APK yang ditambal",
"exportLogButtonTooltip": "Log ekspor", "exportLogButtonTooltip": "Ekspor log",
"screenshotDetected": "Tangkapan layar telah terdeteksi. Jika Anda mencoba membagikan log, silakan bagikan salinan teks.\n\nMenyalin log ke papan klip?", "screenshotDetected": "Tangkapan layar telah terdeteksi. Jika Anda mencoba membagikan log, silakan bagikan salinan teks.\n\nMenyalin log ke papan klip?",
"copiedToClipboard": "Menyalin log ke papan klip", "copiedToClipboard": "Menyalin log ke papan klip",
"noExit": "Pemasangan masih berjalan, tidak bisa keluar..." "noExit": "Pemasangan masih berjalan, tidak bisa keluar..."
@@ -150,45 +151,45 @@
"dataSectionTitle": "Sumber data", "dataSectionTitle": "Sumber data",
"themeModeLabel": "Tema aplikasi", "themeModeLabel": "Tema aplikasi",
"systemThemeLabel": "Sistem", "systemThemeLabel": "Sistem",
"lightThemeLabel": "Cahaya", "lightThemeLabel": "Terang",
"darkThemeLabel": "Mode gelap", "darkThemeLabel": "Gelap",
"dynamicThemeLabel": "Material You", "dynamicThemeLabel": "Material You",
"dynamicThemeHint": "Nikmati pengalaman lebih dekat ke perangkat Anda", "dynamicThemeHint": "Nikmati pengalaman lebih dekat ke perangkat Anda",
"languageLabel": "Bahasa", "languageLabel": "Bahasa",
"languageUpdated": "Bahasa diperbaharui", "languageUpdated": "Bahasa diperbarui",
"sourcesLabel": "Sumber-sumber alternatif", "sourcesLabel": "Sumber alternatif",
"sourcesLabelHint": "Mengonfigurasi sumber alternatif untuk ReVanced Patches dan ReVanced Integrations", "sourcesLabelHint": "Atur sumber alternatif untuk ReVanced Patches dan ReVanced Integrations",
"sourcesIntegrationsLabel": "Sumber Integrasi", "sourcesIntegrationsLabel": "Sumber Integrasi",
"useAlternativeSources": "Gunakan sumber-sumber alternatif", "useAlternativeSources": "Gunakan sumber alternatif",
"useAlternativeSourcesHint": "Gunakan sumber alternatif untuk ReVanced Patches dan ReVanced Integrations alih-alih API", "useAlternativeSourcesHint": "Gunakan sumber alternatif untuk ReVanced Patches dan ReVanced Integrations daripada API",
"sourcesResetDialogTitle": "Atur ulang", "sourcesResetDialogTitle": "Atur ulang",
"sourcesResetDialogText": "Apakah Anda yakin ingin mengatur ulang sumber kustom ke bawaannya?", "sourcesResetDialogText": "Apakah Anda yakin ingin mengatur ulang sumber khusus ke sumber bawaan?",
"apiURLResetDialogText": "Apakah Anda yakin ingin mengatur ulang URL API ke bawaan?", "apiURLResetDialogText": "Apakah Anda yakin ingin mengatur ulang URL API ke bawaan?",
"sourcesUpdateNote": "Catatan: Ini akan secara otomatis mengunduh ReVanced Patches dan ReVanced Integrations dari sumber alternatif.\n\nIni akan menghubungkan Anda ke sumber alternatif.", "sourcesUpdateNote": "Catatan: Ini akan secara otomatis mengunduh ReVanced Patches dan ReVanced Integrations dari sumber alternatif.\n\nIni akan menghubungkan Anda ke sumber alternatif.",
"apiURLLabel": "URL API", "apiURLLabel": "URL API",
"apiURLHint": "Konfigurasikan URL API dari ReVanced Manager", "apiURLHint": "Atur URL API dari ReVanced Manager",
"selectApiURL": "URL API", "selectApiURL": "URL API",
"orgPatchesLabel": "Perapihan tambalan", "orgPatchesLabel": "Organisasi tambalan",
"sourcesPatchesLabel": "Sumber tambalan", "sourcesPatchesLabel": "Sumber tambalan",
"orgIntegrationsLabel": "Organisasi Intergrasi", "orgIntegrationsLabel": "Organisasi Integrasi",
"contributorsLabel": "Kontributor", "contributorsLabel": "Kontributor",
"contributorsHint": "Daftar kontributor ReVanced", "contributorsHint": "Daftar kontributor ReVanced",
"logsLabel": "Bagikan log", "logsLabel": "Bagikan log",
"logsHint": "Bagikan log ReVanced Manager", "logsHint": "Bagikan log ReVanced Manager",
"enablePatchesSelectionLabel": "Izinkan mengubah pemilihan tambalan", "enablePatchesSelectionLabel": "Izinkan mengubah pemilihan tambalan",
"enablePatchesSelectionHint": "Jangan mencegah pemilihan atau pembatalan pemilihan tambalan", "enablePatchesSelectionHint": "Jangan mencegah pemilihan atau pembatalan pemilihan tambalan",
"enablePatchesSelectionWarningText": "Mengubah pilihan dari tambalan akan menyebabkan isu tak terduga.\n\nAktifkan saja?", "enablePatchesSelectionWarningText": "Mengubah pilihan dari tambalan akan menyebabkan masalah tak terduga.\n\nAktifkan saja?",
"disablePatchesSelectionWarningText": "Anda akan menonaktifkan pengubahan pilihan tambalan.\nPilihan tambalan default akan dikembalikan.\n\nMenonaktifkan?", "disablePatchesSelectionWarningText": "Anda akan menonaktifkan pengubahan pilihan tambalan.\nPilihan tambalan bawaan akan dikembalikan.\n\nTetap nonaktifkan?",
"autoUpdatePatchesLabel": "Otomatis perbarui tambalan", "autoUpdatePatchesLabel": "Otomatis perbarui tambalan",
"autoUpdatePatchesHint": "Otomatis perbarui tambalan ke versi terkini", "autoUpdatePatchesHint": "Otomatis perbarui tambalan ke versi terbaru",
"showUpdateDialogLabel": "Tampilkan dialog pembaruan", "showUpdateDialogLabel": "Tampilkan dialog pembaruan",
"showUpdateDialogHint": "Tampilkan dialog ketika pembaruan tersedia", "showUpdateDialogHint": "Tampilkan dialog ketika pembaruan tersedia",
"universalPatchesLabel": "Tampilkan tambalan universal", "universalPatchesLabel": "Tampilkan tambalan universal",
"universalPatchesHint": "Menampilkan semua aplikasi dan tambalan universal (dapat memperlambat daftar aplikasi)", "universalPatchesHint": "Tampilkan semua aplikasi dan tambalan universal (dapat memperlambat daftar aplikasi)",
"lastPatchedAppLabel": "Simpan patch aplikasi", "lastPatchedAppLabel": "Simpan aplikasi tertambal",
"lastPatchedAppHint": "Simpan patch terakhir untuk diinstal atau diekspor nanti", "lastPatchedAppHint": "Simpan tambalan terakhir untuk dipasang atau diekspor nanti",
"versionCompatibilityCheckLabel": "Periksa versi kompatibilitas", "versionCompatibilityCheckLabel": "Pemeriksaan kompatibilitas versi",
"versionCompatibilityCheckHint": "Cegah pemilihan tambalan yang tidak kompatibel dengan versi aplikasi yang dipilih", "versionCompatibilityCheckHint": "Cegah pemilihan tambalan yang tidak cocok dengan versi aplikasi yang dipilih",
"requireSuggestedAppVersionLabel": "Memerlukan versi aplikasi yang disarankan", "requireSuggestedAppVersionLabel": "Memerlukan versi aplikasi yang disarankan",
"requireSuggestedAppVersionHint": "Cegah memilih versi aplikasi yang tidak disarankan", "requireSuggestedAppVersionHint": "Cegah memilih versi aplikasi yang tidak disarankan",
"requireSuggestedAppVersionDialogText": "Memilih versi aplikasi yang tidak disarankan dapat menyebabkan masalah yang tidak terduga.\n\nApakah anda ingin melanjutkan?", "requireSuggestedAppVersionDialogText": "Memilih versi aplikasi yang tidak disarankan dapat menyebabkan masalah yang tidak terduga.\n\nApakah anda ingin melanjutkan?",
@@ -198,39 +199,39 @@
"deleteTempDirLabel": "Hapus berkas sementara", "deleteTempDirLabel": "Hapus berkas sementara",
"deleteTempDirHint": "Hapus berkas sementara yang tidak dipakai", "deleteTempDirHint": "Hapus berkas sementara yang tidak dipakai",
"deletedTempDir": "Berkas sementara dihapus", "deletedTempDir": "Berkas sementara dihapus",
"exportPatchesLabel": "Ekspor tambalan pilihan", "exportPatchesLabel": "Ekspor pilihan tambalan",
"exportPatchesHint": "Ekspor tambalan terpilih ke berkas JSON", "exportPatchesHint": "Ekspor pilihan tambalan ke berkas JSON",
"exportedPatches": "Tambalan pilihan diekspor", "exportedPatches": "Tambalan terpilih diekspor",
"noExportFileFound": "Belum pilih tambalan untuk diekspor", "noExportFileFound": "Belum pilih tambalan untuk diekspor",
"importPatchesLabel": "Impor modifikasi terpilih", "importPatchesLabel": "Impor tambalan pilihan",
"importPatchesHint": "Impor tembalan terpilih dari berkas JSON", "importPatchesHint": "Impor tembalan pilihan dari berkas JSON",
"importedPatches": "Tambalan pilihan diimpor", "importedPatches": "Tambalan pilihan diimpor",
"resetStoredPatchesLabel": "Setel ulang tambalan pilihan", "resetStoredPatchesLabel": "Atur ulang tambalan pilihan",
"resetStoredPatchesHint": "Mulai ulang tambalan pilihan yang disimpan", "resetStoredPatchesHint": "Atur ulang tambalan pilihan yang disimpan",
"resetStoredPatchesDialogTitle": "Mulai ulang tambalan pilihan?", "resetStoredPatchesDialogTitle": "Atur ulang tambalan pilihan?",
"resetStoredPatchesDialogText": "Tambalan pilihan bawaan akan dikembalikan.", "resetStoredPatchesDialogText": "Tambalan pilihan bawaan akan dikembalikan.",
"resetStoredPatches": "Tambalan pilihan telah diatur ulang", "resetStoredPatches": "Tambalan pilihan telah diatur ulang",
"resetStoredOptionsLabel": "Setel ulang opsi tambalan", "resetStoredOptionsLabel": "Atur ulang pilihan tambalan",
"resetStoredOptionsHint": "Setel ulang semua opsi tambalan", "resetStoredOptionsHint": "Atur ulang semua pilihan tambalan",
"resetStoredOptionsDialogTitle": "Setel ulang opsi tambalan?", "resetStoredOptionsDialogTitle": "Atur ulang pilihan tambalan?",
"resetStoredOptionsDialogText": "Menyetel ulang opsi tambalan akan menghapus semua opsi yang disimpan.", "resetStoredOptionsDialogText": "Menyetel ulang pilihan tambalan akan menghapus semua pilihan yang disimpan.",
"resetStoredOptions": "Opsi telah diatur ulang", "resetStoredOptions": "Pilihan telah diatur ulang",
"deleteLogsLabel": "Hapus riwayat", "deleteLogsLabel": "Hapus catatan",
"deleteLogsHint": "Hapus log ReVanced Manager terkumpul", "deleteLogsHint": "Hapus log ReVanced Manager yang dikumpulkan",
"deletedLogs": "Log dihapus", "deletedLogs": "Log dihapus",
"regenerateKeystoreLabel": "Menghasilkan penyimpanan kunci", "regenerateKeystoreLabel": "Buat ulang keystore",
"regenerateKeystoreHint": "Buat ulang penyimpanan kunci yang digunakan untuk menandatangani aplikasi", "regenerateKeystoreHint": "Buat ulang keystore yang digunakan untuk menandatangani aplikasi",
"regenerateKeystoreDialogTitle": "Membuat ulang kunci penyimpanan?", "regenerateKeystoreDialogTitle": "Buat ulang keystore?",
"regenerateKeystoreDialogText": "Aplikasi tambalan yang ditandatangani dengan kunci penyimpanan lama tidak dapat diperbarui lagi.", "regenerateKeystoreDialogText": "Aplikasi tambalan yang ditandatangani dengan keystore lama tidak dapat diperbarui lagi.",
"regeneratedKeystore": "Kunci penyimpanan dibuat ulang", "regeneratedKeystore": "Keystore dibuat ulang",
"exportKeystoreLabel": "Ekspor keystore", "exportKeystoreLabel": "Ekspor keystore",
"exportKeystoreHint": "Ekspor kunci penyimpanan yang digunakan untuk menandatangani aplikasi", "exportKeystoreHint": "Ekspor keystore yang digunakan untuk menandatangani aplikasi",
"exportedKeystore": "Keystore diekspor", "exportedKeystore": "Keystore diekspor",
"noKeystoreExportFileFound": "Tidak ada keystore untuk diekspor", "noKeystoreExportFileFound": "Tidak ada keystore untuk diekspor",
"importKeystoreLabel": "Impor keystore", "importKeystoreLabel": "Impor keystore",
"importKeystoreHint": "Impor kunci penyimpanan yang digunakan untuk menandatangani aplikasi", "importKeystoreHint": "Impor keystore yang digunakan untuk menandatangani aplikasi",
"importedKeystore": "Keystore diimpor", "importedKeystore": "Keystore diimpor",
"selectKeystorePassword": "Kata Sandi Keystore", "selectKeystorePassword": "Kata sandi keystore",
"selectKeystorePasswordHint": "Pilih kata sandi keystore yang digunakan untuk menandatangani aplikasi", "selectKeystorePasswordHint": "Pilih kata sandi keystore yang digunakan untuk menandatangani aplikasi",
"jsonSelectorErrorMessage": "Tidak bisa menggunakan berkas JSON tersebut", "jsonSelectorErrorMessage": "Tidak bisa menggunakan berkas JSON tersebut",
"keystoreSelectorErrorMessage": "Tidak bisa menggunakan berkas keystrore tersebut" "keystoreSelectorErrorMessage": "Tidak bisa menggunakan berkas keystrore tersebut"
@@ -240,26 +241,26 @@
"openButton": "Buka", "openButton": "Buka",
"installButton": "Pasang", "installButton": "Pasang",
"uninstallButton": "Copot", "uninstallButton": "Copot",
"unmountButton": "Lepas mount", "unmountButton": "Unmount",
"exportButton": "Ekspor", "exportButton": "Ekspor",
"deleteButton": "Hapus", "deleteButton": "Hapus",
"rootDialogTitle": "Kesalahan", "rootDialogTitle": "Kesalahan",
"lastPatchedAppDescription": "Ini adalah cadangan patch aplikasi terakhir.", "lastPatchedAppDescription": "Ini adalah cadangan dari aplikasi yang terakhir ditambal.",
"unmountDialogText": "Apakah yakin ingin melepas mount aplikasi ini?", "unmountDialogText": "Apakah Anda yakin ingin unmount aplikasi ini?",
"uninstallDialogText": "Apakah yakin ingin mencopot aplikasi ini?", "uninstallDialogText": "Apakah Anda yakin ingin mencopot aplikasi ini?",
"rootDialogText": "Aplikasi dipasang dengan izin superuser, tapi saat ini ReVanced Manager belum diizinkan.\nMohon berikan izin superuser dulu.", "rootDialogText": "Aplikasi dipasang dengan izin superuser, tapi saat ini ReVanced Manager tidak mempunyai izin.\nMohon berikan izin superuser terlebih dahulu.",
"removeAppDialogTitle": "Hapus Aplikasi?", "removeAppDialogTitle": "Hapus aplikasi?",
"removeAppDialogText": "Yakin akan menghapus data backup ini?", "removeAppDialogText": "Apakah Anda yakin ingin menghapus cadangan ini?",
"packageNameLabel": "Nama paket", "packageNameLabel": "Nama paket",
"installTypeLabel": "Tipe pemasangan", "installTypeLabel": "Jenis pemasangan",
"mountTypeLabel": "Mount", "mountTypeLabel": "Mount",
"regularTypeLabel": "Reguler", "regularTypeLabel": "Reguler",
"patchedDateLabel": "Kapan ditambal", "patchedDateLabel": "Tanggal ditambal",
"appliedPatchesLabel": "Tambalan terterap", "appliedPatchesLabel": "Tambalan yang diterapkan",
"sizeLabel": "Ukuran file", "sizeLabel": "Ukuran berkas",
"patchedDateHint": "${date} pukul ${time}", "patchedDateHint": "${date} pada pukul ${time}",
"appliedPatchesHint": "${quantity} tambalan terterap", "appliedPatchesHint": "${quantity} tambalan yang diterapkan",
"updateNotImplemented": "Fitur ini belum diimplementasi" "updateNotImplemented": "Fitur ini belum diterapkan"
}, },
"contributorsView": { "contributorsView": {
"widgetTitle": "Kontributor" "widgetTitle": "Kontributor"
@@ -270,24 +271,24 @@
"mount_missing_installation": "Pemasangan tidak ada", "mount_missing_installation": "Pemasangan tidak ada",
"status_failure_blocked": "Pemasangan diblokir", "status_failure_blocked": "Pemasangan diblokir",
"install_failed_verification_failure": "Verifikasi gagal", "install_failed_verification_failure": "Verifikasi gagal",
"status_failure_invalid": "Pemasangan tidak absah", "status_failure_invalid": "Pemasangan tidak sah",
"install_failed_version_downgrade": "Tak bisa turun versi", "install_failed_version_downgrade": "Tidak dapat menurunkan versi",
"status_failure_conflict": "Pemasangan cekcok", "status_failure_conflict": "Pemasangan berselisih",
"status_failure_storage": "Ruang pemasangan bermasalah", "status_failure_storage": "Ruang pemasangan bermasalah",
"status_failure_incompatible": "Pemasangan tidak kompatibel", "status_failure_incompatible": "Pemasangan tidak cocok",
"status_failure_timeout": "Pemasangan kelamaan", "status_failure_timeout": "Pemasangan kehabisan waktu",
"status_unknown": "Pemasangan gagal", "status_unknown": "Pemasangan gagal",
"mount_version_mismatch_description": "Penginstalan gagal karena aplikasi yang diinstal merupakan versi yang berbeda dari aplikasi yang ditambal.\n\nInstal versi aplikasi yang anda pasang dan coba lagi.", "mount_version_mismatch_description": "Pemasangan gagal dikarenakan aplikasi yang dipasang merupakan versi yang berbeda dari aplikasi yang ditambal.\n\nPasang versi aplikasi yang Anda pasang dan coba lagi.",
"mount_no_root_description": "Pemasangan ini gagal karena akses root belum dizinkan.\n\nIzinkan akses root ke ReVanced Manager dan coba lagi.", "mount_no_root_description": "Pemasangan gagal karena akses root belum dizinkan.\n\nIzinkan akses root ke ReVanced Manager dan coba lagi.",
"mount_missing_installation_description": "Pemasangan gagal karena aplikasi yang belum ditambal tidak terpasang pada perangkat ini supaya dipasang di atasnya.\n\nPasang aplikasi yang belum ditambal sebelum memasang dan coba lagi.", "mount_missing_installation_description": "Pemasangan gagal dikarenakan aplikasi yang belum ditambal tidak terpasang pada perangkat ini supaya dipasang di atasnya.\n\nPasang aplikasi yang belum ditambal sebelum memasang dan coba lagi.",
"status_failure_timeout_description": "Instalasi memakan waktu terlalu lama untuk diselesaikan.\n\nApakah anda ingin mencoba lagi?", "status_failure_timeout_description": "Pemasangan memakan waktu terlalu lama untuk diselesaikan.\n\nApakah Anda ingin mencoba lagi?",
"status_failure_storage_description": "Instalasi gagal karena penyimpanan tidak mencukupi.\n\nKosongkan sebagian ruang dan coba kembali.", "status_failure_storage_description": "Pemasangan gagal karena ruang penyimpanan tidak cukup.\n\nKosongkan sebagian ruang dan coba lagi.",
"status_failure_invalid_description": "Instalasi gagal karena aplikasi yang ditambal tidak valid.\n\nCopot pemasangan aplikasi dan coba lagi?", "status_failure_invalid_description": "Pemasangan gagal karena aplikasi yang ditambal tidak sah.\n\nCopot pemasangan aplikasi dan coba lagi?",
"status_failure_incompatible_description": "Aplikasi tidak kompatibel dengan perangkat ini.\n\nGunakan APK sesuai jenis perangkat dan coba lagi.", "status_failure_incompatible_description": "Aplikasi tidak cocok dengan perangkat ini.\n\nGunakan APK yang didukung perangkat ini dan coba lagi.",
"status_failure_conflict_description": "Penginstalan dicegah oleh aplikasi yang sudah ada.\n\nCopot pemasangan aplikasi yang terpasang dan coba kembali?", "status_failure_conflict_description": "Pemasangan dicegah oleh aplikasi yang sudah ada.\n\nCopot pemasangan aplikasi yang terpasang dan coba lagi?",
"status_failure_blocked_description": "Instalasi diblokir oleh ${packageName}.\n\nSesuaikan pengaturan keamanan anda dan coba kembali.", "status_failure_blocked_description": "Pemasangan diblokir oleh ${packageName}.\n\nSesuaikan pengaturan keamanan Anda dan coba lagi.",
"install_failed_verification_failure_description": "Instalasi gagal karena masalah verifikasi.\n\nSesuaikan pengaturan keamanan anda dan coba kembali.", "install_failed_verification_failure_description": "Instalasi gagal karena masalah verifikasi.\n\nSesuaikan pengaturan keamanan anda dan coba kembali.",
"install_failed_version_downgrade_description": "Pemasangan gagal karena aplikasi tambalan memiliki versi yang lebih rendah daripada aplikasi yang sudah terpasang.\n\nCopot pemasangan aplikasi dan coba kembali?", "install_failed_version_downgrade_description": "Pemasangan gagal karena aplikasi tambalan memiliki versi yang lebih rendah daripada aplikasi yang sudah terpasang.\n\nCopot pemasangan aplikasi dan coba lagi?",
"status_unknown_description": "Instalasi gagal karena alasan yang tidak diketahui. Silakan coba kembali." "status_unknown_description": "Pemasangan gagal karena alasan yang tidak diketahui. Silakan coba lagi."
} }
} }

View File

@@ -51,7 +51,6 @@
"patcherView": { "patcherView": {
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Bót", "patchButton": "Bót",
"removedPatchesWarningDialogText": "Eftirfarandi patches hafa verið fjarlægðir síðan þú notaðir þá síðast.\n\n${patches}\n\n${newPatches}Halda samt áfram?",
"requiredOptionDialogText": "Það þarf að stilla nokkra patch valkosti." "requiredOptionDialogText": "Það þarf að stilla nokkra patch valkosti."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Patch", "patchButton": "Patch",
"incompatibleArchWarningDialogText": "La patch su questa architettura non è ancora supportata e potrebbe fallire. Continuare comunque?", "incompatibleArchWarningDialogText": "La patch su questa architettura non è ancora supportata e potrebbe fallire. Continuare comunque?",
"removedPatchesWarningDialogText": "Le seguenti patch sono state rimosse dall'ultima volta che le hai usate.\n\n${patches}\n\n${newPatches}Continuare comunque?", "removedPatchesWarningDialogText": "Le patch rimosse dall'ultima volta che hai patchato questa app:\n\n${patches}\n\n${newPatches}Continuare comunque?",
"addedPatchesDialogText": "Aggiunte patch dall'ultima volta che hai patchato questa app:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Alcune opzioni di patch devono essere impostate." "requiredOptionDialogText": "Alcune opzioni di patch devono essere impostate."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "パッチャー", "widgetTitle": "パッチャー",
"patchButton": "パッチ", "patchButton": "パッチ",
"incompatibleArchWarningDialogText": "このアーキテクチャへのパッチ適用はまだサポートされておらず、失敗する可能性があります。とにかく続けますか?", "incompatibleArchWarningDialogText": "このアーキテクチャへのパッチ適用はまだサポートされておらず、失敗する可能性があります。とにかく続けますか?",
"removedPatchesWarningDialogText": "以下のパッチはもう使用できません。\n\n${patches}\n\n${newPatches}続行しますか?", "removedPatchesWarningDialogText": "最後にこのアプリにパッチを適用したときからパッチを削除しました:\n\n${patches}\n\n${newPatches}とにかく続けますか",
"addedPatchesDialogText": "前回このアプリにパッチを適用した時以降のパッチを追加しました:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "一部のパッチオプションを設定する必要があります。" "requiredOptionDialogText": "一部のパッチオプションを設定する必要があります。"
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "패치하기", "patchButton": "패치하기",
"incompatibleArchWarningDialogText": "이 아키텍처에 대한 패치는 아직 지원되지 않으므로 실패할 수 있습니다. 그래도 계속하시겠습니까?", "incompatibleArchWarningDialogText": "이 아키텍처에 대한 패치는 아직 지원되지 않으므로 실패할 수 있습니다. 그래도 계속하시겠습니까?",
"removedPatchesWarningDialogText": "최근 적용된 패치들 중 다음 패치가 제거됩니다.\n\n${patches}\n\n${newPatches}그래도 계속하시겠습니까?", "removedPatchesWarningDialogText": "이 앱을 마지막으로 패치한 이후 제거된 패치입니다:\n\n${patches}\n\n${newPatches}그래도 계속하시겠습니까?",
"addedPatchesDialogText": "이 앱을 마지막으로 패치한 이후 추가된 패치입니다:\n\n${addedPatches}",
"requiredOptionDialogText": "일부 패치 옵션을 설정해야 합니다." "requiredOptionDialogText": "일부 패치 옵션을 설정해야 합니다."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -49,8 +49,7 @@
}, },
"patcherView": { "patcherView": {
"widgetTitle": "Pačeris", "widgetTitle": "Pačeris",
"patchButton": "Pačot", "patchButton": "Pačot"
"removedPatchesWarningDialogText": "Kopš pēdējās lietošanas reizes ir noņemti šādi ielāpi.\n\n${patches}\n\n${newPatches}Turpināt jebkurā gadījumā?"
}, },
"appSelectorCard": { "appSelectorCard": {
"widgetTitle": "Izvēlaties lietotni", "widgetTitle": "Izvēlaties lietotni",

View File

@@ -55,6 +55,8 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Oppdatering", "patchButton": "Oppdatering",
"incompatibleArchWarningDialogText": "Patching på denne arkitekturen er ennå ikke støttet og kan mislykkes. Fortsette likevel?", "incompatibleArchWarningDialogText": "Patching på denne arkitekturen er ennå ikke støttet og kan mislykkes. Fortsette likevel?",
"removedPatchesWarningDialogText": "Fjernede oppdateringer siden forrige gang du sendte denne appen:\n\n${patches}\n\n${newPatches}Fortsette likevel?",
"addedPatchesDialogText": "La til korrigeringer siden forrige gang du patchet denne appen:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Noen oppdateringsalternativer må angis." "requiredOptionDialogText": "Noen oppdateringsalternativer må angis."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Patch", "patchButton": "Patch",
"incompatibleArchWarningDialogText": "Patchen op deze architectuur wordt nog niet ondersteund en zal mogelijk mislukken. Toch doorgaan?", "incompatibleArchWarningDialogText": "Patchen op deze architectuur wordt nog niet ondersteund en zal mogelijk mislukken. Toch doorgaan?",
"removedPatchesWarningDialogText": "De volgende patches zijn verwijderd sinds de laatste keer dat je ze hebt gebruikt.\n\n${patches}\n\n${newPatches}Toch doorgaan?", "removedPatchesWarningDialogText": "Patch patches verwijderd sinds de laatste keer dat u deze app heeft aangepast:\n\n${patches}\n\n${newPatches}toch doorgaan?",
"addedPatchesDialogText": "Patch toegevoegd sinds de laatste keer dat u deze app heeft gepatenteerd:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Er moeten enkele patch-opties worden ingesteld." "requiredOptionDialogText": "Er moeten enkele patch-opties worden ingesteld."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Program łatający", "widgetTitle": "Program łatający",
"patchButton": "Popraw", "patchButton": "Popraw",
"incompatibleArchWarningDialogText": "Aktualizowanie na tej architekturze nie jest jeszcze obsługiwane i może się nie powieść. Czy chcesz kontynuować mimo to?", "incompatibleArchWarningDialogText": "Aktualizowanie na tej architekturze nie jest jeszcze obsługiwane i może się nie powieść. Czy chcesz kontynuować mimo to?",
"removedPatchesWarningDialogText": "Następujące łatki zostały usunięte od ostatniego użycia.\n\n${patches}\n\n${newPatches}Kontynuować mimo to?", "removedPatchesWarningDialogText": "Usunięto plastry od ostatniego wprowadzenia aplikacji:\n\n${patches}\n\n${newPatches}Kontynuować?",
"addedPatchesDialogText": "Dodano plastry od ostatniej aktualizacji aplikacji:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Niektóre opcje muszą być ustawione." "requiredOptionDialogText": "Niektóre opcje muszą być ustawione."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,6 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Patch", "patchButton": "Patch",
"incompatibleArchWarningDialogText": "A aplicação de patches nesta arquitetura ainda não é suportada e pode falhar. Continuar mesmo assim?", "incompatibleArchWarningDialogText": "A aplicação de patches nesta arquitetura ainda não é suportada e pode falhar. Continuar mesmo assim?",
"removedPatchesWarningDialogText": "Os seguintes patches foram removidos desde a última vez que você os utilizou:\n\n${patches}\n\n${newPatches}Continuar mesmo assim?",
"requiredOptionDialogText": "Algumas opções de patch tiveram que ser definidas." "requiredOptionDialogText": "Algumas opções de patch tiveram que ser definidas."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Modificador", "widgetTitle": "Modificador",
"patchButton": "Modificar", "patchButton": "Modificar",
"incompatibleArchWarningDialogText": "Patrulhar nesta arquitetura ainda não é suportado e pode falhar. Continuar mesmo assim?", "incompatibleArchWarningDialogText": "Patrulhar nesta arquitetura ainda não é suportado e pode falhar. Continuar mesmo assim?",
"removedPatchesWarningDialogText": "As seguintes modificações foram removidas desde a última vez que as utilizaste.\n\n${patches}\n\n${newPatches}Continuar na mesma?", "removedPatchesWarningDialogText": "Removido correções desde a última vez que você corrigiu este aplicativo:\n\n${patches}\n\n${newPatches}Continuar mesmo assim?",
"addedPatchesDialogText": "Adicionado patches desde a última vez que você corrigiu este aplicativo:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Algumas opções das Modificações precisam ser definidas." "requiredOptionDialogText": "Algumas opções das Modificações precisam ser definidas."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Patch", "patchButton": "Patch",
"incompatibleArchWarningDialogText": "Patcharea după această arhitectură nu este încă suportată și ar putea eșua. Continuați oricum?", "incompatibleArchWarningDialogText": "Patcharea după această arhitectură nu este încă suportată și ar putea eșua. Continuați oricum?",
"removedPatchesWarningDialogText": "Următoarele patch-uri au fost eliminate de la ultima dată când le-ați folosit.\n\n${patches}\n\n${newPatches}Continuați oricum?", "removedPatchesWarningDialogText": "Plasturii eliminați de la ultima dată când ați modificat această aplicație:\n\n${patches}\n\n${newPatches}Continuați oricum?",
"addedPatchesDialogText": "Plasturii adăugați de la ultima dată când ați modificat această aplicație:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Unele opțiuni pentru patch-uri trebuie setate." "requiredOptionDialogText": "Unele opțiuni pentru patch-uri trebuie setate."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Патчер", "widgetTitle": "Патчер",
"patchButton": "Пропатчить", "patchButton": "Пропатчить",
"incompatibleArchWarningDialogText": "Патчинг на этой архитектуре еще не поддерживается и может завершиться неудачей. Продолжить?", "incompatibleArchWarningDialogText": "Патчинг на этой архитектуре еще не поддерживается и может завершиться неудачей. Продолжить?",
"removedPatchesWarningDialogText": "Следующие патчи были удалены с момента их последнего использования.\n\n ${patches}\n\n ${newPatches}Все равно продолжить?", "removedPatchesWarningDialogText": "Удаленные патчи с момента последнего патчинга приложения:\n\n${patches}\n\n${newPatches}Все равно продолжить?",
"addedPatchesDialogText": "Добавленные патчи с момента последнего патчинга приложения:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Некоторые параметры патчей должны быть обязательно установлены." "requiredOptionDialogText": "Некоторые параметры патчей должны быть обязательно установлены."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -44,8 +44,7 @@
}, },
"patcherView": { "patcherView": {
"widgetTitle": "Popravljalnik", "widgetTitle": "Popravljalnik",
"patchButton": "Popravi", "patchButton": "Popravi"
"removedPatchesWarningDialogText": "Spodnji popravki so bili odstranjeni, odkar ste jih nazadnje uporabili.\n\n${patches}\n\n${newPatches}Vseeno nadaljujem?"
}, },
"appSelectorCard": { "appSelectorCard": {
"widgetTitle": "Izberi aplikacijo", "widgetTitle": "Izberi aplikacijo",

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Pečer", "widgetTitle": "Pečer",
"patchButton": "Pečuj", "patchButton": "Pečuj",
"incompatibleArchWarningDialogText": "Pečovanje na ovoj arhitekturi još uvek nije podržano i možda neće uspeti. Ipak nastaviti?", "incompatibleArchWarningDialogText": "Pečovanje na ovoj arhitekturi još uvek nije podržano i možda neće uspeti. Ipak nastaviti?",
"removedPatchesWarningDialogText": "Sledeći pečevi su uklonjeni od poslednjeg puta kada ste ih koristili.\n\n${patches}\n\n${newPatches}Ipak nastaviti?", "removedPatchesWarningDialogText": "Uklonjeni pečevi od poslednjeg puta kada ste pečovali ovu aplikaciju:\n\n${patches}\n\n${newPatches}Ipak nastaviti?",
"addedPatchesDialogText": "Dodati pečevi od poslednjeg puta kada ste pečovali ovu aplikaciju:\n\n${addedPatches}",
"requiredOptionDialogText": "Neke opcije moraju biti izabrane." "requiredOptionDialogText": "Neke opcije moraju biti izabrane."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Печер", "widgetTitle": "Печер",
"patchButton": "Печуј", "patchButton": "Печуј",
"incompatibleArchWarningDialogText": "Печовање на овој архитектури још увек није подржано и можда неће успети. Ипак наставити?", "incompatibleArchWarningDialogText": "Печовање на овој архитектури још увек није подржано и можда неће успети. Ипак наставити?",
"removedPatchesWarningDialogText": "Следећи печеви су уклоњени од последњег пута када сте их користили.\n\n${patches}\n\n${newPatches}Ипак наставити?", "removedPatchesWarningDialogText": "Уклоњени печеви од последњег пута када сте печовали ову апликацију:\n\n${patches}\n\n${newPatches}Ипак наставити?",
"addedPatchesDialogText": "Додати печеви од последњег пута када сте печовали ову апликацију:\n\n${addedPatches}",
"requiredOptionDialogText": "Неке опције морају бити изабране." "requiredOptionDialogText": "Неке опције морају бити изабране."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Patcher", "widgetTitle": "Patcher",
"patchButton": "Patch", "patchButton": "Patch",
"incompatibleArchWarningDialogText": "Patchning av denna arkitektur stöds ännu inte och kan misslyckas. Fortsätt ändå?", "incompatibleArchWarningDialogText": "Patchning av denna arkitektur stöds ännu inte och kan misslyckas. Fortsätt ändå?",
"removedPatchesWarningDialogText": "Följande patchar har tagits bort sedan du senast använde dem.\n\n${patches}\n\n${newPatches}Fortsätt ändå?", "removedPatchesWarningDialogText": "Tog bort patchar sedan du senast patchade denna app:\n\n${patches}\n\n${newPatches}Fortsätt ändå?",
"addedPatchesDialogText": "Lade till patchar sedan du senast patchade denna app:\n\n${addedPatches}\n\n",
"requiredOptionDialogText": "Vissa patchalternativ måste anges." "requiredOptionDialogText": "Vissa patchalternativ måste anges."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,6 @@
"widgetTitle": "இணைப்பான்", "widgetTitle": "இணைப்பான்",
"patchButton": "இணைப்பு", "patchButton": "இணைப்பு",
"incompatibleArchWarningDialogText": "இந்தக் கட்டமைப்பில் பிறழுதல் இன்னும் ஆதரிக்கப்படவில்லை மற்றும் தோல்வியடையக்கூடும். எப்படியும் தொடரவா?", "incompatibleArchWarningDialogText": "இந்தக் கட்டமைப்பில் பிறழுதல் இன்னும் ஆதரிக்கப்படவில்லை மற்றும் தோல்வியடையக்கூடும். எப்படியும் தொடரவா?",
"removedPatchesWarningDialogText": "நீங்கள் கடைசியாகப் பயன்படுத்தியதிலிருந்து பின்வரும் பிறழ்கள் அகற்றப்பட்டன\n\n${patches}\n\n${newPatches}எப்படியும் தொடரவா?",
"requiredOptionDialogText": "சில பிறழ்களுக்கு விருப்பங்களை அமைக்க வேண்டும்." "requiredOptionDialogText": "சில பிறழ்களுக்கு விருப்பங்களை அமைக்க வேண்டும்."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "Yamalayıcı", "widgetTitle": "Yamalayıcı",
"patchButton": "Yamala", "patchButton": "Yamala",
"incompatibleArchWarningDialogText": "Bu mimari cihazlarda yamalama henüz desteklenmiyor ve başarısız olabilir. Yine de devam edilsin mi?", "incompatibleArchWarningDialogText": "Bu mimari cihazlarda yamalama henüz desteklenmiyor ve başarısız olabilir. Yine de devam edilsin mi?",
"removedPatchesWarningDialogText": "Aşağıdaki yamalar son kullanımınızdan sonra kaldırıldı.\n\n${patches}\n\n${newPatches}Yine de devam edilsin mi?", "removedPatchesWarningDialogText": "Bu uygulamayı son yamaladığınızdan beri kaldırılan yamalar:\n\n${patches}\n\n${newPatches}Yine de devam edilsin mi?",
"addedPatchesDialogText": "Bu uygulamayı son yamaladığınızdan beri eklenen yamalar:\n\n${addedPatches}",
"requiredOptionDialogText": "Bazı yama seçeneklerinin ayarlanması gerekiyor." "requiredOptionDialogText": "Bazı yama seçeneklerinin ayarlanması gerekiyor."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -54,8 +54,9 @@
"patcherView": { "patcherView": {
"widgetTitle": "Патчер", "widgetTitle": "Патчер",
"patchButton": "Патчити", "patchButton": "Патчити",
"incompatibleArchWarningDialogText": "Патчінг на цій архітектурі ще не підтримується і може не спрацювати. Продовжити в будь-якому випадку?", "incompatibleArchWarningDialogText": "Патчінг на цій архітектурі ще не підтримується і може не спрацювати. Все одно продовжити?",
"removedPatchesWarningDialogText": "Наступні патчі було видалено з моменту останнього використання.\n\n${patches}\n\n${newPatches}Все одно продовжити?", "removedPatchesWarningDialogText": "Видалені патчі з моменту останнього патчінгу цього застосунку:\n\n${patches}\n\n${newPatches}Все одно продовжити?",
"addedPatchesDialogText": "Додані патчі з моменту останнього патчінгу цього застосунку:\n\n${addedPatches}",
"requiredOptionDialogText": "Потрібно встановити деякі параметри патчу." "requiredOptionDialogText": "Потрібно встановити деякі параметри патчу."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,6 @@
"widgetTitle": "Trình vá", "widgetTitle": "Trình vá",
"patchButton": "Vá", "patchButton": "Vá",
"incompatibleArchWarningDialogText": "Việc vá ứng dụng trên kiến trúc này hiện chưa được hỗ trợ và có thể thất bại. Bạn vẫn muốn tiếp tục?", "incompatibleArchWarningDialogText": "Việc vá ứng dụng trên kiến trúc này hiện chưa được hỗ trợ và có thể thất bại. Bạn vẫn muốn tiếp tục?",
"removedPatchesWarningDialogText": "Những bản vá sau đây đã bị loại bỏ từ lần cuối bạn dùng chúng.\n\n${patches}\n\n${newPatches}Vẫn tiếp tục?",
"requiredOptionDialogText": "Một số tùy chọn bản vá cần được thiết đặt." "requiredOptionDialogText": "Một số tùy chọn bản vá cần được thiết đặt."
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,6 @@
"widgetTitle": "修补器", "widgetTitle": "修补器",
"patchButton": "修补", "patchButton": "修补",
"incompatibleArchWarningDialogText": "对此架构的修补尚不支持或可能失败。仍要继续吗?", "incompatibleArchWarningDialogText": "对此架构的修补尚不支持或可能失败。仍要继续吗?",
"removedPatchesWarningDialogText": "自您上次使用以下补丁以来,它们已被删除。\n\n${patches}\n\n${newPatches}还是继续吗?",
"requiredOptionDialogText": "某些补丁选项必须设置。" "requiredOptionDialogText": "某些补丁选项必须设置。"
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -55,7 +55,8 @@
"widgetTitle": "修補工具", "widgetTitle": "修補工具",
"patchButton": "修補", "patchButton": "修補",
"incompatibleArchWarningDialogText": "此架構尚未支援修補,可能會失敗。仍要繼續嗎?", "incompatibleArchWarningDialogText": "此架構尚未支援修補,可能會失敗。仍要繼續嗎?",
"removedPatchesWarningDialogText": "自您上次使用以來,以下修補檔已遭移除。\n\n${patches} \n\n${newPatches} 仍要繼續執行嗎?", "removedPatchesWarningDialogText": "自您上次修補此應用程式以來移除的修補程式:\n\n${patches}\n\n${newPatches}仍要繼續嗎?",
"addedPatchesDialogText": "自您上次修補此應用程式以來新增的修補程式:\n\n${addedPatches}",
"requiredOptionDialogText": "某些修補檔選項需要進行設定。" "requiredOptionDialogText": "某些修補檔選項需要進行設定。"
}, },
"appSelectorCard": { "appSelectorCard": {

View File

@@ -50,6 +50,7 @@ Learn how to configure ReVanced Manager.
- 🔑 Keystore used to sign patched apps - 🔑 Keystore used to sign patched apps
- 📄 Remembered selection of patches for each app - 📄 Remembered selection of patches for each app
- ⚙️ Remembered patch options - ⚙️ Remembered patch options
- 🛠️ Remembered settings
> Note > Note
> These can be used to backup and restore or reset settings to default in case of issues. > These can be used to backup and restore or reset settings to default in case of issues.

View File

@@ -62,11 +62,12 @@ class Option {
required this.value, required this.value,
required this.values, required this.values,
required this.required, required this.required,
required this.valueType, required this.type,
}); });
factory Option.fromJson(Map<String, dynamic> json) { factory Option.fromJson(Map<String, dynamic> json) {
_migrateV17ToV19(json); _migrateV17ToV19(json);
_migrateV19ToV20(json);
return _$OptionFromJson(json); return _$OptionFromJson(json);
} }
@@ -83,13 +84,25 @@ class Option {
} }
} }
static void _migrateV19ToV20(Map<String, dynamic> json) {
if (json['valueType'] != null) {
final String type = json['valueType'];
json['type'] = type.endsWith('Array')
? 'kotlin.collections.List<kotlin.${type.replaceAll('Array', '')}>'
: 'kotlin.$type';
json['valueType'] = null;
}
}
final String key; final String key;
final String title; final String title;
final String description; final String description;
final dynamic value; final dynamic value;
final Map<String, dynamic>? values; final Map<String, dynamic>? values;
final bool required; final bool required;
final String valueType; final String type;
Map toJson() => _$OptionToJson(this); Map toJson() => _$OptionToJson(this);
} }

View File

@@ -49,18 +49,24 @@ class GithubAPI {
} }
} }
Future<String?> getManagerChangelogs() async { Future<String?> getChangelogs(bool isPatches) async {
final String repoName = isPatches
? _managerAPI.getPatchesRepo()
: _managerAPI.defaultManagerRepo;
try { try {
final response = await _dioGetSynchronously( final response = await _dioGetSynchronously(
'/repos/${_managerAPI.defaultManagerRepo}/releases?per_page=50', '/repos/$repoName/releases?per_page=50',
); );
final buffer = StringBuffer(); final buffer = StringBuffer();
final String currentVersion = final String version = isPatches
await _managerAPI.getCurrentManagerVersion(); ? _managerAPI.getLastUsedPatchesVersion()
: await _managerAPI.getCurrentManagerVersion();
int releases = 0;
for (final release in response.data) { for (final release in response.data) {
if (release['tag_name'] == currentVersion) { if (release['tag_name'] == version) {
if (buffer.isEmpty) { if (buffer.isEmpty) {
buffer.writeln(release['body']); buffer.writeln(release['body']);
releases++;
} }
break; break;
} }
@@ -68,6 +74,10 @@ class GithubAPI {
continue; continue;
} }
buffer.writeln(release['body']); buffer.writeln(release['body']);
releases++;
if (isPatches && releases == 10) {
break;
}
} }
return buffer.toString(); return buffer.toString();
} on Exception catch (e) { } on Exception catch (e) {
@@ -101,11 +111,7 @@ class GithubAPI {
); );
if (asset != null) { if (asset != null) {
final String downloadUrl = asset['browser_download_url']; final String downloadUrl = asset['browser_download_url'];
if (extension == '.apk') { _managerAPI.setPatchesDownloadURL(downloadUrl);
_managerAPI.setIntegrationsDownloadURL(downloadUrl);
} else {
_managerAPI.setPatchesDownloadURL(downloadUrl);
}
return await _downloadManager.getSingleFile( return await _downloadManager.getSingleFile(
downloadUrl, downloadUrl,
); );

View File

@@ -30,6 +30,7 @@ class ManagerAPI {
final String patcherRepo = 'revanced-patcher'; final String patcherRepo = 'revanced-patcher';
final String cliRepo = 'revanced-cli'; final String cliRepo = 'revanced-cli';
late SharedPreferences _prefs; late SharedPreferences _prefs;
Map<String, List>? contributors;
List<Patch> patches = []; List<Patch> patches = [];
List<Option> options = []; List<Option> options = [];
Patch? selectedPatch; Patch? selectedPatch;
@@ -44,15 +45,13 @@ class ManagerAPI {
String keystoreFile = String keystoreFile =
'/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore'; '/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore';
String defaultKeystorePassword = 's3cur3p@ssw0rd'; String defaultKeystorePassword = 's3cur3p@ssw0rd';
String defaultApiUrl = 'https://api.revanced.app/'; String defaultApiUrl = 'https://api.revanced.app/v4';
String defaultRepoUrl = 'https://api.github.com'; String defaultRepoUrl = 'https://api.github.com';
String defaultPatcherRepo = 'revanced/revanced-patcher'; String defaultPatcherRepo = 'revanced/revanced-patcher';
String defaultPatchesRepo = 'revanced/revanced-patches'; String defaultPatchesRepo = 'revanced/revanced-patches';
String defaultIntegrationsRepo = 'revanced/revanced-integrations';
String defaultCliRepo = 'revanced/revanced-cli'; String defaultCliRepo = 'revanced/revanced-cli';
String defaultManagerRepo = 'revanced/revanced-manager'; String defaultManagerRepo = 'revanced/revanced-manager';
String? patchesVersion = ''; String? patchesVersion = '';
String? integrationsVersion = '';
Future<void> initialize() async { Future<void> initialize() async {
_prefs = await SharedPreferences.getInstance(); _prefs = await SharedPreferences.getInstance();
@@ -68,14 +67,23 @@ class ManagerAPI {
releaseBuild = !(await getCurrentManagerVersion()).contains('-dev'); releaseBuild = !(await getCurrentManagerVersion()).contains('-dev');
} }
// Migrate to new API URL if not done yet as the old one is sunset. final hasMigratedToNewMigrationSystem = _prefs.getBool('migratedToNewApiPrefSystem') ?? false;
final bool hasMigratedToNewApi = if (!hasMigratedToNewMigrationSystem) {
_prefs.getBool('migratedToNewApiUrl') ?? false; final apiUrl = getApiUrl().toLowerCase();
if (!hasMigratedToNewApi) {
final String apiUrl = getApiUrl().toLowerCase(); final isReleases = apiUrl.contains('releases.revanced.app');
if (apiUrl.contains('releases.revanced.app')) { final isV2 = apiUrl.contains('api.revanced.app/v2');
await setApiUrl(''); // Reset to default. final isV3 = apiUrl.contains('api.revanced.app/v3');
_prefs.setBool('migratedToNewApiUrl', true);
if (isReleases || isV2 || isV3) {
await resetApiUrl();
// At this point, the preference is removed.
// Now, no more migration is needed because:
// If the user touches the API URL,
// it will be remembered forever as intended.
// On the other hand, if the user resets it or sets it to the default,
// the URL will be updated whenever the app is updated.
_prefs.setBool('migratedToNewApiPrefSystem', true);
} }
} }
@@ -83,10 +91,8 @@ class ManagerAPI {
_prefs.getBool('migratedToAlternativeSource') ?? false; _prefs.getBool('migratedToAlternativeSource') ?? false;
if (!hasMigratedToAlternativeSource) { if (!hasMigratedToAlternativeSource) {
final String patchesRepo = getPatchesRepo(); final String patchesRepo = getPatchesRepo();
final String integrationsRepo = getIntegrationsRepo();
final bool usingAlternativeSources = final bool usingAlternativeSources =
patchesRepo.toLowerCase() != defaultPatchesRepo || patchesRepo.toLowerCase() != defaultPatchesRepo;
integrationsRepo.toLowerCase() != defaultIntegrationsRepo;
_prefs.setBool('useAlternativeSources', usingAlternativeSources); _prefs.setBool('useAlternativeSources', usingAlternativeSources);
_prefs.setBool('migratedToAlternativeSource', true); _prefs.setBool('migratedToAlternativeSource', true);
} }
@@ -101,12 +107,25 @@ class ManagerAPI {
return _prefs.getString('apiUrl') ?? defaultApiUrl; return _prefs.getString('apiUrl') ?? defaultApiUrl;
} }
Future<void> setApiUrl(String url) async { Future<void> resetApiUrl() async {
if (url.isEmpty || url == ' ') { await _prefs.remove('apiUrl');
url = defaultApiUrl;
}
await _revancedAPI.clearAllCache(); await _revancedAPI.clearAllCache();
_toast.showBottom(t.settingsView.restartAppForChanges);
}
Future<void> setApiUrl(String url) async {
url = url.toLowerCase();
if (url == defaultApiUrl) {
return;
}
if (!url.startsWith('http')) {
url = 'https://$url';
}
await _prefs.setString('apiUrl', url); await _prefs.setString('apiUrl', url);
await _revancedAPI.clearAllCache();
_toast.showBottom(t.settingsView.restartAppForChanges); _toast.showBottom(t.settingsView.restartAppForChanges);
} }
@@ -200,14 +219,6 @@ class ManagerAPI {
await _prefs.setStringList('savedPatches-$packageName', patchesJson); await _prefs.setStringList('savedPatches-$packageName', patchesJson);
} }
String getIntegrationsDownloadURL() {
return _prefs.getString('integrationsDownloadURL') ?? '';
}
Future<void> setIntegrationsDownloadURL(String value) async {
await _prefs.setString('integrationsDownloadURL', value);
}
List<Patch> getUsedPatches(String packageName) { List<Patch> getUsedPatches(String packageName) {
final List<String> patchesJson = final List<String> patchesJson =
_prefs.getStringList('usedPatches-$packageName') ?? []; _prefs.getStringList('usedPatches-$packageName') ?? [];
@@ -256,17 +267,6 @@ class ManagerAPI {
_prefs.remove('patchOption-$packageName-$patchName-$key'); _prefs.remove('patchOption-$packageName-$patchName-$key');
} }
String getIntegrationsRepo() {
return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo;
}
Future<void> setIntegrationsRepo(String value) async {
if (value.isEmpty || value.startsWith('/') || value.endsWith('/')) {
value = defaultIntegrationsRepo;
}
await _prefs.setString('integrationsRepo', value);
}
bool getUseDynamicTheme() { bool getUseDynamicTheme() {
return _prefs.getBool('useDynamicTheme') ?? false; return _prefs.getBool('useDynamicTheme') ?? false;
} }
@@ -367,7 +367,8 @@ class ManagerAPI {
) async { ) async {
deleteLastPatchedApp(); deleteLastPatchedApp();
final Directory appCache = await getApplicationSupportDirectory(); final Directory appCache = await getApplicationSupportDirectory();
app.patchedFilePath = outFile.copySync('${appCache.path}/lastPatchedApp.apk').path; app.patchedFilePath =
outFile.copySync('${appCache.path}/lastPatchedApp.apk').path;
app.fileSize = outFile.lengthSync(); app.fileSize = outFile.lengthSync();
await _prefs.setString( await _prefs.setString(
'lastPatchedApp', 'lastPatchedApp',
@@ -426,7 +427,7 @@ class ManagerAPI {
} }
Future<Map<String, List<dynamic>>> getContributors() async { Future<Map<String, List<dynamic>>> getContributors() async {
return await _revancedAPI.getContributors(); return contributors ??= await _revancedAPI.getContributors();
} }
Future<List<Patch>> getPatches() async { Future<List<Patch>> getPatches() async {
@@ -458,33 +459,16 @@ class ManagerAPI {
} }
Future<File?> downloadPatches() async { Future<File?> downloadPatches() async {
if (!isUsingAlternativeSources()) {
return await _revancedAPI.getLatestReleaseFile('patches');
}
try { try {
final String repoName = getPatchesRepo(); final String repoName = getPatchesRepo();
final String currentVersion = await getCurrentPatchesVersion(); final String currentVersion = await getCurrentPatchesVersion();
final String url = getPatchesDownloadURL(); final String url = getPatchesDownloadURL();
return await _githubAPI.getReleaseFile( return await _githubAPI.getReleaseFile(
'.jar', '.rvp',
repoName,
currentVersion,
url,
);
} on Exception catch (e) {
if (kDebugMode) {
print(e);
}
return null;
}
}
Future<File?> downloadIntegrations() async {
try {
final String repoName = !isUsingAlternativeSources()
? defaultIntegrationsRepo
: getIntegrationsRepo();
final String currentVersion = await getCurrentIntegrationsVersion();
final String url = getIntegrationsDownloadURL();
return await _githubAPI.getReleaseFile(
'.apk',
repoName, repoName,
currentVersion, currentVersion,
url, url,
@@ -498,21 +482,14 @@ class ManagerAPI {
} }
Future<File?> downloadManager() async { Future<File?> downloadManager() async {
return await _revancedAPI.getLatestReleaseFile( return await _revancedAPI.getLatestReleaseFile('manager');
'.apk',
defaultManagerRepo,
);
} }
Future<String?> getLatestPatchesReleaseTime() async { Future<String?> getLatestPatchesReleaseTime() async {
if (!isUsingAlternativeSources()) { if (!isUsingAlternativeSources()) {
return await _revancedAPI.getLatestReleaseTime( return await _revancedAPI.getLatestReleaseTime('patches');
'.json',
defaultPatchesRepo,
);
} else { } else {
final release = final release = await _githubAPI.getLatestRelease(getPatchesRepo());
await _githubAPI.getLatestRelease(getPatchesRepo());
if (release != null) { if (release != null) {
final DateTime timestamp = final DateTime timestamp =
DateTime.parse(release['created_at'] as String); DateTime.parse(release['created_at'] as String);
@@ -525,43 +502,23 @@ class ManagerAPI {
Future<String?> getLatestManagerReleaseTime() async { Future<String?> getLatestManagerReleaseTime() async {
return await _revancedAPI.getLatestReleaseTime( return await _revancedAPI.getLatestReleaseTime(
'.apk', 'manager',
defaultManagerRepo,
); );
} }
Future<String?> getLatestManagerVersion() async { Future<String?> getLatestManagerVersion() async {
return await _revancedAPI.getLatestReleaseVersion( return await _revancedAPI.getLatestReleaseVersion(
'.apk', 'manager',
defaultManagerRepo,
); );
} }
Future<String?> getLatestIntegrationsVersion() async {
if (!isUsingAlternativeSources()) {
return await _revancedAPI.getLatestReleaseVersion(
'.apk',
defaultIntegrationsRepo,
);
} else {
final release = await _githubAPI.getLatestRelease(getIntegrationsRepo());
if (release != null) {
return release['tag_name'];
} else {
return null;
}
}
}
Future<String?> getLatestPatchesVersion() async { Future<String?> getLatestPatchesVersion() async {
if (!isUsingAlternativeSources()) { if (!isUsingAlternativeSources()) {
return await _revancedAPI.getLatestReleaseVersion( return await _revancedAPI.getLatestReleaseVersion(
'.json', 'patches',
defaultPatchesRepo,
); );
} else { } else {
final release = final release = await _githubAPI.getLatestRelease(getPatchesRepo());
await _githubAPI.getLatestRelease(getPatchesRepo());
if (release != null) { if (release != null) {
return release['tag_name']; return release['tag_name'];
} else { } else {
@@ -570,6 +527,30 @@ class ManagerAPI {
} }
} }
String getLastUsedPatchesVersion() {
final String lastPatchesVersions =
_prefs.getString('lastUsedPatchesVersion') ?? '{}';
final Map<String, dynamic> lastPatchesVersionMap =
jsonDecode(lastPatchesVersions);
final String repo = getPatchesRepo();
return lastPatchesVersionMap[repo] ?? '0.0.0';
}
void setLastUsedPatchesVersion({String? version}) {
final String lastPatchesVersions =
_prefs.getString('lastUsedPatchesVersion') ?? '{}';
final Map<String, dynamic> lastPatchesVersionMap =
jsonDecode(lastPatchesVersions);
final repo = getPatchesRepo();
final String lastPatchesVersion =
version ?? lastPatchesVersionMap[repo] ?? '0.0.0';
lastPatchesVersionMap[repo] = lastPatchesVersion;
_prefs.setString(
'lastUsedPatchesVersion',
jsonEncode(lastPatchesVersionMap),
);
}
Future<String> getCurrentManagerVersion() async { Future<String> getCurrentManagerVersion() async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform(); final PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version; String version = packageInfo.version;
@@ -597,25 +578,6 @@ class ManagerAPI {
await downloadPatches(); await downloadPatches();
} }
Future<String> getCurrentIntegrationsVersion() async {
integrationsVersion = _prefs.getString('integrationsVersion') ?? '0.0.0';
if (integrationsVersion == '0.0.0' || isPatchesAutoUpdate()) {
final String newIntegrationsVersion =
await getLatestIntegrationsVersion() ?? '0.0.0';
if (integrationsVersion != newIntegrationsVersion &&
newIntegrationsVersion != '0.0.0') {
await setCurrentIntegrationsVersion(newIntegrationsVersion);
}
}
return integrationsVersion!;
}
Future<void> setCurrentIntegrationsVersion(String version) async {
await _prefs.setString('integrationsVersion', version);
await setIntegrationsDownloadURL('');
await downloadIntegrations();
}
Future<List<PatchedApplication>> getAppsToRemove( Future<List<PatchedApplication>> getAppsToRemove(
List<PatchedApplication> patchedApps, List<PatchedApplication> patchedApps,
) async { ) async {
@@ -818,6 +780,36 @@ class ManagerAPI {
return jsonDecode(string); return jsonDecode(string);
} }
String exportSettings() {
final Map<String, dynamic> settings = _prefs
.getKeys()
.fold<Map<String, dynamic>>({}, (Map<String, dynamic> map, String key) {
map[key] = _prefs.get(key);
return map;
});
return jsonEncode(settings);
}
Future<void> importSettings(String settings) async {
final Map<String, dynamic> settingsMap = jsonDecode(settings);
settingsMap.forEach((key, value) {
if (value is bool) {
_prefs.setBool(key, value);
} else if (value is int) {
_prefs.setInt(key, value);
} else if (value is double) {
_prefs.setDouble(key, value);
} else if (value is String) {
_prefs.setString(key, value);
} else if (value is List<dynamic>) {
_prefs.setStringList(
key,
value.map((a) => json.encode(a.toJson())).toList(),
);
}
});
}
void resetAllOptions() { void resetAllOptions() {
_prefs.getKeys().where((key) => key.startsWith('patchOption-')).forEach( _prefs.getKeys().where((key) => key.startsWith('patchOption-')).forEach(
(key) { (key) {

View File

@@ -18,8 +18,7 @@ import 'package:share_plus/share_plus.dart';
@lazySingleton @lazySingleton
class PatcherAPI { class PatcherAPI {
static const patcherChannel = static const patcherChannel = MethodChannel('app.revanced.manager.flutter/patcher');
MethodChannel('app.revanced.manager.flutter/patcher');
final ManagerAPI _managerAPI = locator<ManagerAPI>(); final ManagerAPI _managerAPI = locator<ManagerAPI>();
final RootAPI _rootAPI = RootAPI(); final RootAPI _rootAPI = RootAPI();
late Directory _dataDir; late Directory _dataDir;
@@ -27,13 +26,12 @@ class PatcherAPI {
late File _keyStoreFile; late File _keyStoreFile;
List<Patch> _patches = []; List<Patch> _patches = [];
List<Patch> _universalPatches = []; List<Patch> _universalPatches = [];
List<String> _compatiblePackages = []; Set<String> _compatiblePackages = {};
Map filteredPatches = <String, List<Patch>>{}; Map filteredPatches = <String, List<Patch>>{};
File? outFile; File? outFile;
Future<void> initialize() async { Future<void> initialize() async {
await loadPatches(); await loadPatches();
await _managerAPI.downloadIntegrations();
final Directory appCache = await getApplicationSupportDirectory(); final Directory appCache = await getApplicationSupportDirectory();
_dataDir = await getExternalStorageDirectory() ?? appCache; _dataDir = await getExternalStorageDirectory() ?? appCache;
_tmpDir = Directory('${appCache.path}/patcher'); _tmpDir = Directory('${appCache.path}/patcher');
@@ -47,8 +45,8 @@ class PatcherAPI {
} }
} }
List<String> getCompatiblePackages() { Set<String> getCompatiblePackages() {
final List<String> compatiblePackages = []; final Set<String> compatiblePackages = {};
for (final Patch patch in _patches) { for (final Patch patch in _patches) {
for (final Package package in patch.compatiblePackages) { for (final Package package in patch.compatiblePackages) {
if (!compatiblePackages.contains(package.name)) { if (!compatiblePackages.contains(package.name)) {
@@ -67,16 +65,16 @@ class PatcherAPI {
try { try {
if (_patches.isEmpty) { if (_patches.isEmpty) {
_patches = await _managerAPI.getPatches(); _patches = await _managerAPI.getPatches();
_universalPatches = getUniversalPatches();
_compatiblePackages = getCompatiblePackages();
} }
} on Exception catch (e) { } on Exception catch (e) {
if (kDebugMode) { if (kDebugMode) {
print(e); print(e);
} }
_patches = List.empty(); _patches = List.empty();
} }
_compatiblePackages = getCompatiblePackages();
_universalPatches = getUniversalPatches();
} }
Future<List<ApplicationWithIcon>> getFilteredInstalledApps( Future<List<ApplicationWithIcon>> getFilteredInstalledApps(
@@ -85,6 +83,7 @@ class PatcherAPI {
final List<ApplicationWithIcon> filteredApps = []; final List<ApplicationWithIcon> filteredApps = [];
final bool allAppsIncluded = final bool allAppsIncluded =
_universalPatches.isNotEmpty && showUniversalPatches; _universalPatches.isNotEmpty && showUniversalPatches;
if (allAppsIncluded) { if (allAppsIncluded) {
final appList = await DeviceApps.getInstalledApplications( final appList = await DeviceApps.getInstalledApplications(
includeAppIcons: true, includeAppIcons: true,
@@ -95,6 +94,7 @@ class PatcherAPI {
filteredApps.add(app as ApplicationWithIcon); filteredApps.add(app as ApplicationWithIcon);
} }
} }
for (final packageName in _compatiblePackages) { for (final packageName in _compatiblePackages) {
try { try {
if (!filteredApps.any((app) => app.packageName == packageName)) { if (!filteredApps.any((app) => app.packageName == packageName)) {
@@ -153,7 +153,6 @@ class PatcherAPI {
List<Patch> selectedPatches, List<Patch> selectedPatches,
bool isFromStorage, bool isFromStorage,
) async { ) async {
final File? integrationsFile = await _managerAPI.downloadIntegrations();
final Map<String, Map<String, dynamic>> options = {}; final Map<String, Map<String, dynamic>> options = {};
for (final patch in selectedPatches) { for (final patch in selectedPatches) {
if (patch.options.isNotEmpty) { if (patch.options.isNotEmpty) {
@@ -169,44 +168,41 @@ class PatcherAPI {
} }
} }
if (integrationsFile != null) { _dataDir.createSync();
_dataDir.createSync(); _tmpDir.createSync();
_tmpDir.createSync(); final Directory workDir = await _tmpDir.createTemp('tmp-');
final Directory workDir = await _tmpDir.createTemp('tmp-');
final File inApkFile = File('${workDir.path}/in.apk'); final File inApkFile = File('${workDir.path}/in.apk');
await File(apkFilePath).copy(inApkFile.path); await File(apkFilePath).copy(inApkFile.path);
if (isFromStorage) { if (isFromStorage) {
// The selected apk was copied to cacheDir by the file picker, so it's not needed anymore. // The selected apk was copied to cacheDir by the file picker, so it's not needed anymore.
// rename() can't be used here, as Android system also counts the size of files moved out from cacheDir // rename() can't be used here, as Android system also counts the size of files moved out from cacheDir
// as part of the app's cache size. // as part of the app's cache size.
File(apkFilePath).delete(); File(apkFilePath).delete();
} }
outFile = File('${workDir.path}/out.apk'); outFile = File('${workDir.path}/out.apk');
final Directory tmpDir = final Directory tmpDir =
Directory('${workDir.path}/revanced-temporary-files'); Directory('${workDir.path}/revanced-temporary-files');
try { try {
await patcherChannel.invokeMethod( await patcherChannel.invokeMethod(
'runPatcher', 'runPatcher',
{ {
'inFilePath': inApkFile.path, 'inFilePath': inApkFile.path,
'outFilePath': outFile!.path, 'outFilePath': outFile!.path,
'integrationsPath': integrationsFile.path, 'selectedPatches': selectedPatches.map((p) => p.name).toList(),
'selectedPatches': selectedPatches.map((p) => p.name).toList(), 'options': options,
'options': options, 'tmpDirPath': tmpDir.path,
'tmpDirPath': tmpDir.path, 'keyStoreFilePath': _keyStoreFile.path,
'keyStoreFilePath': _keyStoreFile.path, 'keystorePassword': _managerAPI.getKeystorePassword(),
'keystorePassword': _managerAPI.getKeystorePassword(), },
}, );
); } on Exception catch (e) {
} on Exception catch (e) { if (kDebugMode) {
if (kDebugMode) { print(e);
print(e);
}
} }
} }
} }

View File

@@ -1,7 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:collection/collection.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart';
@@ -31,7 +29,7 @@ class RevancedAPI {
final Map<String, List<dynamic>> contributors = {}; final Map<String, List<dynamic>> contributors = {};
try { try {
final response = await _dio.get('/contributors'); final response = await _dio.get('/contributors');
final List<dynamic> repositories = response.data['repositories']; final List<dynamic> repositories = response.data;
for (final Map<String, dynamic> repo in repositories) { for (final Map<String, dynamic> repo in repositories) {
final String name = repo['name']; final String name = repo['name'];
contributors[name] = repo['contributors']; contributors[name] = repo['contributors'];
@@ -46,21 +44,15 @@ class RevancedAPI {
} }
Future<Map<String, dynamic>?> _getLatestRelease( Future<Map<String, dynamic>?> _getLatestRelease(
String extension, String toolName,
String repoName,
) { ) {
if (!locator<ManagerAPI>().getDownloadConsent()) { if (!locator<ManagerAPI>().getDownloadConsent()) {
return Future(() => null); return Future(() => null);
} }
return getToolsLock.synchronized(() async { return getToolsLock.synchronized(() async {
try { try {
final response = await _dio.get('/tools'); final response = await _dio.get('/$toolName');
final List<dynamic> tools = response.data['tools']; return response.data;
return tools.firstWhereOrNull(
(t) =>
(t['repository'] as String) == repoName &&
(t['name'] as String).endsWith(extension),
);
} on Exception catch (e) { } on Exception catch (e) {
if (kDebugMode) { if (kDebugMode) {
print(e); print(e);
@@ -71,13 +63,11 @@ class RevancedAPI {
} }
Future<String?> getLatestReleaseVersion( Future<String?> getLatestReleaseVersion(
String extension, String toolName,
String repoName,
) async { ) async {
try { try {
final Map<String, dynamic>? release = await _getLatestRelease( final Map<String, dynamic>? release = await _getLatestRelease(
extension, toolName,
repoName,
); );
if (release != null) { if (release != null) {
return release['version']; return release['version'];
@@ -92,16 +82,14 @@ class RevancedAPI {
} }
Future<File?> getLatestReleaseFile( Future<File?> getLatestReleaseFile(
String extension, String toolName,
String repoName,
) async { ) async {
try { try {
final Map<String, dynamic>? release = await _getLatestRelease( final Map<String, dynamic>? release = await _getLatestRelease(
extension, toolName,
repoName,
); );
if (release != null) { if (release != null) {
final String url = release['browser_download_url']; final String url = release['download_url'];
return await _downloadManager.getSingleFile(url); return await _downloadManager.getSingleFile(url);
} }
} on Exception catch (e) { } on Exception catch (e) {
@@ -129,13 +117,10 @@ class RevancedAPI {
} }
Future<File?> downloadManager() async { Future<File?> downloadManager() async {
final Map<String, dynamic>? release = await _getLatestRelease( final Map<String, dynamic>? release = await _getLatestRelease('manager');
'.apk',
'revanced/revanced-manager',
);
File? outputFile; File? outputFile;
await for (final result in _downloadManager.getFileStream( await for (final result in _downloadManager.getFileStream(
release!['browser_download_url'] as String, release!['download_url'] as String,
)) { )) {
if (result is DownloadProgress) { if (result is DownloadProgress) {
final totalSize = result.totalSize ?? 10000000; final totalSize = result.totalSize ?? 10000000;
@@ -152,17 +137,15 @@ class RevancedAPI {
} }
Future<String?> getLatestReleaseTime( Future<String?> getLatestReleaseTime(
String extension, String toolName,
String repoName,
) async { ) async {
try { try {
final Map<String, dynamic>? release = await _getLatestRelease( final Map<String, dynamic>? release = await _getLatestRelease(
extension, toolName,
repoName,
); );
if (release != null) { if (release != null) {
final DateTime timestamp = final DateTime timestamp =
DateTime.parse(release['timestamp'] as String); DateTime.parse(release['created_at'] as String);
return format(timestamp, locale: 'en_short'); return format(timestamp, locale: 'en_short');
} }
} on Exception catch (e) { } on Exception catch (e) {

View File

@@ -30,30 +30,13 @@ class ContributorsView extends StatelessWidget {
sliver: SliverList( sliver: SliverList(
delegate: SliverChildListDelegate.fixed( delegate: SliverChildListDelegate.fixed(
<Widget>[ <Widget>[
ContributorsCard( for (final String tool in model.contributors.keys) ...[
title: 'ReVanced Patcher', ContributorsCard(
contributors: model.patcherContributors, title: tool,
), contributors: model.contributors[tool]!,
const SizedBox(height: 20), ),
ContributorsCard( const SizedBox(height: 20),
title: 'ReVanced Patches', ],
contributors: model.patchesContributors,
),
const SizedBox(height: 20),
ContributorsCard(
title: 'ReVanced Integrations',
contributors: model.integrationsContributors,
),
const SizedBox(height: 20),
ContributorsCard(
title: 'ReVanced CLI',
contributors: model.cliContributors,
),
const SizedBox(height: 20),
ContributorsCard(
title: 'ReVanced Manager',
contributors: model.managerContributors,
),
SizedBox(height: MediaQuery.viewPaddingOf(context).bottom), SizedBox(height: MediaQuery.viewPaddingOf(context).bottom),
], ],
), ),

View File

@@ -4,21 +4,10 @@ import 'package:stacked/stacked.dart';
class ContributorsViewModel extends BaseViewModel { class ContributorsViewModel extends BaseViewModel {
final ManagerAPI _managerAPI = locator<ManagerAPI>(); final ManagerAPI _managerAPI = locator<ManagerAPI>();
List<dynamic> patcherContributors = []; Map<String, List<dynamic>> contributors = {};
List<dynamic> patchesContributors = [];
List<dynamic> integrationsContributors = [];
List<dynamic> cliContributors = [];
List<dynamic> managerContributors = [];
Future<void> getContributors() async { Future<void> getContributors() async {
final Map<String, List<dynamic>> contributors = contributors = await _managerAPI.getContributors();
await _managerAPI.getContributors();
patcherContributors = contributors[_managerAPI.defaultPatcherRepo] ?? [];
patchesContributors = contributors[_managerAPI.defaultPatchesRepo] ?? [];
integrationsContributors =
contributors[_managerAPI.defaultIntegrationsRepo] ?? [];
cliContributors = contributors[_managerAPI.defaultCliRepo] ?? [];
managerContributors = contributors[_managerAPI.defaultManagerRepo] ?? [];
notifyListeners(); notifyListeners();
} }
} }

View File

@@ -311,11 +311,8 @@ class HomeViewModel extends BaseViewModel {
_toast.showBottom(t.homeView.downloadingMessage); _toast.showBottom(t.homeView.downloadingMessage);
final String patchesVersion = final String patchesVersion =
await _managerAPI.getLatestPatchesVersion() ?? '0.0.0'; await _managerAPI.getLatestPatchesVersion() ?? '0.0.0';
final String integrationsVersion = if (patchesVersion != '0.0.0') {
await _managerAPI.getLatestIntegrationsVersion() ?? '0.0.0';
if (patchesVersion != '0.0.0' && integrationsVersion != '0.0.0') {
await _managerAPI.setCurrentPatchesVersion(patchesVersion); await _managerAPI.setCurrentPatchesVersion(patchesVersion);
await _managerAPI.setCurrentIntegrationsVersion(integrationsVersion);
_toast.showBottom(t.homeView.downloadedMessage); _toast.showBottom(t.homeView.downloadedMessage);
forceRefresh(context); forceRefresh(context);
} else { } else {
@@ -478,14 +475,8 @@ class HomeViewModel extends BaseViewModel {
); );
} }
Future<String?> getManagerChangelogs() { Future<String?> getChangelogs(bool isPatches) {
return _githubAPI.getManagerChangelogs(); return _githubAPI.getChangelogs(isPatches);
}
Future<String?> getLatestPatchesChangelog() async {
final release =
await _githubAPI.getLatestRelease(_managerAPI.getPatchesRepo());
return release?['body'];
} }
Future<String?> getLatestPatchesReleaseTime() { Future<String?> getLatestPatchesReleaseTime() {

View File

@@ -159,6 +159,9 @@ class InstallerViewModel extends BaseViewModel {
_app.packageName, _app.packageName,
); );
await _managerAPI.setUsedPatches(_patches, _app.packageName); await _managerAPI.setUsedPatches(_patches, _app.packageName);
_managerAPI.setLastUsedPatchesVersion(
version: _managerAPI.patchesVersion,
);
} else if (value == -100.0) { } else if (value == -100.0) {
isPatching = false; isPatching = false;
hasErrors = true; hasErrors = true;
@@ -197,7 +200,9 @@ class InstallerViewModel extends BaseViewModel {
_app.patchedFilePath = _patcherAPI.outFile!.path; _app.patchedFilePath = _patcherAPI.outFile!.path;
} }
final homeViewModel = locator<HomeViewModel>(); final homeViewModel = locator<HomeViewModel>();
_managerAPI.reAssessPatchedApps().then((_) => homeViewModel.getPatchedApps()); _managerAPI
.reAssessPatchedApps()
.then((_) => homeViewModel.getPatchedApps());
} on Exception catch (e) { } on Exception catch (e) {
update( update(
-100.0, -100.0,
@@ -325,7 +330,6 @@ class InstallerViewModel extends BaseViewModel {
'Version compatibility check: ${_managerAPI.isVersionCompatibilityCheckEnabled()}', 'Version compatibility check: ${_managerAPI.isVersionCompatibilityCheckEnabled()}',
'Show universal patches: ${_managerAPI.areUniversalPatchesEnabled()}', 'Show universal patches: ${_managerAPI.areUniversalPatchesEnabled()}',
'Patches source: ${_managerAPI.getPatchesRepo()}', 'Patches source: ${_managerAPI.getPatchesRepo()}',
'Integration source: ${_managerAPI.getIntegrationsRepo()}', //
'\n- Logs', '\n- Logs',
logsTrimmed.join('\n'), logsTrimmed.join('\n'),

View File

@@ -44,20 +44,20 @@ class PatchOptionsView extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
for (final Option option in model.modifiedOptions) for (final Option option in model.modifiedOptions)
if (option.valueType == 'String' || if (option.type == 'kotlin.String' ||
option.valueType == 'Int') option.type == 'kotlin.Int')
IntAndStringPatchOption( IntAndStringPatchOption(
patchOption: option, patchOption: option,
model: model, model: model,
) )
else if (option.valueType == 'Boolean') else if (option.type == 'kotlin.Boolean')
BooleanPatchOption( BooleanPatchOption(
patchOption: option, patchOption: option,
model: model, model: model,
) )
else if (option.valueType == 'StringArray' || else if (option.type == 'kotlin.collections.List<kotlin.String>' ||
option.valueType == 'IntArray' || option.type == 'kotlin.collections.List<kotlin.Int>' ||
option.valueType == 'LongArray') option.type == 'kotlin.collections.List<kotlin.Long>')
IntStringLongListPatchOption( IntStringLongListPatchOption(
patchOption: option, patchOption: option,
model: model, model: model,

View File

@@ -74,7 +74,7 @@ class PatchOptionsViewModel extends BaseViewModel {
title: option.title, title: option.title,
description: option.description, description: option.description,
values: option.values, values: option.values,
valueType: option.valueType, type: option.type,
value: value, value: value,
required: option.required, required: option.required,
key: option.key, key: option.key,
@@ -90,7 +90,7 @@ class PatchOptionsViewModel extends BaseViewModel {
title: option.title, title: option.title,
description: option.description, description: option.description,
values: option.values, values: option.values,
valueType: option.valueType, type: option.type,
value: option.value is List ? option.value.toList() : option.value, value: option.value is List ? option.value.toList() : option.value,
required: option.required, required: option.required,
key: option.key, key: option.key,

View File

@@ -13,8 +13,9 @@ class SManageApiUrl extends BaseViewModel {
final TextEditingController _apiUrlController = TextEditingController(); final TextEditingController _apiUrlController = TextEditingController();
Future<void> showApiUrlDialog(BuildContext context) async { Future<void> showApiUrlDialog(BuildContext context) async {
final String apiUrl = _managerAPI.getApiUrl(); final apiUrl = _managerAPI.getApiUrl();
_apiUrlController.text = apiUrl.replaceAll('https://', '');
_apiUrlController.text = apiUrl;
return showDialog( return showDialog(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
@@ -60,11 +61,7 @@ class SManageApiUrl extends BaseViewModel {
), ),
FilledButton( FilledButton(
onPressed: () { onPressed: () {
String apiUrl = _apiUrlController.text; _managerAPI.setApiUrl(_apiUrlController.text);
if (!apiUrl.startsWith('https')) {
apiUrl = 'https://$apiUrl';
}
_managerAPI.setApiUrl(apiUrl);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: Text(t.okButton), child: Text(t.okButton),
@@ -87,7 +84,7 @@ class SManageApiUrl extends BaseViewModel {
), ),
FilledButton( FilledButton(
onPressed: () { onPressed: () {
_managerAPI.setApiUrl(''); _managerAPI.resetApiUrl();
Navigator.of(context) Navigator.of(context)
..pop() ..pop()
..pop(); ..pop();

View File

@@ -14,16 +14,11 @@ class SManageSources extends BaseViewModel {
final TextEditingController _orgPatSourceController = TextEditingController(); final TextEditingController _orgPatSourceController = TextEditingController();
final TextEditingController _patSourceController = TextEditingController(); final TextEditingController _patSourceController = TextEditingController();
final TextEditingController _orgIntSourceController = TextEditingController();
final TextEditingController _intSourceController = TextEditingController();
Future<void> showSourcesDialog(BuildContext context) async { Future<void> showSourcesDialog(BuildContext context) async {
final String patchesRepo = _managerAPI.getPatchesRepo(); final String patchesRepo = _managerAPI.getPatchesRepo();
final String integrationsRepo = _managerAPI.getIntegrationsRepo();
_orgPatSourceController.text = patchesRepo.split('/')[0]; _orgPatSourceController.text = patchesRepo.split('/')[0];
_patSourceController.text = patchesRepo.split('/')[1]; _patSourceController.text = patchesRepo.split('/')[1];
_orgIntSourceController.text = integrationsRepo.split('/')[0];
_intSourceController.text = integrationsRepo.split('/')[1];
return showDialog( return showDialog(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
@@ -72,38 +67,6 @@ class SManageSources extends BaseViewModel {
hintText: patchesRepo.split('/')[1], hintText: patchesRepo.split('/')[1],
), ),
), ),
const SizedBox(height: 8),
// Integrations owner's name
TextField(
controller: _orgIntSourceController,
autocorrect: false,
onChanged: (value) => notifyListeners(),
decoration: InputDecoration(
icon: Icon(
Icons.merge_outlined,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
border: const OutlineInputBorder(),
labelText: t.settingsView.orgIntegrationsLabel,
hintText: integrationsRepo.split('/')[0],
),
),
const SizedBox(height: 8),
// Integrations repository's name
TextField(
controller: _intSourceController,
autocorrect: false,
onChanged: (value) => notifyListeners(),
decoration: InputDecoration(
icon: const Icon(
Icons.merge_outlined,
color: Colors.transparent,
),
border: const OutlineInputBorder(),
labelText: t.settingsView.sourcesIntegrationsLabel,
hintText: integrationsRepo.split('/')[1],
),
),
const SizedBox(height: 20), const SizedBox(height: 20),
Text(t.settingsView.sourcesUpdateNote), Text(t.settingsView.sourcesUpdateNote),
], ],
@@ -113,8 +76,6 @@ class SManageSources extends BaseViewModel {
onPressed: () { onPressed: () {
_orgPatSourceController.clear(); _orgPatSourceController.clear();
_patSourceController.clear(); _patSourceController.clear();
_orgIntSourceController.clear();
_intSourceController.clear();
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: Text(t.cancelButton), child: Text(t.cancelButton),
@@ -124,11 +85,8 @@ class SManageSources extends BaseViewModel {
_managerAPI.setPatchesRepo( _managerAPI.setPatchesRepo(
'${_orgPatSourceController.text.trim()}/${_patSourceController.text.trim()}', '${_orgPatSourceController.text.trim()}/${_patSourceController.text.trim()}',
); );
_managerAPI.setIntegrationsRepo(
'${_orgIntSourceController.text.trim()}/${_intSourceController.text.trim()}',
);
_managerAPI.setCurrentPatchesVersion('0.0.0'); _managerAPI.setCurrentPatchesVersion('0.0.0');
_managerAPI.setCurrentIntegrationsVersion('0.0.0'); _managerAPI.setLastUsedPatchesVersion();
_toast.showBottom(t.settingsView.restartAppForChanges); _toast.showBottom(t.settingsView.restartAppForChanges);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@@ -153,9 +111,7 @@ class SManageSources extends BaseViewModel {
FilledButton( FilledButton(
onPressed: () { onPressed: () {
_managerAPI.setPatchesRepo(''); _managerAPI.setPatchesRepo('');
_managerAPI.setIntegrationsRepo('');
_managerAPI.setCurrentPatchesVersion('0.0.0'); _managerAPI.setCurrentPatchesVersion('0.0.0');
_managerAPI.setCurrentIntegrationsVersion('0.0.0');
_toast.showBottom(t.settingsView.restartAppForChanges); _toast.showBottom(t.settingsView.restartAppForChanges);
Navigator.of(context) Navigator.of(context)
..pop() ..pop()

View File

@@ -56,7 +56,7 @@ class SettingsViewModel extends BaseViewModel {
void useAlternativeSources(bool value) { void useAlternativeSources(bool value) {
_managerAPI.useAlternativeSources(value); _managerAPI.useAlternativeSources(value);
_managerAPI.setCurrentPatchesVersion('0.0.0'); _managerAPI.setCurrentPatchesVersion('0.0.0');
_managerAPI.setCurrentIntegrationsVersion('0.0.0'); _managerAPI.setLastUsedPatchesVersion();
notifyListeners(); notifyListeners();
} }
@@ -222,6 +222,53 @@ class SettingsViewModel extends BaseViewModel {
notifyListeners(); notifyListeners();
} }
Future<void> exportSettings() async {
try {
final String settings = _managerAPI.exportSettings();
final Directory tempDir = await getTemporaryDirectory();
final String filePath = '${tempDir.path}/manager_settings.json';
final File file = File(filePath);
await file.writeAsString(settings);
final String? result = await FlutterFileDialog.saveFile(
params: SaveFileDialogParams(
sourceFilePath: file.path,
fileName: 'manager_settings.json',
mimeTypesFilter: ['application/json'],
),
);
if (result != null) {
_toast.showBottom(t.settingsView.exportedSettings);
}
} on Exception catch (e) {
if (kDebugMode) {
print(e);
}
}
}
Future<void> importSettings() async {
try {
final String? result = await FlutterFileDialog.pickFile(
params: const OpenFileDialogParams(
fileExtensionsFilter: ['json'],
),
);
if (result != null) {
final File inFile = File(result);
final String settings = inFile.readAsStringSync();
inFile.delete();
_managerAPI.importSettings(settings);
_toast.showBottom(t.settingsView.importedSettings);
_toast.showBottom(t.settingsView.restartAppForChanges);
}
} on Exception catch (e) {
if (kDebugMode) {
print(e);
}
_toast.showBottom(t.settingsView.jsonSelectorErrorMessage);
}
}
Future<void> exportPatches() async { Future<void> exportPatches() async {
try { try {
final File outFile = File(_managerAPI.storedPatchesFile); final File outFile = File(_managerAPI.storedPatchesFile);

View File

@@ -49,7 +49,7 @@ class _ContributorsCardState extends State<ContributorsCard> {
child: GestureDetector( child: GestureDetector(
onTap: () => launchUrl( onTap: () => launchUrl(
Uri.parse( Uri.parse(
widget.contributors[index]['html_url'], widget.contributors[index]['url'],
), ),
mode: LaunchMode.externalApplication, mode: LaunchMode.externalApplication,
), ),

View File

@@ -105,9 +105,7 @@ class UpdateConfirmationSheet extends StatelessWidget {
), ),
), ),
FutureBuilder<String?>( FutureBuilder<String?>(
future: !isPatches future: model.getChangelogs(isPatches),
? model.getManagerChangelogs()
: model.getLatestPatchesChangelog(),
builder: (_, snapshot) { builder: (_, snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {
return Padding( return Padding(
@@ -117,7 +115,6 @@ class UpdateConfirmationSheet extends StatelessWidget {
), ),
); );
} }
return Container( return Container(
margin: const EdgeInsets.symmetric(horizontal: 24.0), margin: const EdgeInsets.symmetric(horizontal: 24.0),
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@@ -138,7 +138,7 @@ class IntStringLongListPatchOption extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<dynamic> values = List.from(patchOption.value ?? []); final List<dynamic> values = List.from(patchOption.value ?? []);
final ValueNotifier patchOptionValue = ValueNotifier(values); final ValueNotifier patchOptionValue = ValueNotifier(values);
final String type = patchOption.valueType; final String type = patchOption.type;
String getKey(dynamic value) { String getKey(dynamic value) {
if (value != null && patchOption.values != null) { if (value != null && patchOption.values != null) {
@@ -408,12 +408,12 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final bool isStringOption = widget.patchOption.valueType.contains('String'); final bool isStringOption = widget.patchOption.type.contains('String');
final bool isArrayOption = widget.patchOption.valueType.contains('Array'); final bool isListOption = widget.patchOption.type.contains('List');
selectedKey = selectedKey == '' ? selectedKey : widget.selectedKey; selectedKey = selectedKey == '' ? selectedKey : widget.selectedKey;
final bool isValueArray = widget.value?.startsWith('[') ?? false; final bool isValueArray = widget.value?.startsWith('[') ?? false;
final bool shouldResetValue = final bool shouldResetValue =
!isStringOption && isArrayOption && selectedKey == '' && isValueArray; !isStringOption && isListOption && selectedKey == '' && isValueArray;
controller.text = shouldResetValue ? '' : widget.value ?? ''; controller.text = shouldResetValue ? '' : widget.value ?? '';
defaultValue ??= controller.text; defaultValue ??= controller.text;
return Column( return Column(
@@ -479,7 +479,7 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
} else { } else {
controller.text = widget.patchOption.values![value].toString(); controller.text = widget.patchOption.values![value].toString();
widget.onChanged( widget.onChanged(
isArrayOption isListOption
? widget.patchOption.values![value] ? widget.patchOption.values![value]
: controller.text, : controller.text,
); );
@@ -492,9 +492,9 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
if (selectedKey == '') if (selectedKey == '')
TextFormField( TextFormField(
inputFormatters: [ inputFormatters: [
if (widget.patchOption.valueType.contains('Int')) if (widget.patchOption.type.contains('Int'))
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')), FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
if (widget.patchOption.valueType.contains('Long')) if (widget.patchOption.type.contains('Long'))
FilteringTextInputFormatter.allow(RegExp(r'^[0-9]*\.?[0-9]*')), FilteringTextInputFormatter.allow(RegExp(r'^[0-9]*\.?[0-9]*')),
], ],
controller: controller, controller: controller,
@@ -505,7 +505,7 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
tooltip: t.patchOptionsView.tooltip, tooltip: t.patchOptionsView.tooltip,
itemBuilder: (BuildContext context) { itemBuilder: (BuildContext context) {
return [ return [
if (isArrayOption) if (isListOption)
PopupMenuItem( PopupMenuItem(
value: 'remove', value: 'remove',
child: Text(t.remove), child: Text(t.remove),

View File

@@ -14,6 +14,30 @@ class SExportSection extends StatelessWidget {
return SettingsSection( return SettingsSection(
title: t.settingsView.exportSectionTitle, title: t.settingsView.exportSectionTitle,
children: <Widget>[ children: <Widget>[
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: Text(
t.settingsView.exportSettingsLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: Text(t.settingsView.exportSettingsHint),
onTap: () => _settingsViewModel.exportSettings(),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: Text(
t.settingsView.importSettingsLabel,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
subtitle: Text(t.settingsView.importSettingsHint),
onTap: () => _settingsViewModel.importSettings(),
),
ListTile( ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0), contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: Text( title: Text(
@@ -114,7 +138,6 @@ class SExportSection extends StatelessWidget {
subtitle: Text(t.settingsView.regenerateKeystoreHint), subtitle: Text(t.settingsView.regenerateKeystoreHint),
onTap: () => _showDeleteKeystoreDialog(context), onTap: () => _showDeleteKeystoreDialog(context),
), ),
// SManageKeystorePasswordUI(),
], ],
); );
} }

View File

@@ -33,7 +33,7 @@ bool hasUnsupportedRequiredOption(List<Option> options, Patch patch) {
option.key, option.key,
) == ) ==
null) { null) {
requiredOptionsType.add(option.valueType); requiredOptionsType.add(option.type);
} }
} }
for (final String optionType in requiredOptionsType) { for (final String optionType in requiredOptionsType) {

629
package-lock.json generated
View File

@@ -10,7 +10,8 @@
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^6.0.3", "@semantic-release/exec": "^6.0.3",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"semantic-release": "^23.0.8" "semantic-release": "^24.1.3",
"semantic-release-pub": "^0.8.29"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
@@ -169,12 +170,12 @@
"dev": true "dev": true
}, },
"node_modules/@octokit/plugin-paginate-rest": { "node_modules/@octokit/plugin-paginate-rest": {
"version": "11.3.0", "version": "11.3.5",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.5.tgz",
"integrity": "sha512-n4znWfRinnUQF6TPyxs7EctSAA3yVSP4qlJP2YgI3g9d4Ae2n5F3XDOjbUluKRxPU3rfsgpOboI4O4VtPc6Ilg==", "integrity": "sha512-cgwIRtKrpwhLoBi0CUNuY83DPGRMaWVjqVI/bGKsLJ4PzyWZNaEmhHroI2xlrVXkk6nFv0IsZpOp+ZWSWUS2AQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/types": "^13.5.0" "@octokit/types": "^13.6.0"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 18"
@@ -184,9 +185,9 @@
} }
}, },
"node_modules/@octokit/plugin-retry": { "node_modules/@octokit/plugin-retry": {
"version": "7.1.1", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.1.2.tgz",
"integrity": "sha512-G9Ue+x2odcb8E1XIPhaFBnTTIrrUDfXN05iFXiqhR+SeeeDMMILcAnysOsxUpEWcQp2e5Ft397FCXTcPkiPkLw==", "integrity": "sha512-XOWnPpH2kJ5VTwozsxGurw+svB2e61aWlmk5EVIYZPwFK5F9h4cyPyj9CIKRyMXMHSwpIsI3mPOdpMmrRhe7UQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/request-error": "^6.0.0", "@octokit/request-error": "^6.0.0",
@@ -201,9 +202,9 @@
} }
}, },
"node_modules/@octokit/plugin-throttling": { "node_modules/@octokit/plugin-throttling": {
"version": "9.3.0", "version": "9.3.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.3.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.3.2.tgz",
"integrity": "sha512-B5YTToSRTzNSeEyssnrT7WwGhpIdbpV9NKIs3KyTWHX6PhpYn7gqF/+lL3BvsASBM3Sg5BAUYk7KZx5p/Ec77w==", "integrity": "sha512-FqpvcTpIWFpMMwIeSoypoJXysSAQ3R+ALJhXXSG1HTP3YZOIeLmcNcimKaXxTcws+Sh6yoRl13SJ5r8sXc1Fhw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/types": "^13.0.0", "@octokit/types": "^13.0.0",
@@ -217,9 +218,9 @@
} }
}, },
"node_modules/@octokit/request": { "node_modules/@octokit/request": {
"version": "9.1.1", "version": "9.1.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.3.tgz",
"integrity": "sha512-pyAguc0p+f+GbQho0uNetNQMmLG1e80WjkIaqqgUkihqUp0boRU6nKItXO4VWnr+nbZiLGEyy4TeKRwqaLvYgw==", "integrity": "sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/endpoint": "^10.0.0", "@octokit/endpoint": "^10.0.0",
@@ -232,9 +233,9 @@
} }
}, },
"node_modules/@octokit/request-error": { "node_modules/@octokit/request-error": {
"version": "6.1.1", "version": "6.1.5",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.5.tgz",
"integrity": "sha512-1mw1gqT3fR/WFvnoVpY/zUM2o/XkMs/2AszUUG9I69xn0JFLv6PGkPhNk5lbfvROs79wiS0bqiJNxfCZcRJJdg==", "integrity": "sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/types": "^13.0.0" "@octokit/types": "^13.0.0"
@@ -244,9 +245,9 @@
} }
}, },
"node_modules/@octokit/types": { "node_modules/@octokit/types": {
"version": "13.5.0", "version": "13.6.1",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.5.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.6.1.tgz",
"integrity": "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==", "integrity": "sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^22.2.0" "@octokit/openapi-types": "^22.2.0"
@@ -1109,14 +1110,15 @@
} }
}, },
"node_modules/@semantic-release/commit-analyzer": { "node_modules/@semantic-release/commit-analyzer": {
"version": "12.0.0", "version": "13.0.0",
"resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-12.0.0.tgz", "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-13.0.0.tgz",
"integrity": "sha512-qG+md5gdes+xa8zP7lIo1fWE17zRdO8yMCaxh9lyL65TQleoSv8WHHOqRURfghTytUh+NpkSyBprQ5hrkxOKVQ==", "integrity": "sha512-KtXWczvTAB1ZFZ6B4O+w8HkfYm/OgQb1dUGNFZtDgQ0csggrmkq8sTxhd+lwGF8kMb59/RnG9o4Tn7M/I8dQ9Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"conventional-changelog-angular": "^7.0.0", "conventional-changelog-angular": "^8.0.0",
"conventional-commits-filter": "^4.0.0", "conventional-changelog-writer": "^8.0.0",
"conventional-commits-parser": "^5.0.0", "conventional-commits-filter": "^5.0.0",
"conventional-commits-parser": "^6.0.0",
"debug": "^4.0.0", "debug": "^4.0.0",
"import-from-esm": "^1.0.3", "import-from-esm": "^1.0.3",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
@@ -1129,6 +1131,73 @@
"semantic-release": ">=20.1.0" "semantic-release": ">=20.1.0"
} }
}, },
"node_modules/@semantic-release/commit-analyzer/node_modules/conventional-changelog-angular": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz",
"integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==",
"dev": true,
"dependencies": {
"compare-func": "^2.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@semantic-release/commit-analyzer/node_modules/conventional-changelog-writer": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.0.0.tgz",
"integrity": "sha512-TQcoYGRatlAnT2qEWDON/XSfnVG38JzA7E0wcGScu7RElQBkg9WWgZd1peCWFcWDh1xfb2CfsrcvOn1bbSzztA==",
"dev": true,
"dependencies": {
"@types/semver": "^7.5.5",
"conventional-commits-filter": "^5.0.0",
"handlebars": "^4.7.7",
"meow": "^13.0.0",
"semver": "^7.5.2"
},
"bin": {
"conventional-changelog-writer": "dist/cli/index.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-filter": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz",
"integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==",
"dev": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-parser": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.0.0.tgz",
"integrity": "sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==",
"dev": true,
"dependencies": {
"meow": "^13.0.0"
},
"bin": {
"conventional-commits-parser": "dist/cli/index.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@semantic-release/commit-analyzer/node_modules/meow": {
"version": "13.2.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
"integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
"dev": true,
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@semantic-release/error": { "node_modules/@semantic-release/error": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz",
@@ -1181,9 +1250,9 @@
} }
}, },
"node_modules/@semantic-release/github": { "node_modules/@semantic-release/github": {
"version": "10.0.5", "version": "11.0.0",
"resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.0.5.tgz", "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.0.tgz",
"integrity": "sha512-hmuCDkfru/Uc9+ZBNOSremAupu6BCslvOVDiG0wYcL8TQodCycp6uvwDyeym1H0M4l3ob9c0s0xMBiZjjXQ2yA==", "integrity": "sha512-Uon6G6gJD8U1JNvPm7X0j46yxNRJ8Ui6SgK4Zw5Ktu8RgjEft3BGn+l/RX1TTzhhO3/uUcKuqM+/9/ETFxWS/Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@octokit/core": "^6.0.0", "@octokit/core": "^6.0.0",
@@ -1207,7 +1276,7 @@
"node": ">=20.8.1" "node": ">=20.8.1"
}, },
"peerDependencies": { "peerDependencies": {
"semantic-release": ">=20.1.0" "semantic-release": ">=24.1.0"
} }
}, },
"node_modules/@semantic-release/github/node_modules/@semantic-release/error": { "node_modules/@semantic-release/github/node_modules/@semantic-release/error": {
@@ -1492,21 +1561,21 @@
} }
}, },
"node_modules/@semantic-release/release-notes-generator": { "node_modules/@semantic-release/release-notes-generator": {
"version": "13.0.0", "version": "14.0.1",
"resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-13.0.0.tgz", "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.0.1.tgz",
"integrity": "sha512-LEeZWb340keMYuREMyxrODPXJJ0JOL8D/mCl74B4LdzbxhtXV2LrPN2QBEcGJrlQhoqLO0RhxQb6masHytKw+A==", "integrity": "sha512-K0w+5220TM4HZTthE5dDpIuFrnkN1NfTGPidJFm04ULT1DEZ9WG89VNXN7F0c+6nMEpWgqmPvb7vY7JkB2jyyA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"conventional-changelog-angular": "^7.0.0", "conventional-changelog-angular": "^8.0.0",
"conventional-changelog-writer": "^7.0.0", "conventional-changelog-writer": "^8.0.0",
"conventional-commits-filter": "^4.0.0", "conventional-commits-filter": "^5.0.0",
"conventional-commits-parser": "^5.0.0", "conventional-commits-parser": "^6.0.0",
"debug": "^4.0.0", "debug": "^4.0.0",
"get-stream": "^7.0.0", "get-stream": "^7.0.0",
"import-from-esm": "^1.0.3", "import-from-esm": "^1.0.3",
"into-stream": "^7.0.0", "into-stream": "^7.0.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"read-pkg-up": "^11.0.0" "read-package-up": "^11.0.0"
}, },
"engines": { "engines": {
"node": ">=20.8.1" "node": ">=20.8.1"
@@ -1515,6 +1584,61 @@
"semantic-release": ">=20.1.0" "semantic-release": ">=20.1.0"
} }
}, },
"node_modules/@semantic-release/release-notes-generator/node_modules/conventional-changelog-angular": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz",
"integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==",
"dev": true,
"dependencies": {
"compare-func": "^2.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@semantic-release/release-notes-generator/node_modules/conventional-changelog-writer": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.0.0.tgz",
"integrity": "sha512-TQcoYGRatlAnT2qEWDON/XSfnVG38JzA7E0wcGScu7RElQBkg9WWgZd1peCWFcWDh1xfb2CfsrcvOn1bbSzztA==",
"dev": true,
"dependencies": {
"@types/semver": "^7.5.5",
"conventional-commits-filter": "^5.0.0",
"handlebars": "^4.7.7",
"meow": "^13.0.0",
"semver": "^7.5.2"
},
"bin": {
"conventional-changelog-writer": "dist/cli/index.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-filter": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz",
"integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==",
"dev": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-parser": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.0.0.tgz",
"integrity": "sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==",
"dev": true,
"dependencies": {
"meow": "^13.0.0"
},
"bin": {
"conventional-commits-parser": "dist/cli/index.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": {
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz",
@@ -1527,6 +1651,18 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/@semantic-release/release-notes-generator/node_modules/meow": {
"version": "13.2.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
"integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
"dev": true,
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@sindresorhus/is": { "node_modules/@sindresorhus/is": {
"version": "4.6.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
@@ -1557,6 +1693,12 @@
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
"dev": true "dev": true
}, },
"node_modules/@types/semver": {
"version": "7.5.8",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
"dev": true
},
"node_modules/agent-base": { "node_modules/agent-base": {
"version": "7.1.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
@@ -1698,12 +1840,41 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/before-after-hook": { "node_modules/before-after-hook": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
"dev": true "dev": true
}, },
"node_modules/bignumber.js": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
"dev": true,
"engines": {
"node": "*"
}
},
"node_modules/bottleneck": { "node_modules/bottleneck": {
"version": "2.19.5", "version": "2.19.5",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
@@ -1722,6 +1893,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"dev": true
},
"node_modules/call-bind": { "node_modules/call-bind": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
@@ -2282,6 +2459,15 @@
"readable-stream": "^2.0.2" "readable-stream": "^2.0.2"
} }
}, },
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"dev": true,
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -2637,6 +2823,12 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1" "url": "https://github.com/sindresorhus/execa?sponsor=1"
} }
}, },
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"dev": true
},
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
@@ -2810,6 +3002,35 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gaxios": {
"version": "6.7.1",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
"integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
"dev": true,
"dependencies": {
"extend": "^3.0.2",
"https-proxy-agent": "^7.0.1",
"is-stream": "^2.0.0",
"node-fetch": "^2.6.9",
"uuid": "^9.0.1"
},
"engines": {
"node": ">=14"
}
},
"node_modules/gcp-metadata": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz",
"integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==",
"dev": true,
"dependencies": {
"gaxios": "^6.0.0",
"json-bigint": "^1.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/get-caller-file": { "node_modules/get-caller-file": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -2950,6 +3171,23 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/google-auth-library": {
"version": "9.14.2",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.2.tgz",
"integrity": "sha512-R+FRIfk1GBo3RdlRYWPdwk8nmtVUOn6+BkDomAC46KoU8kzXzE1HLmOasSCbWUByMMAGkknVF0G5kQ69Vj7dlA==",
"dev": true,
"dependencies": {
"base64-js": "^1.3.0",
"ecdsa-sig-formatter": "^1.0.11",
"gaxios": "^6.1.1",
"gcp-metadata": "^6.1.0",
"gtoken": "^7.0.0",
"jws": "^4.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/gopd": { "node_modules/gopd": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
@@ -2968,6 +3206,19 @@
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true "dev": true
}, },
"node_modules/gtoken": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
"integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
"dev": true,
"dependencies": {
"gaxios": "^6.0.0",
"jws": "^4.0.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/handlebars": { "node_modules/handlebars": {
"version": "4.7.8", "version": "4.7.8",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
@@ -3586,9 +3837,9 @@
"dev": true "dev": true
}, },
"node_modules/issue-parser": { "node_modules/issue-parser": {
"version": "7.0.0", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.0.tgz", "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz",
"integrity": "sha512-jgAw78HO3gs9UrKqJNQvfDj9Ouy8Mhu40fbEJ8yXff4MW8+/Fcn9iFjyWUQ6SKbX8ipPk3X5A3AyfYHRu6uVLw==", "integrity": "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"lodash.capitalize": "^4.2.1", "lodash.capitalize": "^4.2.1",
@@ -3628,6 +3879,15 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/json-bigint": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
"dev": true,
"dependencies": {
"bignumber.js": "^9.0.0"
}
},
"node_modules/json-parse-better-errors": { "node_modules/json-parse-better-errors": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@@ -3683,6 +3943,27 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/jwa": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
"dev": true,
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
"dev": true,
"dependencies": {
"jwa": "^2.0.0",
"safe-buffer": "^5.0.1"
}
},
"node_modules/lines-and-columns": { "node_modules/lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -3967,6 +4248,26 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dev": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/normalize-package-data": { "node_modules/normalize-package-data": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz",
@@ -7197,16 +7498,16 @@
} }
}, },
"node_modules/semantic-release": { "node_modules/semantic-release": {
"version": "23.1.1", "version": "24.1.3",
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.1.1.tgz", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.1.3.tgz",
"integrity": "sha512-qqJDBhbtHsjUEMsojWKGuL5lQFCJuPtiXKEIlFKyTzDDGTAE/oyvznaP8GeOr5PvcqBJ6LQz4JCENWPLeehSpA==", "integrity": "sha512-Cb0Pm3Ye15u8k/B+7EnusMUSIIucAIEBD3QDRmmclv53KVyqmg1Lb3XPx0AMNxfJZEI+ZT+M+IXDyTrudK6Rew==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@semantic-release/commit-analyzer": "^12.0.0", "@semantic-release/commit-analyzer": "^13.0.0-beta.1",
"@semantic-release/error": "^4.0.0", "@semantic-release/error": "^4.0.0",
"@semantic-release/github": "^10.0.0", "@semantic-release/github": "^11.0.0",
"@semantic-release/npm": "^12.0.0", "@semantic-release/npm": "^12.0.0",
"@semantic-release/release-notes-generator": "^13.0.0", "@semantic-release/release-notes-generator": "^14.0.0-beta.1",
"aggregate-error": "^5.0.0", "aggregate-error": "^5.0.0",
"cosmiconfig": "^9.0.0", "cosmiconfig": "^9.0.0",
"debug": "^4.0.0", "debug": "^4.0.0",
@@ -7217,7 +7518,7 @@
"get-stream": "^6.0.0", "get-stream": "^6.0.0",
"git-log-parser": "^1.2.0", "git-log-parser": "^1.2.0",
"hook-std": "^3.0.0", "hook-std": "^3.0.0",
"hosted-git-info": "^7.0.0", "hosted-git-info": "^8.0.0",
"import-from-esm": "^1.3.1", "import-from-esm": "^1.3.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"marked": "^12.0.0", "marked": "^12.0.0",
@@ -7239,6 +7540,170 @@
"node": ">=20.8.1" "node": ">=20.8.1"
} }
}, },
"node_modules/semantic-release-pub": {
"version": "0.8.29",
"resolved": "https://registry.npmjs.org/semantic-release-pub/-/semantic-release-pub-0.8.29.tgz",
"integrity": "sha512-vQbM6kPtnnmVf6ruALL7QkdsKGMVUY9wEcNkKrjvlI78vPvuLSaIm/2nid6kxP2mcZvUPt8PDYkzRk82wLy5+w==",
"dev": true,
"dependencies": {
"@semantic-release/error": "^4.0.0",
"execa": "^9.4.0",
"google-auth-library": "^9.14.1",
"yaml": "^2.5.1",
"zod": "^3.23.8"
},
"engines": {
"node": ">=20.18.0"
}
},
"node_modules/semantic-release-pub/node_modules/@semantic-release/error": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz",
"integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==",
"dev": true,
"engines": {
"node": ">=18"
}
},
"node_modules/semantic-release-pub/node_modules/@sindresorhus/merge-streams": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
"integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
"dev": true,
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release-pub/node_modules/execa": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-9.4.1.tgz",
"integrity": "sha512-5eo/BRqZm3GYce+1jqX/tJ7duA2AnE39i88fuedNFUV8XxGxUpF3aWkBRfbUcjV49gCkvS/pzc0YrCPhaIewdg==",
"dev": true,
"dependencies": {
"@sindresorhus/merge-streams": "^4.0.0",
"cross-spawn": "^7.0.3",
"figures": "^6.1.0",
"get-stream": "^9.0.0",
"human-signals": "^8.0.0",
"is-plain-obj": "^4.1.0",
"is-stream": "^4.0.1",
"npm-run-path": "^6.0.0",
"pretty-ms": "^9.0.0",
"signal-exit": "^4.1.0",
"strip-final-newline": "^4.0.0",
"yoctocolors": "^2.0.0"
},
"engines": {
"node": "^18.19.0 || >=20.5.0"
},
"funding": {
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
"node_modules/semantic-release-pub/node_modules/get-stream": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
"integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
"dev": true,
"dependencies": {
"@sec-ant/readable-stream": "^0.4.1",
"is-stream": "^4.0.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release-pub/node_modules/human-signals": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
"integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==",
"dev": true,
"engines": {
"node": ">=18.18.0"
}
},
"node_modules/semantic-release-pub/node_modules/is-stream": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
"integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
"dev": true,
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release-pub/node_modules/npm-run-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
"integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
"dev": true,
"dependencies": {
"path-key": "^4.0.0",
"unicorn-magic": "^0.3.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release-pub/node_modules/path-key": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release-pub/node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/semantic-release-pub/node_modules/strip-final-newline": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
"integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
"dev": true,
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release-pub/node_modules/unicorn-magic": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
"integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
"dev": true,
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/@semantic-release/error": { "node_modules/semantic-release/node_modules/@semantic-release/error": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz",
@@ -7345,6 +7810,18 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/semantic-release/node_modules/hosted-git-info": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.0.0.tgz",
"integrity": "sha512-4nw3vOVR+vHUOT8+U4giwe2tcGv+R3pwwRidUe67DoMBTjhrfr6rZYJVVwdkBE+Um050SG+X9tf0Jo4fOpn01w==",
"dev": true,
"dependencies": {
"lru-cache": "^10.0.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/semantic-release/node_modules/human-signals": { "node_modules/semantic-release/node_modules/human-signals": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-7.0.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-7.0.0.tgz",
@@ -7973,6 +8450,12 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"dev": true
},
"node_modules/traverse": { "node_modules/traverse": {
"version": "0.6.9", "version": "0.6.9",
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.9.tgz", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.9.tgz",
@@ -8189,6 +8672,19 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true "dev": true
}, },
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"dev": true,
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/validate-npm-package-license": { "node_modules/validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@@ -8199,6 +8695,22 @@
"spdx-expression-parse": "^3.0.0" "spdx-expression-parse": "^3.0.0"
} }
}, },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"dev": true
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dev": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -8329,6 +8841,18 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/yaml": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz",
"integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==",
"dev": true,
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/yargs": { "node_modules/yargs": {
"version": "17.7.2", "version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@@ -8367,6 +8891,15 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
},
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
} }
} }
} }

View File

@@ -5,6 +5,7 @@
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^6.0.3", "@semantic-release/exec": "^6.0.3",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"semantic-release": "^23.0.8" "semantic-release": "^24.1.3",
"semantic-release-pub": "^0.8.29"
} }
} }

View File

@@ -4,7 +4,7 @@ homepage: https://revanced.app
publish_to: 'none' publish_to: 'none'
version: 1.23.0-dev.1+101800041 version: 1.23.0-dev.7+101800047
environment: environment:
sdk: ^3.5.3 sdk: ^3.5.3