Compare commits

...

95 Commits

Author SHA1 Message Date
84df499ea6 Merge pull request #1606 from ImranR98/dev
- Add more links to the settings page (#1554)
- Support for more Huawei AppGallery URL schemes (#1570)
- Fix HTML release asset download (#1578)
- Fix non-APK GitHub release asset downloads (#1581)
- Fix asset date UI (#1590)
2024-05-05 22:07:51 -04:00
0d25b74050 Increment version 2024-05-05 22:05:59 -04:00
0effbc3841 Merge remote-tracking branch 'origin/main' into dev 2024-05-05 22:05:07 -04:00
7478a7af22 Add more links to the settings page (#1554) 2024-05-05 22:03:04 -04:00
0838a6d30b Support for more Huawei AppGallery URL schemes (#1570) 2024-05-05 21:51:05 -04:00
8cee268d13 Fix HTML release asset download (#1578) 2024-05-05 21:43:05 -04:00
a3fddc5400 Fix non-APK GitHub release asset downloads (#1581) 2024-05-05 21:35:16 -04:00
c0a2e372e5 Fix asset date UI (#1590) + update packages 2024-05-05 21:11:59 -04:00
c633963203 Merge pull request #1598 from LilligantMatsuri/main
Update Chinese translation
2024-05-02 09:11:40 -04:00
299f457938 Update zh.json
- Add a missing string and its translation (#L116)
- Correct inaccurate translations
- Minor improvements

Signed-off-by: Matsuri <matsuri@vmoe.info>
2024-05-02 16:00:00 +08:00
37e62c922b Merge pull request #1591 from Hamster45105/main
Fix README link
2024-05-01 09:05:15 -04:00
95722ce47b Fix README link 2024-05-01 16:42:56 +10:00
8b806b3ef1 Merge pull request #1585 from Hamster45105/patch-1
Update README
2024-04-30 16:35:41 -04:00
09221b3526 Update README 2024-04-29 11:56:28 +10:00
31b6250082 Merge pull request #1568 from DwainZwerg/patch-16
Update de.json
2024-04-28 13:32:12 -04:00
07372da91b Merge pull request #1569 from bluefly000/japanese-translation
Update ja.json
2024-04-28 13:32:01 -04:00
5c36bcfb4b Merge pull request #1575 from Stephan-P/patch-1
Update nl.json
2024-04-28 13:31:52 -04:00
e5012b1fcb Merge pull request #1582 from CertainBot/patch-3
Spanish Update
2024-04-28 13:31:43 -04:00
6f951175a4 Spanish Update
English:
- texts homogenized, few corrections
Español:
- homogeneizar textos, algunas correcciones
2024-04-27 17:31:38 +02:00
be52ec372f Update nl.json
Significant overhaul of the Dutch translation including addition of a line that was missing compared to en.json
2024-04-24 20:02:50 +02:00
eb7126afc3 Update ja.json 2024-04-24 13:14:41 +09:00
26fc63a02a Update de.json 2024-04-23 22:15:22 +02:00
d33ca0948f Merge pull request #1567 from ImranR98/dev
- Share apps.obtainium.imranr.dev config links instead of HTML raw (#1553)
- Remove foreground requirement for Shizuku (#1561)
- Fix "illegal encoding" error (#1563)
2024-04-23 14:48:53 -04:00
f76637a2e1 Update packages, increment version 2024-04-23 14:47:13 -04:00
b7de627c7b Share apps.obtainium.imranr.dev config links instead of HTML raw (#1553) 2024-04-23 14:43:37 -04:00
27fc60d437 Fix "illegal encoding" error (#1563), Remove foreground requirement for Shizuku (#1561) 2024-04-23 14:35:28 -04:00
ec240f946e Merge pull request #1555 from DwainZwerg/patch-15
Update de.json
2024-04-23 14:15:56 -04:00
ecd80fc371 Merge pull request #1556 from re7gog/re7gog
Fixes
2024-04-23 14:15:47 -04:00
68fa660e6d Merge pull request #1559 from CertainBot/patch-2
Spanish update
2024-04-23 14:15:37 -04:00
70f9e33d17 Merge pull request #1560 from jmoerschbach/conflicting_provider
Use applicationId for provider authorities
2024-04-23 14:15:09 -04:00
2e2dffd8e2 Merge pull request #1562 from ArcticFoxPro/main
Fix some questions of 简体中文(Simplified Chinese) and English.
2024-04-23 14:15:00 -04:00
0b1d5bf514 Fix some questions of 简体中文(zh-CN) and English.
Google's "Material You" is a specific noun in China, and it can be used directly in English, because Google China is also directly used in English, and translated into Chinese "您的材料" will look strange to Chinese users.
2024-04-22 16:01:21 +08:00
2570c8e289 Use applicationId for provider authorities
Fixes #1378

Instead of hardcoding the authority string, use the ${applicationId} to
always make the provider unique.
2024-04-21 21:49:33 +02:00
43a8ba4de1 Spanish update
- English:
Minor changes.

- Spanish:
Modificaciones menores.
2024-04-21 21:20:55 +02:00
3f2fb1c1ed Update de.json 2024-04-21 15:45:26 +02:00
40d303fb57 Partially rollback system theme (#1552) 2024-04-21 16:31:55 +03:00
2c1687c33d Hide some settings if they are not available 2024-04-21 12:53:57 +03:00
b688e7f160 Fix #968 2024-04-21 12:21:52 +03:00
0c80d88583 Merge pull request #1551 from ImranR98/dev
Minor Adjustments
2024-04-20 19:45:46 -04:00
b293b1e9ff Update Flutter, packages, increment version 2024-04-20 19:44:32 -04:00
61038a8969 Updated translations 2024-04-20 19:38:59 -04:00
b92d1541bf Restore Flutter branch 2024-04-20 19:36:02 -04:00
13f0ccb10d Merge pull request #1548 from re7gog/re7gog
Native and UI improvements
2024-04-20 19:35:37 -04:00
ed732cfad2 Look at all these colors!🌈 2024-04-20 18:24:08 +03:00
fb206aee84 Add system theme api level check 2024-04-20 11:57:12 +03:00
285530784d little 2024-04-20 11:30:34 +03:00
0ddb5b5e81 Merge branch 'main' into re7gog
# Conflicts:
#	pubspec.lock
2024-04-19 18:07:51 +03:00
c16cda1962 Make pretending to be a Google Play setting per app based⚙️ 2024-04-19 17:57:22 +03:00
49022726d3 Shizuku logic 3: Prettify 2024-04-19 16:41:34 +03:00
a311894b9f Shizuku logic 2: Determination of installation 2024-04-18 20:01:40 +03:00
29e13efd66 Change background shizuku logic 2024-04-17 17:05:08 +03:00
8c2a97e092 Merge pull request #1544 from ImranR98/dev
- Don't trust content-length header from sites w/o accept-ranges support (#1542) + bugfixes
- Allow for spaces in HTML link and version filters (#1537)
2024-04-15 19:16:10 -04:00
34d571f586 Merge remote-tracking branch 'origin/main' into dev 2024-04-15 19:14:47 -04:00
a20b87889b Update packages, increment version 2024-04-15 19:14:39 -04:00
c7319cd958 Merge pull request #1540 from o101010/main
Corrects french translations
2024-04-15 19:09:50 -04:00
d61fd800ef Merge pull request #1543 from yurtpage/main
fastlane: i18n ru for app description
2024-04-15 19:09:26 -04:00
12dda8bfa9 Allow for spaces in HTML link and version filters (#1537) 2024-04-15 19:06:24 -04:00
0657f832e1 Don't trust content-length header from sites w/o accept-ranges support (#1542) + bugfixes 2024-04-15 18:39:21 -04:00
6431357b15 ru.json: translate apk.other 2024-04-16 01:16:08 +03:00
dcc42bdfe5 fastlane: i18n ru for app description 2024-04-16 01:09:18 +03:00
85718dc3a3 Update README.md 2024-04-15 17:53:55 -04:00
9dff352796 Update README.md 2024-04-15 17:52:35 -04:00
c5477767a0 Update README.md 2024-04-15 17:52:08 -04:00
3131ef8c4e Neat slider 2024-04-15 12:55:34 +03:00
4d9f05aa87 Corrects french translations
Corrects french translations in fr.json.
2024-04-14 20:52:51 +02:00
7b882d9bd8 Move to plugins🐱🎉 2024-04-14 18:40:32 +03:00
d1a2831922 Merge pull request #1535 from ImranR98/dev
Update packages, increment version
2024-04-13 03:09:10 -04:00
b042050ea3 Update packages, increment version 2024-04-13 03:05:44 -04:00
2d43dfe0a7 Merge pull request #1525 from gidano/main
Update hu.json
2024-04-13 03:04:13 -04:00
b1a740223c Merge pull request #1529 from DwainZwerg/patch-14
Update de.json
2024-04-13 03:04:02 -04:00
41c98d97b1 Merge pull request #1532 from gepbird/fix-generated-form-update
Fix out of bounds array access in GeneratedForm update
2024-04-13 03:03:47 -04:00
fb06babb96 Merge branch 'main' into re7gog 2024-04-12 13:21:52 +03:00
ccc0e7696b Fix out of bounds array access in GeneratedForm update 2024-04-08 21:45:19 +02:00
6d41ed8011 Update de.json
Corrected translation
2024-04-08 08:44:28 +02:00
c1476a7d58 Update hu.json 2024-04-07 09:37:28 +02:00
b1ee39be3b Merge pull request #1524 from ImranR98/dev
Add release asset download button (#1493) + Minor UI change
2024-04-07 02:25:27 -04:00
c2ccdd3d05 Merge remote-tracking branch 'origin/main' into dev 2024-04-07 02:21:45 -04:00
a621f1dfb4 Update packages, increment version 2024-04-07 02:21:38 -04:00
8527ad0007 Bugfix in release asset download 2024-04-07 02:19:40 -04:00
377ecef1b4 More resilient release asset import (if Downloads inaccessible, use export dir) 2024-04-07 02:18:26 -04:00
1f9921e6ff UI improvements 2024-04-07 02:13:36 -04:00
00988ed04d Improve release asset download UI 2024-04-07 01:41:35 -04:00
3d1113c057 Add release asset download button (#1493) 2024-04-07 01:28:45 -04:00
1c81f0c1e1 Merge pull request #1516 from ImranR98/dev
* Add support for GitLab CI artifact links in releases (#1506)
* Improve load speed on return to foreground
2024-04-03 18:15:44 -04:00
b26043ef5e Merge remote-tracking branch 'origin/main' into dev 2024-04-03 18:14:04 -04:00
e3ad144c06 Merge pull request #1503 from ngocanhtve/main
Update vi.json
2024-04-03 18:13:53 -04:00
fdb45c48ce Upgrade packages, increment version 2024-04-03 18:12:42 -04:00
8619cfa819 Add support for GitLab CI artifact links in releases (#1506) 2024-04-02 14:07:32 -04:00
1fe4cdd648 Improve load speed on return to foreground 2024-04-02 13:45:32 -04:00
2289e58dda Move to fonts plugin 2024-03-31 14:18:21 +03:00
049bcfbaf5 Ooops 2024-03-30 16:11:55 +03:00
5b5f922b54 Synced 2024-03-30 15:58:28 +03:00
6545498c21 Return random request code 2024-03-30 15:39:48 +03:00
ce22197ec9 Update vi.json
Complete.
2024-03-29 12:07:13 +07:00
9717db0ca4 Probably fixed 2024-02-05 18:26:17 +03:00
52 changed files with 1695 additions and 1387 deletions

View File

@ -4,11 +4,13 @@
Get Android App Updates Directly From the Source. Get Android App Updates Directly From the Source.
Obtainium allows you to install and update Apps directly from their releases pages, and receive notifications when new releases are made available. Obtainium allows you to install and update apps directly from their releases pages, and receive notifications when new releases are made available.
Motivation: [Side Of Burritos - You should use this instead of F-Droid | How to use app RSS feed](https://youtu.be/FFz57zNR_M0) More info:
- [Obtainium/wiki](https://github.com/ImranR98/Obtainium/wiki)
Read the Wiki: [https://github.com/ImranR98/Obtainium/wiki](https://github.com/ImranR98/Obtainium/wiki) - [AppVerifier](https://github.com/soupslurpr/AppVerifier) - App verification tool (recommended, integrates with Obtainium)
- [apps.obtainium.imranr.dev](https://apps.obtainium.imranr.dev/) - Crowdsourced app configurations
- [Side Of Burritos - You should use this instead of F-Droid | How to use app RSS feed](https://youtu.be/FFz57zNR_M0) - Original motivation for this app
Currently supported App sources: Currently supported App sources:
- Open Source - General: - Open Source - General:
@ -27,15 +29,23 @@ Currently supported App sources:
- [Huawei AppGallery](https://appgallery.huawei.com/) - [Huawei AppGallery](https://appgallery.huawei.com/)
- Jenkins Jobs - Jenkins Jobs
- Open Source - App-Specific: - Open Source - App-Specific:
- [Mullvad](https://mullvad.net/en/)
- [Signal](https://signal.org/) - [Signal](https://signal.org/)
- [VLC](https://videolan.org/) - [VLC](https://videolan.org/)
- Other - App-Specific: - Other - App-Specific:
- [WhatsApp](https://whatsapp.com) - [WhatsApp](https://whatsapp.com)
- [Telegram App](https://telegram.org) - [Telegram App](https://telegram.org)
- [Neutron Code](https://neutroncode.com) - [Neutron Code](https://neutroncode.com)
- Direct APK Link
- "HTML" (Fallback): Any other URL that returns an HTML page with links to APK files - "HTML" (Fallback): Any other URL that returns an HTML page with links to APK files
## Finding App Configurations
You can find crowdsourced app configurations at [apps.obtainium.imranr.dev](https://apps.obtainium.imranr.dev).
If you can't find the configuration for an app you want, feel free to leave a request on the [discussions page](https://github.com/ImranR98/apps.obtainium.imranr.dev/discussions/new?category=app-requests).
Or, contribute some configurations to the website by creating a PR at [this repo](https://github.com/ImranR98/apps.obtainium.imranr.dev).
## Installation ## Installation
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png" [<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"

View File

@ -92,20 +92,6 @@ repositories {
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
} }
dependencies {
def shizuku_version = '13.1.5'
implementation "dev.rikka.shizuku:api:$shizuku_version"
implementation "dev.rikka.shizuku:provider:$shizuku_version"
def hidden_api_version = '4.3.1'
implementation "dev.rikka.tools.refine:runtime:$hidden_api_version"
implementation "dev.rikka.hidden:compat:$hidden_api_version"
compileOnly "dev.rikka.hidden:stub:$hidden_api_version"
implementation "org.lsposed.hiddenapibypass:hiddenapibypass:4.3"
implementation "com.github.topjohnwu.libsu:core:5.2.2"
}
ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3] ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3]
import com.android.build.OutputFile import com.android.build.OutputFile
android.applicationVariants.all { variant -> android.applicationVariants.all { variant ->

View File

@ -47,7 +47,7 @@
android:value="2" /> android:value="2" />
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="dev.imranr.obtainium" android:authorities="${applicationId}"
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data
android:name="android.support.FILE_PROVIDER_PATHS" android:name="android.support.FILE_PROVIDER_PATHS"
@ -72,4 +72,4 @@
android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />\ android:maxSdkVersion="29" />\
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
</manifest> </manifest>

View File

@ -1,44 +0,0 @@
package dev.imranr.obtainium
import android.util.Xml
import org.xmlpull.v1.XmlPullParser
import java.io.File
import java.io.FileInputStream
class DefaultSystemFont {
fun get(): String {
return try {
val file = File("/system/etc/fonts.xml")
val fileStream = FileInputStream(file)
parseFontsFileStream(fileStream)
} catch (e: Exception) {
e.message ?: "Unknown fonts.xml parsing exception"
}
}
private fun parseFontsFileStream(fileStream: FileInputStream): String {
fileStream.use { stream ->
val parser = Xml.newPullParser()
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
parser.setInput(stream, null)
parser.nextTag()
return parseFonts(parser)
}
}
private fun parseFonts(parser: XmlPullParser): String {
while (!((parser.next() == XmlPullParser.END_TAG) && (parser.name == "family"))) {
if ((parser.eventType == XmlPullParser.START_TAG) && (parser.name == "font")
&& (parser.getAttributeValue(null, "style") == "normal")
&& (parser.getAttributeValue(null, "weight") == "400")) {
break
}
}
parser.next()
val fontFile = parser.text.trim()
if (fontFile == "") {
throw NoSuchFieldException("The font filename couldn't be found in fonts.xml")
}
return "/system/fonts/$fontFile"
}
}

View File

@ -1,179 +1,5 @@
package dev.imranr.obtainium package dev.imranr.obtainium
import android.content.Intent
import android.content.IntentSender
import android.content.pm.IPackageInstaller
import android.content.pm.IPackageInstallerSession
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Process
import androidx.annotation.NonNull
import com.topjohnwu.superuser.Shell
import dev.imranr.obtainium.util.IIntentSenderAdaptor
import dev.imranr.obtainium.util.IntentSenderUtils
import dev.imranr.obtainium.util.PackageInstallerUtils
import dev.imranr.obtainium.util.ShizukuSystemServerApi
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.Result
import java.io.IOException
import java.util.concurrent.CountDownLatch
import org.lsposed.hiddenapibypass.HiddenApiBypass
import rikka.shizuku.Shizuku
import rikka.shizuku.Shizuku.OnRequestPermissionResultListener
import rikka.shizuku.ShizukuBinderWrapper
class MainActivity: FlutterActivity() { class MainActivity: FlutterActivity()
private var nativeChannel: MethodChannel? = null
private val SHIZUKU_PERMISSION_REQUEST_CODE = (10..200).random()
private fun shizukuCheckPermission(result: Result) {
try {
if (Shizuku.isPreV11()) { // Unsupported
result.success(-1)
} else if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
result.success(1)
} else if (Shizuku.shouldShowRequestPermissionRationale()) { // Deny and don't ask again
result.success(0)
} else {
Shizuku.requestPermission(SHIZUKU_PERMISSION_REQUEST_CODE)
result.success(-2)
}
} catch (_: Exception) { // If shizuku not running
result.success(-1)
}
}
private val shizukuRequestPermissionResultListener = OnRequestPermissionResultListener {
requestCode: Int, grantResult: Int ->
if (requestCode == SHIZUKU_PERMISSION_REQUEST_CODE) {
val res = if (grantResult == PackageManager.PERMISSION_GRANTED) 1 else 0
nativeChannel!!.invokeMethod("resPermShizuku", mapOf("res" to res))
}
}
private fun shizukuInstallApk(apkFileUri: String, result: Result) {
val uri = Uri.parse(apkFileUri)
var res = false
var session: PackageInstaller.Session? = null
try {
val iPackageInstaller: IPackageInstaller =
ShizukuSystemServerApi.PackageManager_getPackageInstaller()
val isRoot = Shizuku.getUid() == 0
// The reason for use "com.android.shell" as installer package under adb
// is that getMySessions will check installer package's owner
val installerPackageName = if (isRoot) packageName else "com.android.shell"
var installerAttributionTag: String? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
installerAttributionTag = attributionTag
}
val userId = if (isRoot) Process.myUserHandle().hashCode() else 0
val packageInstaller = PackageInstallerUtils.createPackageInstaller(
iPackageInstaller, installerPackageName, installerAttributionTag, userId)
val params =
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
var installFlags: Int = PackageInstallerUtils.getInstallFlags(params)
installFlags = installFlags or (0x00000002/*PackageManager.INSTALL_REPLACE_EXISTING*/
or 0x00000004 /*PackageManager.INSTALL_ALLOW_TEST*/)
PackageInstallerUtils.setInstallFlags(params, installFlags)
val sessionId = packageInstaller.createSession(params)
val iSession = IPackageInstallerSession.Stub.asInterface(
ShizukuBinderWrapper(iPackageInstaller.openSession(sessionId).asBinder()))
session = PackageInstallerUtils.createSession(iSession)
val inputStream = contentResolver.openInputStream(uri)
val openedSession = session.openWrite("apk.apk", 0, -1)
val buffer = ByteArray(8192)
var length: Int
try {
while (inputStream!!.read(buffer).also { length = it } > 0) {
openedSession.write(buffer, 0, length)
openedSession.flush()
session.fsync(openedSession)
}
} finally {
try {
inputStream!!.close()
openedSession.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
val results = arrayOf<Intent?>(null)
val countDownLatch = CountDownLatch(1)
val intentSender: IntentSender =
IntentSenderUtils.newInstance(object : IIntentSenderAdaptor() {
override fun send(intent: Intent?) {
results[0] = intent
countDownLatch.countDown()
}
})
session.commit(intentSender)
countDownLatch.await()
res = results[0]!!.getIntExtra(
PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE) == 0
} catch (_: Exception) {
res = false
} finally {
if (session != null) {
try {
session.close()
} catch (_: Exception) {
res = false
}
}
}
result.success(res)
}
private fun rootCheckPermission(result: Result) {
Shell.getShell(Shell.GetShellCallback(
fun(shell: Shell) {
result.success(shell.isRoot)
}
))
}
private fun rootInstallApk(apkFilePath: String, result: Result) {
Shell.sh("pm install -r -t " + apkFilePath).submit { out ->
val builder = StringBuilder()
for (data in out.getOut()) { builder.append(data) }
result.success(builder.toString().endsWith("Success"))
}
}
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
HiddenApiBypass.addHiddenApiExemptions("")
}
Shizuku.addRequestPermissionResultListener(shizukuRequestPermissionResultListener)
nativeChannel = MethodChannel(
flutterEngine.dartExecutor.binaryMessenger, "native")
nativeChannel!!.setMethodCallHandler {
call, result ->
if (call.method == "getSystemFont") {
val res = DefaultSystemFont().get()
result.success(res)
} else if (call.method == "checkPermissionShizuku") {
shizukuCheckPermission(result)
} else if (call.method == "checkPermissionRoot") {
rootCheckPermission(result)
} else if (call.method == "installWithShizuku") {
val apkFileUri: String? = call.argument("apkFileUri")
shizukuInstallApk(apkFileUri!!, result)
} else if (call.method == "installWithRoot") {
val apkFilePath: String? = call.argument("apkFilePath")
rootInstallApk(apkFilePath!!, result)
}
}
}
override fun onDestroy() {
super.onDestroy()
Shizuku.removeRequestPermissionResultListener(shizukuRequestPermissionResultListener)
}
}

View File

@ -1,37 +0,0 @@
package dev.imranr.obtainium.util;
import android.annotation.SuppressLint;
import android.app.Application;
import android.os.Build;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ApplicationUtils {
private static Application application;
public static Application getApplication() {
return application;
}
public static void setApplication(Application application) {
ApplicationUtils.application = application;
}
public static String getProcessName() {
if (Build.VERSION.SDK_INT >= 28)
return Application.getProcessName();
else {
try {
@SuppressLint("PrivateApi")
Class<?> activityThread = Class.forName("android.app.ActivityThread");
@SuppressLint("DiscouragedPrivateApi")
Method method = activityThread.getDeclaredMethod("currentProcessName");
return (String) method.invoke(null);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@ -1,23 +0,0 @@
package dev.imranr.obtainium.util;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
public abstract class IIntentSenderAdaptor extends IIntentSender.Stub {
public abstract void send(Intent intent);
@Override
public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
send(intent);
return 0;
}
@Override
public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
send(intent);
}
}

View File

@ -1,14 +0,0 @@
package dev.imranr.obtainium.util;
import android.content.IIntentSender;
import android.content.IntentSender;
import java.lang.reflect.InvocationTargetException;
public class IntentSenderUtils {
public static IntentSender newInstance(IIntentSender binder) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//noinspection JavaReflectionMemberAccess
return IntentSender.class.getConstructor(IIntentSender.class).newInstance(binder);
}
}

View File

@ -1,41 +0,0 @@
package dev.imranr.obtainium.util;
import android.content.Context;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageInstallerSession;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.os.Build;
import java.lang.reflect.InvocationTargetException;
@SuppressWarnings({"JavaReflectionMemberAccess"})
public class PackageInstallerUtils {
public static PackageInstaller createPackageInstaller(IPackageInstaller installer, String installerPackageName, String installerAttributionTag, int userId) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
return PackageInstaller.class.getConstructor(IPackageInstaller.class, String.class, String.class, int.class)
.newInstance(installer, installerPackageName, installerAttributionTag, userId);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return PackageInstaller.class.getConstructor(IPackageInstaller.class, String.class, int.class)
.newInstance(installer, installerPackageName, userId);
} else {
return PackageInstaller.class.getConstructor(Context.class, PackageManager.class, IPackageInstaller.class, String.class, int.class)
.newInstance(ApplicationUtils.getApplication(), ApplicationUtils.getApplication().getPackageManager(), installer, installerPackageName, userId);
}
}
public static PackageInstaller.Session createSession(IPackageInstallerSession session) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
return PackageInstaller.Session.class.getConstructor(IPackageInstallerSession.class)
.newInstance(session);
}
public static int getInstallFlags(PackageInstaller.SessionParams params) throws NoSuchFieldException, IllegalAccessException {
return (int) PackageInstaller.SessionParams.class.getDeclaredField("installFlags").get(params);
}
public static void setInstallFlags(PackageInstaller.SessionParams params, int newValue) throws NoSuchFieldException, IllegalAccessException {
PackageInstaller.SessionParams.class.getDeclaredField("installFlags").set(params, newValue);
}
}

View File

@ -1,68 +0,0 @@
package dev.imranr.obtainium.util;
import android.content.Context;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
import android.os.Build;
import android.os.IUserManager;
import android.os.RemoteException;
import java.util.List;
import rikka.shizuku.ShizukuBinderWrapper;
import rikka.shizuku.SystemServiceHelper;
public class ShizukuSystemServerApi {
private static final Singleton<IPackageManager> PACKAGE_MANAGER = new Singleton<IPackageManager>() {
@Override
protected IPackageManager create() {
return IPackageManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")));
}
};
private static final Singleton<IUserManager> USER_MANAGER = new Singleton<IUserManager>() {
@Override
protected IUserManager create() {
return IUserManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService(Context.USER_SERVICE)));
}
};
public static IPackageInstaller PackageManager_getPackageInstaller() throws RemoteException {
IPackageInstaller packageInstaller = PACKAGE_MANAGER.get().getPackageInstaller();
return IPackageInstaller.Stub.asInterface(new ShizukuBinderWrapper(packageInstaller.asBinder()));
}
public static List<UserInfo> UserManager_getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated) throws RemoteException {
if (Build.VERSION.SDK_INT >= 30) {
return USER_MANAGER.get().getUsers(excludePartial, excludeDying, excludePreCreated);
} else {
try {
return USER_MANAGER.get().getUsers(excludeDying);
} catch (NoSuchFieldError e) {
return USER_MANAGER.get().getUsers(excludePartial, excludeDying, excludePreCreated);
}
}
}
// method 2: use transactRemote directly
/*public static List<UserInfo> UserManager_getUsers(boolean excludeDying) {
Parcel data = SystemServiceHelper.obtainParcel(Context.USER_SERVICE, "android.os.IUserManager", "getUsers");
Parcel reply = Parcel.obtain();
data.writeInt(excludeDying ? 1 : 0);
List<UserInfo> res = null;
try {
ShizukuService.transactRemote(data, reply, 0);
reply.readException();
res = reply.createTypedArrayList(UserInfo.CREATOR);
} catch (RemoteException e) {
Log.e("ShizukuSample", "UserManager#getUsers", e);
} finally {
data.recycle();
reply.recycle();
}
return res;
}*/
}

View File

@ -1,17 +0,0 @@
package dev.imranr.obtainium.util;
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}

View File

@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx2048M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(obavezno)", "requiredInBrackets": "(obavezno)",
"dropdownNoOptsError": "GREŠKA: PADAJUĆI MENI MORA IMATI NAJMANJE JEDNU OPCIJU", "dropdownNoOptsError": "GREŠKA: PADAJUĆI MENI MORA IMATI NAJMANJE JEDNU OPCIJU",
"colour": "Boja", "colour": "Boja",
"standard": "Standard",
"custom": "Custom",
"useMaterialYou": "Use Material You",
"githubStarredRepos": "GitHub repo-i sa zvjezdicom", "githubStarredRepos": "GitHub repo-i sa zvjezdicom",
"uname": "Korisničko ime", "uname": "Korisničko ime",
"wrongArgNum": "Naveden je pogrešan broj argumenata", "wrongArgNum": "Naveden je pogrešan broj argumenata",
@ -110,6 +113,7 @@
"dark": "Tamna", "dark": "Tamna",
"light": "Svijetla", "light": "Svijetla",
"followSystem": "Pratite sistem", "followSystem": "Pratite sistem",
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications",
"useBlackTheme": "Koristite čisto crnu tamnu temu", "useBlackTheme": "Koristite čisto crnu tamnu temu",
"appSortBy": "Aplikacije sortirane po", "appSortBy": "Aplikacije sortirane po",
"authorName": "Autor/Ime", "authorName": "Autor/Ime",
@ -143,8 +147,10 @@
"noNewUpdates": "Nema novih ažuriranja.", "noNewUpdates": "Nema novih ažuriranja.",
"xHasAnUpdate": "{} ima ažuriranje.", "xHasAnUpdate": "{} ima ažuriranje.",
"appsUpdated": "Aplikacije su ažurirane", "appsUpdated": "Aplikacije su ažurirane",
"appsNotUpdated": "Failed to update applications",
"appsUpdatedNotifDescription": "Obavještava korisnika da su u pozadini primijenjena ažuriranja na jednu ili više aplikacija", "appsUpdatedNotifDescription": "Obavještava korisnika da su u pozadini primijenjena ažuriranja na jednu ili više aplikacija",
"xWasUpdatedToY": "{} je ažuriran na {}.", "xWasUpdatedToY": "{} je ažuriran na {}.",
"xWasNotUpdatedToY": "Failed to update {} to {}.",
"errorCheckingUpdates": "Greška pri provjeri ažuriranja", "errorCheckingUpdates": "Greška pri provjeri ažuriranja",
"errorCheckingUpdatesNotifDescription": "Obavijest koja se prikazuje kada provjera sigurnosnog ažuriranja ne uspije", "errorCheckingUpdatesNotifDescription": "Obavijest koja se prikazuje kada provjera sigurnosnog ažuriranja ne uspije",
"appsRemoved": "Aplikacije su uklonjene", "appsRemoved": "Aplikacije su uklonjene",
@ -183,6 +189,9 @@
"disableVersionDetection": "Onemogući detekciju verzije", "disableVersionDetection": "Onemogući detekciju verzije",
"noVersionDetectionExplanation": "Ova opcija bi se trebala koristiti samo za aplikacije gdje detekcija verzije ne radi ispravno.", "noVersionDetectionExplanation": "Ova opcija bi se trebala koristiti samo za aplikacije gdje detekcija verzije ne radi ispravno.",
"downloadingX": "Preuzimanje {}", "downloadingX": "Preuzimanje {}",
"downloadX": "Download {}",
"downloadedX": "Downloaded {}",
"releaseAsset": "Release Asset",
"downloadNotifDescription": "Obavještava korisnika o napretku u preuzimanju aplikacije", "downloadNotifDescription": "Obavještava korisnika o napretku u preuzimanju aplikacije",
"noAPKFound": "APK nije pronađen", "noAPKFound": "APK nije pronađen",
"noVersionDetection": "Nema detekcije verzije", "noVersionDetection": "Nema detekcije verzije",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Podržite fiksne APK URL-ove", "supportFixedAPKURL": "Podržite fiksne APK URL-ove",
"selectX": "Izaberite {}", "selectX": "Izaberite {}",
"parallelDownloads": "Dozvoli paralelna preuzimanja", "parallelDownloads": "Dozvoli paralelna preuzimanja",
"installMethod": "Način instalacije", "useShizuku": "Use Shizuku or Sui to install",
"normal": "normalno",
"root": "korijen",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"shizukuOld": "Old Shizuku version (<11) - update it",
"shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead",
"shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)",
"useSystemFont": "Koristite sistemski font", "useSystemFont": "Koristite sistemski font",
"systemFontError": "Greška pri učitavanju sistemskog fonta: {}",
"useVersionCodeAsOSVersion": "Koristite kod verzije aplikacije kao verziju koju je otkrio OS", "useVersionCodeAsOSVersion": "Koristite kod verzije aplikacije kao verziju koju je otkrio OS",
"requestHeader": "Zaglavlje zahtjeva", "requestHeader": "Zaglavlje zahtjeva",
"useLatestAssetDateAsReleaseDate": "Koristite najnovije otpremanje materijala kao datum izdavanja", "useLatestAssetDateAsReleaseDate": "Koristite najnovije otpremanje materijala kao datum izdavanja",
@ -301,6 +310,8 @@
"badDownload": "The APK could not be parsed (incompatible or partial download)", "badDownload": "The APK could not be parsed (incompatible or partial download)",
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", "beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)",
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", "appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.",
"wiki": "Help/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?", "one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?" "other": "Želite li ukloniti aplikacije?"
@ -349,6 +360,10 @@
"one": "{} i još 1 aplikacija je ažurirana.", "one": "{} i još 1 aplikacija je ažurirana.",
"other": "{} i još {} aplikacija je ažurirano." "other": "{} i još {} aplikacija je ažurirano."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Failed to update {} and 1 more app.",
"other": "Failed to update {} and {} more apps."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} i još jedna aplikacija je vjerovatno ažurirana.", "one": "{} i još jedna aplikacija je vjerovatno ažurirana.",
"other": "{} i još {} aplikacija su vjerovatno ažurirane." "other": "{} i još {} aplikacija su vjerovatno ažurirane."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(Požadované)", "requiredInBrackets": "(Požadované)",
"dropdownNoOptsError": "ERROR: DROPDOWN MUSÍ MÍT AŽ JEDNU MOŽNOST", "dropdownNoOptsError": "ERROR: DROPDOWN MUSÍ MÍT AŽ JEDNU MOŽNOST",
"colour": "Barva", "colour": "Barva",
"standard": "Standardní",
"custom": "Vlastní",
"useMaterialYou": "Použijte materiál, který jste",
"githubStarredRepos": "GitHub označená hvězdičkou", "githubStarredRepos": "GitHub označená hvězdičkou",
"uname": "Uživatelské jméno", "uname": "Uživatelské jméno",
"wrongArgNum": "Nesprávný počet zadaných argumentů", "wrongArgNum": "Nesprávný počet zadaných argumentů",
@ -110,6 +113,7 @@
"dark": "Tmavé", "dark": "Tmavé",
"light": "Světlé", "light": "Světlé",
"followSystem": "Jako systém", "followSystem": "Jako systém",
"followSystemThemeExplanation": "Sledování motivu systému je možné pouze pomocí aplikací třetích stran.",
"useBlackTheme": "Použít čistě černé tmavé téma", "useBlackTheme": "Použít čistě černé tmavé téma",
"appSortBy": "Seřadit podle", "appSortBy": "Seřadit podle",
"authorName": "Autor/Jméno", "authorName": "Autor/Jméno",
@ -143,8 +147,10 @@
"noNewUpdates": "Žádné nové aktualizace.", "noNewUpdates": "Žádné nové aktualizace.",
"xHasAnUpdate": "{} má aktualizaci.", "xHasAnUpdate": "{} má aktualizaci.",
"appsUpdated": "Aplikace aktualizovány", "appsUpdated": "Aplikace aktualizovány",
"appsNotUpdated": "Nepodařilo se aktualizovat aplikace",
"appsUpdatedNotifDescription": "Upozornit, že byly provedeny aktualizace jedné nebo více aplikací na pozadí", "appsUpdatedNotifDescription": "Upozornit, že byly provedeny aktualizace jedné nebo více aplikací na pozadí",
"xWasUpdatedToY": "{} byla aktualizována na {}", "xWasUpdatedToY": "{} byla aktualizována na {}",
"xWasNotUpdatedToY": "Nepodařilo se aktualizovat {} na {}.",
"errorCheckingUpdates": "Chyba kontroly aktualizací", "errorCheckingUpdates": "Chyba kontroly aktualizací",
"errorCheckingUpdatesNotifDescription": "Zobrazit oznámení při neúspěšné kontrole aktualizací na pozadí", "errorCheckingUpdatesNotifDescription": "Zobrazit oznámení při neúspěšné kontrole aktualizací na pozadí",
"appsRemoved": "Odstraněné aplikace", "appsRemoved": "Odstraněné aplikace",
@ -183,6 +189,9 @@
"disableVersionDetection": "Deaktivovat detekci verze", "disableVersionDetection": "Deaktivovat detekci verze",
"noVersionDetectionExplanation": "Tato možnost by měla být použita pouze u aplikace, kde detekce verzí nefunguje správně.", "noVersionDetectionExplanation": "Tato možnost by měla být použita pouze u aplikace, kde detekce verzí nefunguje správně.",
"downloadingX": "Stáhnout {}", "downloadingX": "Stáhnout {}",
"downloadX": "Stáhnout {}",
"downloadedX": "Staženo {}",
"releaseAsset": "Vydání aktiva",
"downloadNotifDescription": "Informuje uživatele o průběhu stahování aplikace", "downloadNotifDescription": "Informuje uživatele o průběhu stahování aplikace",
"noAPKFound": "Žádná APK nebyla nalezena", "noAPKFound": "Žádná APK nebyla nalezena",
"noVersionDetection": "Žádná detekce verze", "noVersionDetection": "Žádná detekce verze",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Odhadnout novější verzi na základě prvních třiceti číslic kontrolního součtu adresy URL APK, pokud není podporována jinak", "supportFixedAPKURL": "Odhadnout novější verzi na základě prvních třiceti číslic kontrolního součtu adresy URL APK, pokud není podporována jinak",
"selectX": "Vybrat {}", "selectX": "Vybrat {}",
"parallelDownloads": "Povolit souběžné stahování", "parallelDownloads": "Povolit souběžné stahování",
"installMethod": "Metoda instalace", "useShizuku": "K instalaci použijte Shizuku nebo Sui",
"normal": "Normální",
"root": "Správce",
"shizukuBinderNotFound": "Shizuku neběží", "shizukuBinderNotFound": "Shizuku neběží",
"shizukuOld": "Stará verze Shizuku (<11) - aktualizujte ji",
"shizukuOldAndroidWithADB": "Shizuku běží na Androidu < 8.1 s ADB - aktualizujte Android nebo místo toho použijte Sui",
"shizukuPretendToBeGooglePlay": "Nastavení Google Play jako zdroje instalace (pokud se používá Shizuku)",
"useSystemFont": "Použít systémové písmo", "useSystemFont": "Použít systémové písmo",
"systemFontError": "Chyba při načítání systémového písma: {}",
"useVersionCodeAsOSVersion": "Použít kód verze aplikace jako verzi zjištěnou OS", "useVersionCodeAsOSVersion": "Použít kód verze aplikace jako verzi zjištěnou OS",
"requestHeader": "Hlavička požadavku", "requestHeader": "Hlavička požadavku",
"useLatestAssetDateAsReleaseDate": "Použít poslední nahrané dílo jako datum vydání", "useLatestAssetDateAsReleaseDate": "Použít poslední nahrané dílo jako datum vydání",
@ -301,6 +310,8 @@
"badDownload": "APK nelze analyzovat (nekompatibilní nebo částečné stažení)", "badDownload": "APK nelze analyzovat (nekompatibilní nebo částečné stažení)",
"beforeNewInstallsShareToAppVerifier": "Sdílení nových aplikací s aplikací AppVerifier (pokud je k dispozici)", "beforeNewInstallsShareToAppVerifier": "Sdílení nových aplikací s aplikací AppVerifier (pokud je k dispozici)",
"appVerifierInstructionToast": "Sdílejte do aplikace AppVerifier a po dokončení se sem vraťte.", "appVerifierInstructionToast": "Sdílejte do aplikace AppVerifier a po dokončení se sem vraťte.",
"wiki": "Nápověda/Wiki",
"crowdsourcedConfigsLabel": "Konfigurace aplikací s využitím crowdsourcingu (použití na vlastní nebezpečí)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Odstranit Apku?", "one": "Odstranit Apku?",
"other": "Odstranit Apky?" "other": "Odstranit Apky?"
@ -349,6 +360,10 @@
"one": "{} a 1 další aplikace mají aktualizace.", "one": "{} a 1 další aplikace mají aktualizace.",
"other": "{} a {} další aplikace byly aktualizovány." "other": "{} a {} další aplikace byly aktualizovány."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Nepodařilo se aktualizovat {} a 1 další aplikaci.",
"other": "Nepodařilo se aktualizovat {} a {} další aplikace."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} a 1 další aplikace možno aktualizovat", "one": "{} a 1 další aplikace možno aktualizovat",
"other": "{} a {} další aplikace mohou být aktualizovány." "other": "{} a {} další aplikace mohou být aktualizovány."

View File

@ -19,9 +19,12 @@
"noDescription": "Keine Beschreibung", "noDescription": "Keine Beschreibung",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"continue": "Weiter", "continue": "Weiter",
"requiredInBrackets": "(Benötigt)", "requiredInBrackets": "(wird benötigt)",
"dropdownNoOptsError": "FEHLER: DROPDOWN MUSS MINDESTENS EINE OPTION HABEN", "dropdownNoOptsError": "FEHLER: DROPDOWN MUSS MINDESTENS EINE OPTION HABEN",
"colour": "Farbe", "colour": "Farbe",
"standard": "Standard",
"custom": "Benutzerdefiniert",
"useMaterialYou": "Verwende Material You",
"githubStarredRepos": "GitHub Starred Repos", "githubStarredRepos": "GitHub Starred Repos",
"uname": "Benutzername", "uname": "Benutzername",
"wrongArgNum": "Falsche Anzahl von Argumenten (Parametern) übermittelt", "wrongArgNum": "Falsche Anzahl von Argumenten (Parametern) übermittelt",
@ -110,6 +113,7 @@
"dark": "Dunkel", "dark": "Dunkel",
"light": "Hell", "light": "Hell",
"followSystem": "System folgen", "followSystem": "System folgen",
"followSystemThemeExplanation": "Das Folgen des Systemthemes ist unter Android <10 nur mit Hilfe von Drittanbieteranwendungen möglich",
"useBlackTheme": "Verwende Pure Black Dark Theme", "useBlackTheme": "Verwende Pure Black Dark Theme",
"appSortBy": "App sortieren nach", "appSortBy": "App sortieren nach",
"authorName": "Autor/Name", "authorName": "Autor/Name",
@ -143,8 +147,10 @@
"noNewUpdates": "Keine neuen Aktualisierungen.", "noNewUpdates": "Keine neuen Aktualisierungen.",
"xHasAnUpdate": "{} hat eine Aktualisierung.", "xHasAnUpdate": "{} hat eine Aktualisierung.",
"appsUpdated": "Apps aktualisiert", "appsUpdated": "Apps aktualisiert",
"appsNotUpdated": "Aktualisierung der Anwendungen fehlgeschlagen",
"appsUpdatedNotifDescription": "Benachrichtigt den Benutzer, dass Aktualisierungen für eine oder mehrere Apps im Hintergrund durchgeführt wurden", "appsUpdatedNotifDescription": "Benachrichtigt den Benutzer, dass Aktualisierungen für eine oder mehrere Apps im Hintergrund durchgeführt wurden",
"xWasUpdatedToY": "{} wurde auf {} aktualisiert.", "xWasUpdatedToY": "{} wurde auf {} aktualisiert.",
"xWasNotUpdatedToY": "Die Aktualisierung von {} auf {} ist fehlgeschlagen.",
"errorCheckingUpdates": "Fehler beim Prüfen auf Aktualisierungen", "errorCheckingUpdates": "Fehler beim Prüfen auf Aktualisierungen",
"errorCheckingUpdatesNotifDescription": "Eine Benachrichtigung, die angezeigt wird, wenn die Prüfung der Hintergrundaktualisierung fehlschlägt", "errorCheckingUpdatesNotifDescription": "Eine Benachrichtigung, die angezeigt wird, wenn die Prüfung der Hintergrundaktualisierung fehlschlägt",
"appsRemoved": "Apps entfernt", "appsRemoved": "Apps entfernt",
@ -183,6 +189,9 @@
"disableVersionDetection": "Versionsermittlung deaktivieren", "disableVersionDetection": "Versionsermittlung deaktivieren",
"noVersionDetectionExplanation": "Diese Option sollte nur für Apps verwendet werden, bei denen die Versionserkennung nicht korrekt funktioniert.", "noVersionDetectionExplanation": "Diese Option sollte nur für Apps verwendet werden, bei denen die Versionserkennung nicht korrekt funktioniert.",
"downloadingX": "Lade {} herunter", "downloadingX": "Lade {} herunter",
"downloadX": "{} herunterladen",
"downloadedX": "{} heruntergeladen",
"releaseAsset": "release Asset",
"downloadNotifDescription": "Benachrichtigt den Nutzer über den Fortschritt beim Herunterladen einer App", "downloadNotifDescription": "Benachrichtigt den Nutzer über den Fortschritt beim Herunterladen einer App",
"noAPKFound": "Keine APK gefunden", "noAPKFound": "Keine APK gefunden",
"noVersionDetection": "Keine Versionserkennung", "noVersionDetection": "Keine Versionserkennung",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "neuere Version anhand der ersten dreißig Zahlen der Checksumme der APK URL erraten, wenn anderweitig nicht unterstützt", "supportFixedAPKURL": "neuere Version anhand der ersten dreißig Zahlen der Checksumme der APK URL erraten, wenn anderweitig nicht unterstützt",
"selectX": "Wähle {}", "selectX": "Wähle {}",
"parallelDownloads": "Erlaube parallele Downloads", "parallelDownloads": "Erlaube parallele Downloads",
"installMethod": "Installationsmethode", "useShizuku": "Verwenden Sie Shizuku oder Sui zur Installation",
"normal": "Normal",
"root": "Root",
"shizukuBinderNotFound": "Kompatibler Shizukudienst wurde nicht gefunden", "shizukuBinderNotFound": "Kompatibler Shizukudienst wurde nicht gefunden",
"shizukuOld": "Alte Shizuku-Version (<11) - aktualisieren Sie sie",
"shizukuOldAndroidWithADB": "Shizuku läuft auf Android < 8.1 mit ADB - aktualisieren Sie Android oder verwenden Sie stattdessen Sui",
"shizukuPretendToBeGooglePlay": "Google Play als Installationsquelle festlegen (wenn Shizuku verwendet wird)",
"useSystemFont": "Verwende die Systemschriftart", "useSystemFont": "Verwende die Systemschriftart",
"systemFontError": "Fehler beim Laden der Systemschriftart: {}",
"useVersionCodeAsOSVersion": "Verwende die Appversion als erkannte Version vom Betriebssystem", "useVersionCodeAsOSVersion": "Verwende die Appversion als erkannte Version vom Betriebssystem",
"requestHeader": "Request Header", "requestHeader": "Request Header",
"useLatestAssetDateAsReleaseDate": "Den letzten Asset-Upload als Veröffentlichungsdatum verwenden", "useLatestAssetDateAsReleaseDate": "Den letzten Asset-Upload als Veröffentlichungsdatum verwenden",
@ -301,6 +310,8 @@
"badDownload": "Die APK konnte nicht geparst werden (inkompatibler oder teilweiser Download)", "badDownload": "Die APK konnte nicht geparst werden (inkompatibler oder teilweiser Download)",
"beforeNewInstallsShareToAppVerifier": "Neue Apps mit AppVerifier teilen (falls verfügbar)", "beforeNewInstallsShareToAppVerifier": "Neue Apps mit AppVerifier teilen (falls verfügbar)",
"appVerifierInstructionToast": "Geben Sie die Daten an AppVerifier weiter und kehren Sie dann hierher zurück, wenn Sie fertig sind.", "appVerifierInstructionToast": "Geben Sie die Daten an AppVerifier weiter und kehren Sie dann hierher zurück, wenn Sie fertig sind.",
"wiki": "Hilfe/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (Verwendung auf eigene Gefahr)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App entfernen?", "one": "App entfernen?",
"other": "Apps entfernen?" "other": "Apps entfernen?"
@ -349,6 +360,10 @@
"one": "{} und 1 weitere Anwendung wurden aktualisiert.", "one": "{} und 1 weitere Anwendung wurden aktualisiert.",
"other": "{} und {} weitere Anwendungen wurden aktualisiert." "other": "{} und {} weitere Anwendungen wurden aktualisiert."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Aktualisierung fehlgeschlagen {} und 1 weitere Anwendung.",
"other": "Die Aktualisierung von {} und {} weiteren Anwendungen ist fehlgeschlagen."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} und 1 weitere Anwendung wurden möglicherweise aktualisiert.", "one": "{} und 1 weitere Anwendung wurden möglicherweise aktualisiert.",
"other": "{} und {} weitere Anwendungen wurden möglicherweise aktualisiert." "other": "{} und {} weitere Anwendungen wurden möglicherweise aktualisiert."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(Required)", "requiredInBrackets": "(Required)",
"dropdownNoOptsError": "ERROR: DROPDOWN MUST HAVE AT LEAST ONE OPT", "dropdownNoOptsError": "ERROR: DROPDOWN MUST HAVE AT LEAST ONE OPT",
"colour": "Colour", "colour": "Colour",
"standard": "Standard",
"custom": "Custom",
"useMaterialYou": "Use Material You",
"githubStarredRepos": "GitHub Starred Repos", "githubStarredRepos": "GitHub Starred Repos",
"uname": "Username", "uname": "Username",
"wrongArgNum": "Wrong number of arguments provided", "wrongArgNum": "Wrong number of arguments provided",
@ -110,6 +113,7 @@
"dark": "Dark", "dark": "Dark",
"light": "Light", "light": "Light",
"followSystem": "Follow System", "followSystem": "Follow System",
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications",
"useBlackTheme": "Use pure black dark theme", "useBlackTheme": "Use pure black dark theme",
"appSortBy": "App Sort By", "appSortBy": "App Sort By",
"authorName": "Author/Name", "authorName": "Author/Name",
@ -143,8 +147,10 @@
"noNewUpdates": "No new updates.", "noNewUpdates": "No new updates.",
"xHasAnUpdate": "{} has an update.", "xHasAnUpdate": "{} has an update.",
"appsUpdated": "Apps Updated", "appsUpdated": "Apps Updated",
"appsNotUpdated": "Failed to update applications",
"appsUpdatedNotifDescription": "Notifies the user that updates to one or more Apps were applied in the background", "appsUpdatedNotifDescription": "Notifies the user that updates to one or more Apps were applied in the background",
"xWasUpdatedToY": "{} was updated to {}.", "xWasUpdatedToY": "{} was updated to {}.",
"xWasNotUpdatedToY": "Failed to update {} to {}.",
"errorCheckingUpdates": "Error Checking for Updates", "errorCheckingUpdates": "Error Checking for Updates",
"errorCheckingUpdatesNotifDescription": "A notification that shows when background update checking fails", "errorCheckingUpdatesNotifDescription": "A notification that shows when background update checking fails",
"appsRemoved": "Apps Removed", "appsRemoved": "Apps Removed",
@ -183,6 +189,9 @@
"disableVersionDetection": "Disable Version Detection", "disableVersionDetection": "Disable Version Detection",
"noVersionDetectionExplanation": "This option should only be used for Apps where version detection does not work correctly.", "noVersionDetectionExplanation": "This option should only be used for Apps where version detection does not work correctly.",
"downloadingX": "Downloading {}", "downloadingX": "Downloading {}",
"downloadX": "Download {}",
"downloadedX": "Downloaded {}",
"releaseAsset": "Release Asset",
"downloadNotifDescription": "Notifies the user of the progress in downloading an App", "downloadNotifDescription": "Notifies the user of the progress in downloading an App",
"noAPKFound": "No APK found", "noAPKFound": "No APK found",
"noVersionDetection": "No version detection", "noVersionDetection": "No version detection",
@ -250,7 +259,7 @@
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi", "bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK", "autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
"versionExtractionRegEx": "Version String Extraction RegEx", "versionExtractionRegEx": "Version String Extraction RegEx",
"matchGroupToUse": "Match Group to Use for Version String Extraction Regex", "matchGroupToUse": "Match Group to Use for Version String Extraction RegEx",
"highlightTouchTargets": "Highlight less obvious touch targets", "highlightTouchTargets": "Highlight less obvious touch targets",
"pickExportDir": "Pick Export Directory", "pickExportDir": "Pick Export Directory",
"autoExportOnChanges": "Auto-export on changes", "autoExportOnChanges": "Auto-export on changes",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Support fixed APK URLs", "supportFixedAPKURL": "Support fixed APK URLs",
"selectX": "Select {}", "selectX": "Select {}",
"parallelDownloads": "Allow parallel downloads", "parallelDownloads": "Allow parallel downloads",
"installMethod": "Installation method", "useShizuku": "Use Shizuku or Sui to install",
"normal": "Normal", "shizukuBinderNotFound": "Shizuku service not running",
"root": "Root", "shizukuOld": "Old Shizuku version (<11) - update it",
"shizukuBinderNotFound": "Сompatible Shizuku service wasn't found", "shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead",
"shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)",
"useSystemFont": "Use the system font", "useSystemFont": "Use the system font",
"systemFontError": "Error loading the system font: {}",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date", "useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
@ -301,6 +310,8 @@
"badDownload": "The APK could not be parsed (incompatible or partial download)", "badDownload": "The APK could not be parsed (incompatible or partial download)",
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", "beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)",
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", "appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.",
"wiki": "Help/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remove App?", "one": "Remove App?",
"other": "Remove Apps?" "other": "Remove Apps?"
@ -349,6 +360,10 @@
"one": "{} and 1 more app was updated.", "one": "{} and 1 more app was updated.",
"other": "{} and {} more apps were updated." "other": "{} and {} more apps were updated."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Failed to update {} and 1 more app.",
"other": "Failed to update {} and {} more apps."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} and 1 more app may have been updated.", "one": "{} and 1 more app may have been updated.",
"other": "{} and {} more apps may have been updated." "other": "{} and {} more apps may have been updated."

View File

@ -1,10 +1,10 @@
{ {
"invalidURLForSource": "El URL de la aplicación {} no es válido", "invalidURLForSource": "El URL de la aplicación {} no es válido",
"noReleaseFound": "No se ha podido encontrar una versión válida", "noReleaseFound": "No se ha encontrado una versión válida",
"noVersionFound": "No se ha podido determinar la versión", "noVersionFound": "No se ha podido determinar la versión",
"urlMatchesNoSource": "El URL no coincide con ninguna fuente conocida", "urlMatchesNoSource": "El URL no coincide con ninguna fuente conocida",
"cantInstallOlderVersion": "No se puede instalar una versión previa de la aplicación", "cantInstallOlderVersion": "No se puede instalar una versión previa de la aplicación",
"appIdMismatch": "El id. del paquete descargado no coincide con la ID de la aplicación instalada", "appIdMismatch": "El ID del paquete descargado no coincide con el ID de la aplicación instalada",
"functionNotImplemented": "Esta clase no ha implementado esta función", "functionNotImplemented": "Esta clase no ha implementado esta función",
"placeholder": "Espacio reservado", "placeholder": "Espacio reservado",
"someErrors": "Han ocurrido algunos errores", "someErrors": "Han ocurrido algunos errores",
@ -22,14 +22,17 @@
"requiredInBrackets": "(Requerido)", "requiredInBrackets": "(Requerido)",
"dropdownNoOptsError": "ERROR: EL DESPLEGABLE DEBE TENER AL MENOS UNA OPCIÓN", "dropdownNoOptsError": "ERROR: EL DESPLEGABLE DEBE TENER AL MENOS UNA OPCIÓN",
"colour": "Color", "colour": "Color",
"standard": "Estándar",
"custom": "A medida",
"useMaterialYou": "Use 'Material You'",
"githubStarredRepos": "Repositorios favoritos en GitHub", "githubStarredRepos": "Repositorios favoritos en GitHub",
"uname": "Nombre de usuario", "uname": "Nombre de usuario",
"wrongArgNum": "Número de argumentos provistos inválido", "wrongArgNum": "Número de argumentos provistos inválido",
"xIsTrackOnly": "{} es de 'sólo seguimiento'", "xIsTrackOnly": "{} es de 'sólo seguimiento'",
"source": "Origen", "source": "Origen",
"app": "Aplicación", "app": "Aplicación",
"appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son de 'solo seguimiento'.", "appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para seguimiento.",
"youPickedTrackOnly": "Debe seleccionar la opción de 'solo seguimiento'.", "youPickedTrackOnly": "Debe seleccionar la opción de 'solo para seguimiento'.",
"trackOnlyAppDescription": "Se hará el seguimiento de actualizaciones para la aplicación, pero Obtainium no será capaz de descargar o actualizarla.", "trackOnlyAppDescription": "Se hará el seguimiento de actualizaciones para la aplicación, pero Obtainium no será capaz de descargar o actualizarla.",
"cancelled": "Cancelado", "cancelled": "Cancelado",
"appAlreadyAdded": "Aplicación añadida anteriormente", "appAlreadyAdded": "Aplicación añadida anteriormente",
@ -42,14 +45,14 @@
"search": "Buscar", "search": "Buscar",
"additionalOptsFor": "Opciones adicionales para {}", "additionalOptsFor": "Opciones adicionales para {}",
"supportedSources": "Fuentes admitidas", "supportedSources": "Fuentes admitidas",
"trackOnlyInBrackets": "(Solo seguimiento)", "trackOnlyInBrackets": "(Solo para seguimiento)",
"searchableInBrackets": "(permite búsqueda)", "searchableInBrackets": "(permite búsqueda)",
"appsString": "Aplicaciones", "appsString": "Aplicaciones",
"noApps": "Sin Aplicaciones", "noApps": "Sin Aplicaciones",
"noAppsForFilter": "Sin aplicaciones para filtrar", "noAppsForFilter": "Sin aplicaciones para filtrar",
"byX": "por: {}", "byX": "por: {}",
"percentProgress": "Progreso: {} %", "percentProgress": "Progreso: {} %",
"pleaseWait": "Espere un momento", "pleaseWait": "Espere...",
"updateAvailable": "Actualización disponible", "updateAvailable": "Actualización disponible",
"notInstalled": "No instalado", "notInstalled": "No instalado",
"pseudoVersion": "pseudoversión", "pseudoVersion": "pseudoversión",
@ -60,7 +63,7 @@
"removeSelectedApps": "Eliminar aplicaciones seleccionadas", "removeSelectedApps": "Eliminar aplicaciones seleccionadas",
"updateX": "Actualizar {}", "updateX": "Actualizar {}",
"installX": "Instalar {}", "installX": "Instalar {}",
"markXTrackOnlyAsUpdated": "Marcar {}\n(Solo seguimiento)\ncomo actualizada", "markXTrackOnlyAsUpdated": "Marcar {}\n(solo para seguimiento)\ncomo actualizada",
"changeX": "Cambiar {}", "changeX": "Cambiar {}",
"installUpdateApps": "Instalar/actualizar aplicaciones", "installUpdateApps": "Instalar/actualizar aplicaciones",
"installUpdateSelectedApps": "Instalar/actualizar aplicaciones seleccionadas", "installUpdateSelectedApps": "Instalar/actualizar aplicaciones seleccionadas",
@ -97,7 +100,7 @@
"appURLList": "Lista de URL de aplicaciones", "appURLList": "Lista de URL de aplicaciones",
"line": "Línea", "line": "Línea",
"searchX": "Buscar {}", "searchX": "Buscar {}",
"noResults": "No se encontró ningún resultado", "noResults": "No se ha encontrado ningún resultado",
"importX": "Importar desde {}", "importX": "Importar desde {}",
"importedAppsIdDisclaimer": "Las aplicaciones importadas podrían mostrarse incorrectamente como «No instalada».\nPara solucionarlo, reinstálelas a través de Obtainium.\nEsto no debería afectar a los datos de las aplicaciones.\n\nSolo afecta a los URL y a los métodos de importación mediante terceros.", "importedAppsIdDisclaimer": "Las aplicaciones importadas podrían mostrarse incorrectamente como «No instalada».\nPara solucionarlo, reinstálelas a través de Obtainium.\nEsto no debería afectar a los datos de las aplicaciones.\n\nSolo afecta a los URL y a los métodos de importación mediante terceros.",
"importErrors": "Errores de Importación", "importErrors": "Errores de Importación",
@ -110,6 +113,7 @@
"dark": "Oscuro", "dark": "Oscuro",
"light": "Claro", "light": "Claro",
"followSystem": "Seguir al sistema", "followSystem": "Seguir al sistema",
"followSystemThemeExplanation": "Seguir el tema del sistema sólo es posible utilizando aplicaciones de terceros",
"useBlackTheme": "Negro puro en tema oscuro", "useBlackTheme": "Negro puro en tema oscuro",
"appSortBy": "Ordenar aplicaciones por", "appSortBy": "Ordenar aplicaciones por",
"authorName": "Autor/nombre", "authorName": "Autor/nombre",
@ -143,8 +147,10 @@
"noNewUpdates": "No hay nuevas actualizaciones.", "noNewUpdates": "No hay nuevas actualizaciones.",
"xHasAnUpdate": "{} tiene una actualización.", "xHasAnUpdate": "{} tiene una actualización.",
"appsUpdated": "Aplicaciones actualizadas", "appsUpdated": "Aplicaciones actualizadas",
"appsNotUpdated": "Error al actualizar las aplicaciones",
"appsUpdatedNotifDescription": "Notifica al usuario de que una o más aplicaciones han sido actualizadas en segundo plano", "appsUpdatedNotifDescription": "Notifica al usuario de que una o más aplicaciones han sido actualizadas en segundo plano",
"xWasUpdatedToY": "{} ha sido actualizada a {}.", "xWasUpdatedToY": "{} ha sido actualizada a {}.",
"xWasNotUpdatedToY": "Error al actualizar {} a {}.",
"errorCheckingUpdates": "Error al buscar actualizaciones", "errorCheckingUpdates": "Error al buscar actualizaciones",
"errorCheckingUpdatesNotifDescription": "Una notificación que muestra cuándo la comprobación de actualizaciones en segundo plano falla", "errorCheckingUpdatesNotifDescription": "Una notificación que muestra cuándo la comprobación de actualizaciones en segundo plano falla",
"appsRemoved": "Aplicaciones eliminadas", "appsRemoved": "Aplicaciones eliminadas",
@ -170,9 +176,9 @@
"fdroid": "Repositorio oficial F-Droid", "fdroid": "Repositorio oficial F-Droid",
"appIdOrName": "ID o Nombre de la Aplicación", "appIdOrName": "ID o Nombre de la Aplicación",
"appId": "ID de la Aplicación", "appId": "ID de la Aplicación",
"appWithIdOrNameNotFound": "No se han encontrado aplicaciones con esa ID o nombre", "appWithIdOrNameNotFound": "No se han encontrado aplicaciones con ese ID o nombre",
"reposHaveMultipleApps": "Los repositorios pueden contener varias aplicaciones", "reposHaveMultipleApps": "Los repositorios pueden contener varias aplicaciones",
"fdroidThirdPartyRepo": "Repositorio de tercera parte F-Droid", "fdroidThirdPartyRepo": "Repositorio de terceros F-Droid",
"steamMobile": "Steam para móviles", "steamMobile": "Steam para móviles",
"steamChat": "Chat de Steam", "steamChat": "Chat de Steam",
"install": "Instalar", "install": "Instalar",
@ -183,8 +189,11 @@
"disableVersionDetection": "Desactivar la detección de versiones", "disableVersionDetection": "Desactivar la detección de versiones",
"noVersionDetectionExplanation": "Esta opción solo se debe usar en aplicaciones en las que la deteción de versiones pueda que no funcionar correctamente.", "noVersionDetectionExplanation": "Esta opción solo se debe usar en aplicaciones en las que la deteción de versiones pueda que no funcionar correctamente.",
"downloadingX": "Descargando {}", "downloadingX": "Descargando {}",
"downloadX": "Descargar {}",
"downloadedX": "Descargado {}",
"releaseAsset": "Recurso publicado",
"downloadNotifDescription": "Notifica al usuario del progreso de descarga de una aplicación", "downloadNotifDescription": "Notifica al usuario del progreso de descarga de una aplicación",
"noAPKFound": "No se encontró el paquete de instalación APK", "noAPKFound": "No se ha encontrado el paquete de instalación APK",
"noVersionDetection": "Sin detección de versiones", "noVersionDetection": "Sin detección de versiones",
"categorize": "Catogorizar", "categorize": "Catogorizar",
"categories": "Categorías", "categories": "Categorías",
@ -196,7 +205,7 @@
"addCategory": "Añadir categoría", "addCategory": "Añadir categoría",
"label": "Nombre", "label": "Nombre",
"language": "Idioma", "language": "Idioma",
"copiedToClipboard": "Se copió en el portapapeles", "copiedToClipboard": "Copiado en el portapapeles",
"storagePermissionDenied": "Permiso de almacenamiento rechazado", "storagePermissionDenied": "Permiso de almacenamiento rechazado",
"selectedCategorizeWarning": "Esto reemplazará cualquier ajuste de categoría para las aplicaciones seleccionadas.", "selectedCategorizeWarning": "Esto reemplazará cualquier ajuste de categoría para las aplicaciones seleccionadas.",
"filterAPKsByRegEx": "Filtrar por APK", "filterAPKsByRegEx": "Filtrar por APK",
@ -213,16 +222,16 @@
"standardVersionDetection": "Por versión", "standardVersionDetection": "Por versión",
"groupByCategory": "Agrupar por categoría", "groupByCategory": "Agrupar por categoría",
"autoApkFilterByArch": "Filtrar APK por arquitectura del procesador (si es posible)", "autoApkFilterByArch": "Filtrar APK por arquitectura del procesador (si es posible)",
"overrideSource": "Anular fuente", "overrideSource": "Forzar desde la fuente",
"dontShowAgain": "No mostrar de nuevo", "dontShowAgain": "No mostrar de nuevo",
"dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps en 'solo seguimiento'", "dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps 'solo para seguimiento",
"dontShowAPKOriginWarnings": "No mostrar avisos sobre las fuentes de las APKs", "dontShowAPKOriginWarnings": "No mostrar avisos sobre las fuentes de las APKs",
"moveNonInstalledAppsToBottom": "Mover Apps no instaladas al final", "moveNonInstalledAppsToBottom": "Mover apps no instaladas al final",
"gitlabPATLabel": "Token de acceso personal a GitLab", "gitlabPATLabel": "Token de acceso personal a GitLab",
"about": "Acerca", "about": "Acerca",
"requiresCredentialsInSettings": "{}: Esto requiere credenciales adicionales (en ajustes)", "requiresCredentialsInSettings": "{}: Esto requiere credenciales adicionales (en ajustes)",
"checkOnStart": "Comprobar actualizaciones al inicio", "checkOnStart": "Comprobar actualizaciones al inicio",
"tryInferAppIdFromCode": "Intentar deducir la ID de la app por el código fuente", "tryInferAppIdFromCode": "Intentar deducir el ID de la app por el código fuente",
"removeOnExternalUninstall": "Auto eliminar apps desinstaladas externamente", "removeOnExternalUninstall": "Auto eliminar apps desinstaladas externamente",
"pickHighestVersionCode": "Auto selección de versión superior del paquete APK", "pickHighestVersionCode": "Auto selección de versión superior del paquete APK",
"checkUpdateOnDetailPage": "Comprobar actualizaciones al abrir detalles de la app", "checkUpdateOnDetailPage": "Comprobar actualizaciones al abrir detalles de la app",
@ -277,30 +286,32 @@
"checkingForUpdatesNotifChannel": "Buscando actualizaciones", "checkingForUpdatesNotifChannel": "Buscando actualizaciones",
"onlyCheckInstalledOrTrackOnlyApps": "Comprobar actualizaciones solo para apps instaladas o en seguimiento", "onlyCheckInstalledOrTrackOnlyApps": "Comprobar actualizaciones solo para apps instaladas o en seguimiento",
"supportFixedAPKURL": "Soporte para URLs fijas de APK", "supportFixedAPKURL": "Soporte para URLs fijas de APK",
"selectX": "Selecciona {}", "selectX": "Elija {}",
"parallelDownloads": "Permitir descargas paralelas", "parallelDownloads": "Permitir descargas paralelas",
"installMethod": "Método de instalación", "useShizuku": "Use Shizuku o Sui para instalar",
"normal": "Normal",
"root": "Raíz",
"shizukuBinderNotFound": "Shizuku no funciona", "shizukuBinderNotFound": "Shizuku no funciona",
"useSystemFont": "Usar la fuente de impresión del sistema", "shizukuOld": "Versión antigua de Shizuku (<11) - actualícela",
"systemFontError": "Error al cargar la fuente de impresión del sistema: {}", "shizukuOldAndroidWithADB": "Shizuku corriendo en Android < 8.1 con ADB - actualiza Android o usa Sui en su lugar",
"shizukuPretendToBeGooglePlay": "Establecer Google Play como fuente de instalación (si se usa Shizuku)",
"useSystemFont": "Usar fuente del sistema",
"useVersionCodeAsOSVersion": "Usar la versión de la aplicación como versión detectada por el sistema operativo", "useVersionCodeAsOSVersion": "Usar la versión de la aplicación como versión detectada por el sistema operativo",
"requestHeader": "Encabezado de solicitud", "requestHeader": "Encabezado de solicitud",
"useLatestAssetDateAsReleaseDate": "Usar la última carga de recursos como fecha de lanzamiento", "useLatestAssetDateAsReleaseDate": "Usar la última carga del recurso como fecha de lanzamiento",
"defaultPseudoVersioningMethod": "Método de pseudoversionado predeterminado", "defaultPseudoVersioningMethod": "Método de pseudoversionado predeterminado",
"partialAPKHash": "Hash de APK parcial", "partialAPKHash": "Hash de APK parcial",
"APKLinkHash": "Hash de enlace APK", "APKLinkHash": "Hash de enlace APK",
"directAPKLink": "Enlace APK directo", "directAPKLink": "Enlace APK directo",
"pseudoVersionInUse": "Se está utilizando una pseudoversión", "pseudoVersionInUse": "Se está usando una pseudoversión",
"installed": "Instalado", "installed": "Instalado",
"latest": "Versión más reciente", "latest": "Versión más reciente",
"invertRegEx": "Invertir expresión regular", "invertRegEx": "Invertir expresión regular",
"note": "Nota", "note": "Nota",
"selfHostedNote": "El desplegable «{}» puede utilizarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.", "selfHostedNote": "El desplegable «{}» puede usarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.",
"badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)", "badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)",
"beforeNewInstallsShareToAppVerifier": "Compartir nuevas aplicaciones con AppVerifier (si está disponible)", "beforeNewInstallsShareToAppVerifier": "Compartir nuevas aplicaciones con AppVerifier (si está disponible)",
"appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.", "appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.",
"wiki": "Ayuda/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "¿Eliminar aplicación?", "one": "¿Eliminar aplicación?",
"other": "¿Eliminar aplicaciones?" "other": "¿Eliminar aplicaciones?"
@ -349,6 +360,10 @@
"one": "{} y 1 aplicación más se han actualizado.", "one": "{} y 1 aplicación más se han actualizado.",
"other": "{} y {} aplicaciones más se han actualizado." "other": "{} y {} aplicaciones más se han actualizado."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Error al actualizar {} y 1 aplicación más.",
"other": "No se han podido actualizar {} y {} aplicaciones más."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} y 1 aplicación más podría haber sido actualizada.", "one": "{} y 1 aplicación más podría haber sido actualizada.",
"other": "{} y {} aplicaciones más podrían haber sido actualizadas." "other": "{} y {} aplicaciones más podrían haber sido actualizadas."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(ضروری)", "requiredInBrackets": "(ضروری)",
"dropdownNoOptsError": "خطا: کشویی باید حداقل یک گزینه داشته باشد", "dropdownNoOptsError": "خطا: کشویی باید حداقل یک گزینه داشته باشد",
"colour": "رنگ", "colour": "رنگ",
"standard": "Standard",
"custom": "Custom",
"useMaterialYou": "Use Material You",
"githubStarredRepos": "مخازن ستاره دار گیتهاب", "githubStarredRepos": "مخازن ستاره دار گیتهاب",
"uname": "نام کاربری", "uname": "نام کاربری",
"wrongArgNum": "تعداد آرگومان های ارائه شده اشتباه است", "wrongArgNum": "تعداد آرگومان های ارائه شده اشتباه است",
@ -110,6 +113,7 @@
"dark": "تاریک", "dark": "تاریک",
"light": "روشن", "light": "روشن",
"followSystem": "هماهنگ با سیستم", "followSystem": "هماهنگ با سیستم",
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications",
"useBlackTheme": "استفاده از تم تیره سیاه خالص", "useBlackTheme": "استفاده از تم تیره سیاه خالص",
"appSortBy": "مرتب سازی برنامه بر اساس", "appSortBy": "مرتب سازی برنامه بر اساس",
"authorName": "سازنده/اسم", "authorName": "سازنده/اسم",
@ -143,8 +147,10 @@
"noNewUpdates": "به روز رسانی جدیدی وجود ندارد.", "noNewUpdates": "به روز رسانی جدیدی وجود ندارد.",
"xHasAnUpdate": "{} یک به روز رسانی دارد.", "xHasAnUpdate": "{} یک به روز رسانی دارد.",
"appsUpdated": "برنامه ها به روز شدند", "appsUpdated": "برنامه ها به روز شدند",
"appsNotUpdated": "Failed to update applications",
"appsUpdatedNotifDescription": "به کاربر اطلاع می دهد که به روز رسانی یک یا چند برنامه در پس زمینه اعمال شده است", "appsUpdatedNotifDescription": "به کاربر اطلاع می دهد که به روز رسانی یک یا چند برنامه در پس زمینه اعمال شده است",
"xWasUpdatedToY": "{} به {} به روز شد.", "xWasUpdatedToY": "{} به {} به روز شد.",
"xWasNotUpdatedToY": "Failed to update {} to {}.",
"errorCheckingUpdates": "خطا در بررسی به‌روزرسانی‌ها", "errorCheckingUpdates": "خطا در بررسی به‌روزرسانی‌ها",
"errorCheckingUpdatesNotifDescription": "اعلانی که وقتی بررسی به‌روزرسانی پس‌زمینه ناموفق است نشان می‌دهد", "errorCheckingUpdatesNotifDescription": "اعلانی که وقتی بررسی به‌روزرسانی پس‌زمینه ناموفق است نشان می‌دهد",
"appsRemoved": "برنامه ها حذف شدند", "appsRemoved": "برنامه ها حذف شدند",
@ -183,6 +189,9 @@
"disableVersionDetection": "غیرفعال کردن تشخیص نسخه", "disableVersionDetection": "غیرفعال کردن تشخیص نسخه",
"noVersionDetectionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند.", "noVersionDetectionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند.",
"downloadingX": "در حال دانلود {}", "downloadingX": "در حال دانلود {}",
"downloadX": "Download {}",
"downloadedX": "Downloaded {}",
"releaseAsset": "Release Asset",
"downloadNotifDescription": "کاربر را از پیشرفت دانلود یک برنامه مطلع می کند", "downloadNotifDescription": "کاربر را از پیشرفت دانلود یک برنامه مطلع می کند",
"noAPKFound": "APK پیدا نشد فایل", "noAPKFound": "APK پیدا نشد فایل",
"noVersionDetection": "بدون تشخیص نسخه", "noVersionDetection": "بدون تشخیص نسخه",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "پشتیبانی از URL های APK ثابت", "supportFixedAPKURL": "پشتیبانی از URL های APK ثابت",
"selectX": "انتخاب کنید {}", "selectX": "انتخاب کنید {}",
"parallelDownloads": "اجازه دانلود موازی", "parallelDownloads": "اجازه دانلود موازی",
"installMethod": "روش نصب", "useShizuku": "Use Shizuku or Sui to install",
"normal": "طبیعی",
"root": "ریشه",
"shizukuBinderNotFound": "Shizuku در حال اجرا نیست", "shizukuBinderNotFound": "Shizuku در حال اجرا نیست",
"shizukuOld": "Old Shizuku version (<11) - update it",
"shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead",
"shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)",
"useSystemFont": "استفاده از فونت سیستم", "useSystemFont": "استفاده از فونت سیستم",
"systemFontError": "خطا در بارگیری فونت سیستم: {}",
"useVersionCodeAsOSVersion": "استفاده کد نسخه برنامه به جای نسخه شناسایی شده توسط سیستم عامل استفاده کنید", "useVersionCodeAsOSVersion": "استفاده کد نسخه برنامه به جای نسخه شناسایی شده توسط سیستم عامل استفاده کنید",
"requestHeader": "درخواست سطر بالایی", "requestHeader": "درخواست سطر بالایی",
"useLatestAssetDateAsReleaseDate": "استفاده از آخرین بارگذاری دارایی به عنوان تاریخ انتشار", "useLatestAssetDateAsReleaseDate": "استفاده از آخرین بارگذاری دارایی به عنوان تاریخ انتشار",
@ -301,6 +310,8 @@
"badDownload": "The APK could not be parsed (incompatible or partial download)", "badDownload": "The APK could not be parsed (incompatible or partial download)",
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", "beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)",
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", "appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.",
"wiki": "Help/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "برنامه حذف شود؟", "one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟" "other": "برنامه ها حذف شوند؟"
@ -349,6 +360,10 @@
"one": "{} و 1 برنامه دیگر به روز شدند.", "one": "{} و 1 برنامه دیگر به روز شدند.",
"other": "{} و {} برنامه دیگر به روز شدند." "other": "{} و {} برنامه دیگر به روز شدند."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Failed to update {} and 1 more app.",
"other": "Failed to update {} and {} more apps."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.", "one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.",
"other": "ممکن است {} و {} برنامه های دیگر به روز شده باشند." "other": "ممکن است {} و {} برنامه های دیگر به روز شده باشند."

View File

@ -1,7 +1,7 @@
{ {
"invalidURLForSource": "URL d'application {} invalide", "invalidURLForSource": "URL d'application {} invalide",
"noReleaseFound": "Impossible de trouver une version appropriée", "noReleaseFound": "Impossible de trouver une version adaptée",
"noVersionFound": "Impossible de déterminer la version de la version", "noVersionFound": "Impossible de déterminer la variante de la version",
"urlMatchesNoSource": "L'URL ne correspond pas à une source connue", "urlMatchesNoSource": "L'URL ne correspond pas à une source connue",
"cantInstallOlderVersion": "Impossible d'installer une ancienne version d'une application", "cantInstallOlderVersion": "Impossible d'installer une ancienne version d'une application",
"appIdMismatch": "L'ID de paquet téléchargé ne correspond pas à l'ID de l'application existante", "appIdMismatch": "L'ID de paquet téléchargé ne correspond pas à l'ID de l'application existante",
@ -22,6 +22,9 @@
"requiredInBrackets": "(Requis)", "requiredInBrackets": "(Requis)",
"dropdownNoOptsError": "ERREUR : LE DÉROULEMENT DOIT AVOIR AU MOINS UNE OPT", "dropdownNoOptsError": "ERREUR : LE DÉROULEMENT DOIT AVOIR AU MOINS UNE OPT",
"colour": "Couleur", "colour": "Couleur",
"standard": "Standard",
"custom": "Sur mesure",
"useMaterialYou": "Utiliser le matériel que vous",
"githubStarredRepos": "Dépôts étoilés GitHub", "githubStarredRepos": "Dépôts étoilés GitHub",
"uname": "Nom d'utilisateur", "uname": "Nom d'utilisateur",
"wrongArgNum": "Mauvais nombre d'arguments fournis", "wrongArgNum": "Mauvais nombre d'arguments fournis",
@ -43,7 +46,7 @@
"additionalOptsFor": "Options supplémentaires pour {}", "additionalOptsFor": "Options supplémentaires pour {}",
"supportedSources": "Sources prises en charge ", "supportedSources": "Sources prises en charge ",
"trackOnlyInBrackets": "(Suivi uniquement)", "trackOnlyInBrackets": "(Suivi uniquement)",
"searchableInBrackets": "(Recherchable)", "searchableInBrackets": "(Intérrogeable)",
"appsString": "Applications", "appsString": "Applications",
"noApps": "Aucune application", "noApps": "Aucune application",
"noAppsForFilter": "Aucune application pour le filtre", "noAppsForFilter": "Aucune application pour le filtre",
@ -51,7 +54,7 @@
"percentProgress": "Progrès: {}%", "percentProgress": "Progrès: {}%",
"pleaseWait": "Veuillez patienter", "pleaseWait": "Veuillez patienter",
"updateAvailable": "Mise à jour disponible", "updateAvailable": "Mise à jour disponible",
"notInstalled": "Pas installé", "notInstalled": "Non installé",
"pseudoVersion": "pseudo-version", "pseudoVersion": "pseudo-version",
"selectAll": "Tout sélectionner", "selectAll": "Tout sélectionner",
"deselectX": "Déselectionner {}", "deselectX": "Déselectionner {}",
@ -60,22 +63,22 @@
"removeSelectedApps": "Supprimer les applications sélectionnées", "removeSelectedApps": "Supprimer les applications sélectionnées",
"updateX": "Mise à jour {}", "updateX": "Mise à jour {}",
"installX": "Installer {}", "installX": "Installer {}",
"markXTrackOnlyAsUpdated": "Marquer {}\n(Suivi uniquement)\nas mis à jour", "markXTrackOnlyAsUpdated": "Marquer {}\n(Suivi uniquement)\n comme mis à jour",
"changeX": "Changer {}", "changeX": "Changer {}",
"installUpdateApps": "Installer/Mettre à jour les applications", "installUpdateApps": "Installer/Mettre à jour les applications",
"installUpdateSelectedApps": "Installer/Mettre à jour les applications sélectionnées", "installUpdateSelectedApps": "Installer/Mettre à jour les applications sélectionnées",
"markXSelectedAppsAsUpdated": "Marquer {} les applications sélectionnées comme mises à jour ?", "markXSelectedAppsAsUpdated": "Marquer {} les applications sélectionnées comme étant à jour ?",
"no": "Non", "no": "Non",
"yes": "Oui", "yes": "Oui",
"markSelectedAppsUpdated": "Marquer les applications sélectionnées comme mises à jour", "markSelectedAppsUpdated": "Marquer les applications sélectionnées comme étant à jour",
"pinToTop": "Épingler en haut", "pinToTop": "Épingler en haut",
"unpinFromTop": "Détacher du haut", "unpinFromTop": "Désépingler du haut",
"resetInstallStatusForSelectedAppsQuestion": "Réinitialiser ltat d'installation des applications sélectionnées ?", "resetInstallStatusForSelectedAppsQuestion": "Réinitialiser le statu d'installation des applications sélectionnées ?",
"installStatusOfXWillBeResetExplanation": "Ltat d'installation de toutes les applications sélectionnées sera réinitialisé.\n\nCela peut aider lorsque la version de l'application affichée dans Obtainium est incorrecte en raison d'échecs de mises à jour ou d'autres problèmes.", "installStatusOfXWillBeResetExplanation": "Le statu d'installation de toutes les applications sélectionnées sera réinitialisé.\n\nCela peut aider lorsque la version de l'application affichée dans Obtainium est incorrecte en raison d'échecs de mises à jour ou d'autres problèmes.",
"customLinkMessage": "Ces liens fonctionnent sur les appareils sur lesquels Obtenirium est installé", "customLinkMessage": "Ces liens fonctionnent sur les appareils sur lesquels Obtainium est installé",
"shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML", "shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML",
"shareSelectedAppURLs": "Partager les URL d'application sélectionnées", "shareSelectedAppURLs": "Partager les URL d'application sélectionnées",
"resetInstallStatus": "Réinitialiser le statut d'installation", "resetInstallStatus": "Réinitialiser le statu d'installation",
"more": "Plus", "more": "Plus",
"removeOutdatedFilter": "Supprimer le filtre d'application obsolète", "removeOutdatedFilter": "Supprimer le filtre d'application obsolète",
"showOutdatedOnly": "Afficher uniquement les applications obsolètes", "showOutdatedOnly": "Afficher uniquement les applications obsolètes",
@ -88,12 +91,12 @@
"importExport": "Importer/Exporter", "importExport": "Importer/Exporter",
"settings": "Paramètres", "settings": "Paramètres",
"exportedTo": "Exporté vers {}", "exportedTo": "Exporté vers {}",
"obtainiumExport": "Exportation d'Obtainium", "obtainiumExport": "Exporter d'Obtainium",
"invalidInput": "Entrée invalide", "invalidInput": "Entrée invalide",
"importedX": "Importé {}", "importedX": "Importé {}",
"obtainiumImport": "Importation d'Obtainium", "obtainiumImport": "Importer d'Obtainium",
"importFromURLList": "Importer à partir de la liste d'URL", "importFromURLList": "Importer à partir de la liste d'URL",
"searchQuery": "Requête de recherche", "searchQuery": "Requête",
"appURLList": "Liste d'URL d'application", "appURLList": "Liste d'URL d'application",
"line": "Queue", "line": "Queue",
"searchX": "Rechercher {}", "searchX": "Rechercher {}",
@ -110,14 +113,15 @@
"dark": "Sombre", "dark": "Sombre",
"light": "Clair", "light": "Clair",
"followSystem": "Suivre le système", "followSystem": "Suivre le système",
"useBlackTheme": "Utilisez le thème noir pur et sombre", "followSystemThemeExplanation": "Il n'est possible de suivre le thème du système qu'en utilisant des applications tierces.",
"useBlackTheme": "Utilisez le thème noir pur",
"appSortBy": "Applications triées par", "appSortBy": "Applications triées par",
"authorName": "Auteur/Nom", "authorName": "Auteur/Nom",
"nameAuthor": "Nom/Auteur", "nameAuthor": "Nom/Auteur",
"asAdded": "Comme ajouté", "asAdded": "Comme ajouté",
"appSortOrder": "Ordre de tri des applications", "appSortOrder": "Ordre de tri des applications",
"ascending": "Ascendant", "ascending": "Ascendant",
"descending": "Descendanr", "descending": "Descendant",
"bgUpdateCheckInterval": "Intervalle de vérification des mises à jour en arrière-plan", "bgUpdateCheckInterval": "Intervalle de vérification des mises à jour en arrière-plan",
"neverManualOnly": "Jamais - Manuel uniquement", "neverManualOnly": "Jamais - Manuel uniquement",
"appearance": "Apparence", "appearance": "Apparence",
@ -131,20 +135,22 @@
"close": "Fermer", "close": "Fermer",
"share": "Partager", "share": "Partager",
"appNotFound": "Application introuvable", "appNotFound": "Application introuvable",
"obtainiumExportHyphenatedLowercase": "exportation d'obtainium", "obtainiumExportHyphenatedLowercase": "exportation d'Obtainium",
"pickAnAPK": "Choisissez un APK", "pickAnAPK": "Choisissez un APK",
"appHasMoreThanOnePackage": "{} a plus d'un paquet :", "appHasMoreThanOnePackage": "{} a plus d'un paquet :",
"deviceSupportsXArch": "Votre appareil prend en charge l'architecture de processeur {}.", "deviceSupportsXArch": "Votre appareil prend en charge l'architecture CPU {}.",
"deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivantes :", "deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivantes :",
"warning": "Avertissement", "warning": "Avertissement",
"sourceIsXButPackageFromYPrompt": "La source de l'application est '{}' mais le paquet de version provient de '{}'. Continuer?", "sourceIsXButPackageFromYPrompt": "La source de l'application est '{}' mais la version du paquet provient de '{}'. Continuer?",
"updatesAvailable": "Mises à jour disponibles", "updatesAvailable": "Mises à jour disponibles",
"updatesAvailableNotifDescription": "Avertit l'utilisateur que des mises à jour sont disponibles pour une ou plusieurs applications suivies par Obtainium", "updatesAvailableNotifDescription": "Avertit l'utilisateur que des mises à jour sont disponibles pour une ou plusieurs applications suivies par Obtainium",
"noNewUpdates": "Aucune nouvelle mise à jour.", "noNewUpdates": "Aucune nouvelle mise à jour.",
"xHasAnUpdate": "{} a une mise à jour.", "xHasAnUpdate": "{} a une mise à jour.",
"appsUpdated": "Applications mises à jour", "appsUpdated": "Applications mises à jour",
"appsNotUpdated": "Échec de la mise à jour des applications",
"appsUpdatedNotifDescription": "Avertit l'utilisateur que les mises à jour d'une ou plusieurs applications ont été appliquées en arrière-plan", "appsUpdatedNotifDescription": "Avertit l'utilisateur que les mises à jour d'une ou plusieurs applications ont été appliquées en arrière-plan",
"xWasUpdatedToY": "{} a été mis à jour pour {}.", "xWasUpdatedToY": "{} a été mis à jour pour {}.",
"xWasNotUpdatedToY": "Échec de la mise à jour de {} vers {}.",
"errorCheckingUpdates": "Erreur lors de la vérification des mises à jour", "errorCheckingUpdates": "Erreur lors de la vérification des mises à jour",
"errorCheckingUpdatesNotifDescription": "Une notification qui s'affiche lorsque la vérification de la mise à jour en arrière-plan échoue", "errorCheckingUpdatesNotifDescription": "Une notification qui s'affiche lorsque la vérification de la mise à jour en arrière-plan échoue",
"appsRemoved": "Applications supprimées", "appsRemoved": "Applications supprimées",
@ -179,13 +185,16 @@
"markInstalled": "Marquer installée", "markInstalled": "Marquer installée",
"update": "Mettre à jour", "update": "Mettre à jour",
"markUpdated": "Marquer à jour", "markUpdated": "Marquer à jour",
"additionalOptions": "Options additionelles", "additionalOptions": "Options additionnelles",
"disableVersionDetection": "Désactiver la détection de version", "disableVersionDetection": "Désactiver la détection de version",
"noVersionDetectionExplanation": "Cette option ne doit être utilisée que pour les applications où la détection de version ne fonctionne pas correctement.", "noVersionDetectionExplanation": "Cette option ne doit être utilisée que pour les applications où la détection de version ne fonctionne pas correctement.",
"downloadingX": "Téléchargement {}", "downloadingX": "Téléchargement {}",
"downloadX": "Télécharger {}",
"downloadedX": "Téléchargé {}",
"releaseAsset": "Actif libéré",
"downloadNotifDescription": "Avertit l'utilisateur de la progression du téléchargement d'une application", "downloadNotifDescription": "Avertit l'utilisateur de la progression du téléchargement d'une application",
"noAPKFound": "Aucun APK trouvé", "noAPKFound": "Aucun APK trouvé",
"noVersionDetection": "Pas de détection de version", "noVersionDetection": "Aucune de détection de version",
"categorize": "Catégoriser", "categorize": "Catégoriser",
"categories": "Catégories", "categories": "Catégories",
"category": "Catégorie", "category": "Catégorie",
@ -198,13 +207,13 @@
"language": "Langue", "language": "Langue",
"copiedToClipboard": "Copié dans le presse-papier", "copiedToClipboard": "Copié dans le presse-papier",
"storagePermissionDenied": "Autorisation de stockage refusée", "storagePermissionDenied": "Autorisation de stockage refusée",
"selectedCategorizeWarning": "Cela remplacera tous les paramètres de catégorie existants pour les applications sélectionnées.", "selectedCategorizeWarning": "Cela remplacera toutes les catégorie définies pour les applications sélectionnées.",
"filterAPKsByRegEx": "Filtrer les APK par expression régulière", "filterAPKsByRegEx": "Filtrer les APK par expression régulière",
"removeFromObtainium": "Supprimer d'Obtainium", "removeFromObtainium": "Supprimer d'Obtainium",
"uninstallFromDevice": "Désinstaller de l'appareil", "uninstallFromDevice": "Désinstaller de l'appareil",
"onlyWorksWithNonVersionDetectApps": "Fonctionne uniquement pour les applications avec la détection de version désactivée.", "onlyWorksWithNonVersionDetectApps": "Fonctionne uniquement pour les applications avec la détection de version désactivée.",
"releaseDateAsVersion": "Utiliser la date de sortie comme version", "releaseDateAsVersion": "Utiliser la date de sortie comme version",
"releaseDateAsVersionExplanation": "Cette option ne doit être utilisée que pour les applications où la détection de version ne fonctionne pas correctement, mais une date de sortie est disponible.", "releaseDateAsVersionExplanation": "Cette option ne doit être utilisée que pour les applications où la détection de version ne fonctionne pas correctement, mais dont une date de sortie est disponible.",
"changes": "Changements", "changes": "Changements",
"releaseDate": "Date de sortie", "releaseDate": "Date de sortie",
"importFromURLsInFile": "Importer à partir d'URL dans un fichier (comme OPML)", "importFromURLsInFile": "Importer à partir d'URL dans un fichier (comme OPML)",
@ -212,59 +221,59 @@
"versionDetection": "Détection des versions", "versionDetection": "Détection des versions",
"standardVersionDetection": "Détection de version standard", "standardVersionDetection": "Détection de version standard",
"groupByCategory": "Regrouper par catégorie", "groupByCategory": "Regrouper par catégorie",
"autoApkFilterByArch": "Essayez de filtrer les APK par architecture CPU si possible", "autoApkFilterByArch": "Si possible, essayez de filtrer les APK par architecture CPU",
"overrideSource": "Remplacer la source", "overrideSource": "Remplacer la source",
"dontShowAgain": "Ne montre plus ça", "dontShowAgain": "Ne plus montrer",
"dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning", "dontShowTrackOnlyWarnings": "Ne pas afficher l'avertissement 'Track-Only'",
"dontShowAPKOriginWarnings": "Ne pas afficher les avertissements sur l'origine de l'APK", "dontShowAPKOriginWarnings": "Ne pas afficher les avertissements sur l'origine de l'APK",
"moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications", "moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications",
"gitlabPATLabel": "Jeton d'accès personnel GitLab", "gitlabPATLabel": "Jeton d'accès personnel GitLab",
"about": "À propos de", "about": "À propos de",
"requiresCredentialsInSettings": "{}: This needs additional credentials (in Settings)", "requiresCredentialsInSettings": "{}: Cela nécessite des identifiants supplémentaires (dans Paramètres)",
"checkOnStart": "Vérifier les mises à jour au démarrage", "checkOnStart": "Vérifier les mises à jour au démarrage",
"tryInferAppIdFromCode": "Essayez de déduire l'ID de l'application à partir du code source", "tryInferAppIdFromCode": "Essayez de déduire l'ID de l'application à partir du code source",
"removeOnExternalUninstall": "Supprimer automatiquement les applications désinstallées en externe", "removeOnExternalUninstall": "Supprimer automatiquement les applications désinstallées en externe",
"pickHighestVersionCode": "Sélectionner automatiquement le code APK de la version la plus élevée", "pickHighestVersionCode": "Sélectionner automatiquement le code de version de l'APK la plus élevée",
"checkUpdateOnDetailPage": "Vérifier les mises à jour lors de l'ouverture d'une page de détails d'application", "checkUpdateOnDetailPage": "Vérifier les mises à jour lors de l'ouverture de la page détaillée d'une application",
"disablePageTransitions": "Désactiver les animations de transition de page", "disablePageTransitions": "Désactiver les animations de transition de page",
"reversePageTransitions": "Animations de transition de page inversée", "reversePageTransitions": "Inverser les animations de transition de page",
"minStarCount": "Nombre minimum d'étoiles", "minStarCount": "Nombre minimum d'étoiles",
"addInfoBelow": "Ajoutez ces informations ci-dessous.", "addInfoBelow": "Ajoutez ces informations ci-dessous.",
"addInfoInSettings": "Ajoutez ces informations dans les paramètres.", "addInfoInSettings": "Ajoutez ces informations dans les paramètres.",
"githubSourceNote": "La limitation du débit GitHub peut être évitée à l'aide d'une clé API.", "githubSourceNote": "La limite de débit GitHub peut être évitée à l'aide d'une clé API.",
"sortByLastLinkSegment": "Trier uniquement sur le dernier segment du lien", "sortByLastLinkSegment": "Trier uniquement sur le dernier segment du lien",
"filterReleaseNotesByRegEx": "Filtrer les notes de version par expression régulière", "filterReleaseNotesByRegEx": "Filtrer les notes de version par expression régulière",
"customLinkFilterRegex": "Filtre de lien APK personnalisé par expression régulière (par défaut '.apk$')", "customLinkFilterRegex": "Filtre du lien APK personnalisé par expression régulière (par défaut '.apk$')",
"appsPossiblyUpdated": "Tentative de mise à jour de l'application", "appsPossiblyUpdated": "Tentative de mise à jour de l'application",
"appsPossiblyUpdatedNotifDescription": "Avertit l'utilisateur que des mises à jour d'une ou plusieurs applications ont été potentiellement appliquées en arrière-plan", "appsPossiblyUpdatedNotifDescription": "Avertit l'utilisateur que des mises à jour d'une ou plusieurs applications ont été potentiellement appliquées en arrière-plan",
"xWasPossiblyUpdatedToY": "{} a peut-être été mis à jour vers {}.", "xWasPossiblyUpdatedToY": "{} a peut-être été mis à jour vers {}.",
"enableBackgroundUpdates": "Activer les mises à jour en arrière-plan", "enableBackgroundUpdates": "Activer les mises à jour en arrière-plan",
"backgroundUpdateReqsExplanation": "Les mises à jour en arrière-plan peuvent ne pas être possibles pour toutes les applications.", "backgroundUpdateReqsExplanation": "Les mises à jour en arrière-plan peuvent ne pas être possibles pour toutes les applications.",
"backgroundUpdateLimitsExplanation": "Le succès d'une installation en arrière-plan ne peut être déterminé qu'à l'ouverture d'Obetium.", "backgroundUpdateLimitsExplanation": "Le succès d'une installation en arrière-plan ne peut être déterminé qu'à l'ouverture d'Obtainium.",
"verifyLatestTag": "Vérifiez la balise 'dernière'", "verifyLatestTag": "Vérifiez la balise 'Latest'",
"intermediateLinkRegex": " Filtrer un lien \" intermédiaire \" à visiter ", "intermediateLinkRegex": " Filtrer un lien \" intermédiaire \" à visiter ",
"filterByLinkText": "Filtrer les liens par texte de lien", "filterByLinkText": "Filtrer les liens par le texte du lien",
"intermediateLinkNotFound": "Lien intermédiaire introuvable", "intermediateLinkNotFound": "Lien intermédiaire introuvable",
"intermediateLink": "Lien intermédiaire", "intermediateLink": "Lien intermédiaire",
"exemptFromBackgroundUpdates": "Exempt des mises à jour en arrière-plan (si activé)", "exemptFromBackgroundUpdates": "Exempté des mises à jour en arrière-plan (si activé)",
"bgUpdatesOnWiFiOnly": "Désactiver les mises à jour en arrière-plan lorsque vous n'êtes pas connecté au WiFi", "bgUpdatesOnWiFiOnly": "Désactiver les mises à jour en arrière-plan lorsque vous n'êtes pas connecté au WiFi",
"autoSelectHighestVersionCode": "Sélection automatique de la version la plus élevéeCode APK", "autoSelectHighestVersionCode": "Sélection automatique du code de version de l'APK la plus élevée",
"versionExtractionRegEx": "Version Extraction RegEx", "versionExtractionRegEx": "Expression régulière d'extraction de version",
"matchGroupToUse": "Match Group to Use", "matchGroupToUse": "Groupe de correspondance pour l'expression régulière d'extraction de version",
"highlightTouchTargets": "Mettez en évidence les cibles tactiles moins évidentes", "highlightTouchTargets": "Mettre en évidence les cibles tactiles moins évidentes",
"pickExportDir": "Choisir le répertoire d'exportation", "pickExportDir": "Choisir le répertoire d'exportation",
"autoExportOnChanges": "Exportation automatique sur modifications", "autoExportOnChanges": "Exporter automatiquement après modification",
"includeSettings": "Inclure les paramètres", "includeSettings": "Inclure les paramètres",
"filterVersionsByRegEx": "Filtrer les versions par expression régulière", "filterVersionsByRegEx": "Filtrer les versions par expression régulière",
"trySelectingSuggestedVersionCode": "Essayez de sélectionner la version suggéréeCode APK", "trySelectingSuggestedVersionCode": "Essayez de sélectionner le code de la version APK suggérée",
"dontSortReleasesList": "Conserver la commande de version de l'API", "dontSortReleasesList": "Conserver l'ordre des version de l'API",
"reverseSort": "Tri inversé", "reverseSort": "Tri inversé",
"takeFirstLink": "Prendre le premier lien", "takeFirstLink": "Prendre le premier lien",
"skipSort": "Sauter le tri", "skipSort": "Sauter le tri",
"debugMenu": "Menu de débogage", "debugMenu": "Menu de débogage",
"bgTaskStarted": "Tâche en arrière-plan démarrée - vérifier les journaux.", "bgTaskStarted": "Tâche en arrière-plan démarrée - vérifier les journaux.",
"runBgCheckNow": "Exécuter la vérification de la mise à jour en arrière-plan maintenant", "runBgCheckNow": "Exécuter maintenant la vérification de la mise à jour en arrière-plan",
"versionExtractWholePage": "Apply Version Extraction Regex to Entire Page", "versionExtractWholePage": "Appliquer l'expression régulière d'extraction de version sur l'ensemble de la page",
"installing": "Installation", "installing": "Installation",
"skipUpdateNotifications": "Ignorer les notifications de mise à jour", "skipUpdateNotifications": "Ignorer les notifications de mise à jour",
"updatesAvailableNotifChannel": "Mises à jour disponibles", "updatesAvailableNotifChannel": "Mises à jour disponibles",
@ -275,19 +284,19 @@
"downloadingXNotifChannel": "Téléchargement {}", "downloadingXNotifChannel": "Téléchargement {}",
"completeAppInstallationNotifChannel": "Installation complète de l'application", "completeAppInstallationNotifChannel": "Installation complète de l'application",
"checkingForUpdatesNotifChannel": "Vérification des mises à jour", "checkingForUpdatesNotifChannel": "Vérification des mises à jour",
"onlyCheckInstalledOrTrackOnlyApps": "Vérifiez uniquement les mises à jour des applications installées et de suivi uniquement", "onlyCheckInstalledOrTrackOnlyApps": "Vérifiez uniquement les mises à jour des applications installées et 'Track-Only'",
"supportFixedAPKURL": "Prise en charge des URL APK fixes", "supportFixedAPKURL": "Prise en charge des URL APK fixes",
"selectX": "Sélectionner {}", "selectX": "Sélectionner {}",
"parallelDownloads": "Autoriser les téléchargements parallèles", "parallelDownloads": "Autoriser les téléchargements parallèles",
"installMethod": "Méthode d'installation", "useShizuku": "Utiliser Shizuku ou Sui pour l'installation",
"normal": "Normale", "shizukuBinderNotFound": "Service Shizuku compatible non trouvé",
"root": "Racine", "shizukuOld": "Ancienne version de Shizuku (<11) - la mettre à jour",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuOldAndroidWithADB": "Shizuku fonctionne sur Android < 8.1 avec ADB - mettre à jour Android ou utiliser Sui à la place",
"useSystemFont": "Utiliser la police système", "shizukuPretendToBeGooglePlay": "Définir Google Play comme source d'installation (si Shizuku est utilisé)",
"systemFontError": "Erreur de chargement de la police système : {}", "useSystemFont": "Utiliser la police du système",
"useVersionCodeAsOSVersion": "Utiliser le code de version de l'application comme version détectée par le système d'exploitation", "useVersionCodeAsOSVersion": "Utiliser le code de version de l'application comme version détectée par le système d'exploitation",
"requestHeader": "En-tête de demande", "requestHeader": "En-tête de demande",
"useLatestAssetDateAsReleaseDate": "Utiliser le dernier téléchargement d'élément comme date de sortie", "useLatestAssetDateAsReleaseDate": "Utiliser le dernier élément téléversé comme date de sortie",
"defaultPseudoVersioningMethod": "Méthode de pseudo-version par défaut", "defaultPseudoVersioningMethod": "Méthode de pseudo-version par défaut",
"partialAPKHash": "Hash APK partiel", "partialAPKHash": "Hash APK partiel",
"APKLinkHash": "Hash de lien APK", "APKLinkHash": "Hash de lien APK",
@ -301,6 +310,8 @@
"badDownload": "L'APK n'a pas pu être analysé (téléchargement incompatible ou partiel)", "badDownload": "L'APK n'a pas pu être analysé (téléchargement incompatible ou partiel)",
"beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)", "beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)",
"appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque vous êtes prêt.", "appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque vous êtes prêt.",
"wiki": "Aide/Wiki",
"crowdsourcedConfigsLabel": "Configurations d'applications par la foule (utilisation à vos risques et périls)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Supprimer l'application ?", "one": "Supprimer l'application ?",
"other": "Supprimer les applications ?" "other": "Supprimer les applications ?"
@ -310,12 +321,12 @@
"other": "Trop de demandes (taux limité) - réessayez dans {} minutes" "other": "Trop de demandes (taux limité) - réessayez dans {} minutes"
}, },
"bgUpdateGotErrorRetryInMinutes": { "bgUpdateGotErrorRetryInMinutes": {
"one": "La vérification de la mise à jour en arrière-plan a rencontré un {}, planifiera une nouvelle tentative de vérification dans {} minute", "one": "La vérification de la mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative de vérification sera planifié dans {} minute",
"other": "La vérification de la mise à jour en arrière-plan a rencontré un {}, planifiera une nouvelle tentative de vérification dans {} minutes" "other": "La vérification de la mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative de vérification sera planifié dans {} minute"
}, },
"bgCheckFoundUpdatesWillNotifyIfNeeded": { "bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "La vérification des mises à jour en arrière-plan trouvée {} mise à jour - avertira l'utilisateur si nécessaire", "one": "La vérification des mises à jour en arrière-plan a trouvée {} mise à jour - l'utilisateur sera notifié si nécessaire",
"other": "La vérification des mises à jour en arrière-plan a trouvé {} mises à jour - avertira l'utilisateur si nécessaire" "other": "La vérification des mises à jour en arrière-plan a trouvé {} mises à jour - l'utilisateur sera notifié si nécessaire"
}, },
"apps": { "apps": {
"one": "{} Application", "one": "{} Application",
@ -349,6 +360,10 @@
"one": "{} et 1 autre application ont été mises à jour.", "one": "{} et 1 autre application ont été mises à jour.",
"other": "{} et {} autres applications ont été mises à jour." "other": "{} et {} autres applications ont été mises à jour."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Échec de la mise à jour de {} et d'une autre application.",
"other": "Échec de la mise à jour de {} et {} autres applications."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"une": "{} et 1 application supplémentaire ont peut-être été mises à jour.", "une": "{} et 1 application supplémentaire ont peut-être été mises à jour.",
"other": "{} et {} autres applications peuvent avoir été mises à jour." "other": "{} et {} autres applications peuvent avoir été mises à jour."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(Kötelező)", "requiredInBrackets": "(Kötelező)",
"dropdownNoOptsError": "HIBA: A LEDOBÁST LEGALÁBB EGY OPCIÓHOZ KELL RENDELNI", "dropdownNoOptsError": "HIBA: A LEDOBÁST LEGALÁBB EGY OPCIÓHOZ KELL RENDELNI",
"colour": "Szín", "colour": "Szín",
"standard": "Standard",
"custom": "Custom",
"useMaterialYou": "Használja az Ön által használt anyagot",
"githubStarredRepos": "GitHub Csillagos Repo-k", "githubStarredRepos": "GitHub Csillagos Repo-k",
"uname": "Felh.név", "uname": "Felh.név",
"wrongArgNum": "Rossz számú argumentumot adott meg", "wrongArgNum": "Rossz számú argumentumot adott meg",
@ -110,6 +113,7 @@
"dark": "Sötét", "dark": "Sötét",
"light": "Világos", "light": "Világos",
"followSystem": "Rendszer szerint", "followSystem": "Rendszer szerint",
"followSystemThemeExplanation": "A következő rendszer téma csak harmadik féltől származó alkalmazások használatával lehetséges",
"useBlackTheme": "Használjon teljesen fekete sötét témát", "useBlackTheme": "Használjon teljesen fekete sötét témát",
"appSortBy": "App rendezés...", "appSortBy": "App rendezés...",
"authorName": "Szerző/Név", "authorName": "Szerző/Név",
@ -143,8 +147,10 @@
"noNewUpdates": "Nincsenek új frissítések.", "noNewUpdates": "Nincsenek új frissítések.",
"xHasAnUpdate": "A(z) {} frissítést kapott.", "xHasAnUpdate": "A(z) {} frissítést kapott.",
"appsUpdated": "Alkalmazások frissítve", "appsUpdated": "Alkalmazások frissítve",
"appsNotUpdated": "Nem sikerült frissíteni az alkalmazásokat",
"appsUpdatedNotifDescription": "Értesíti a felhasználót, hogy egy/több app frissítése megtörtént a háttérben", "appsUpdatedNotifDescription": "Értesíti a felhasználót, hogy egy/több app frissítése megtörtént a háttérben",
"xWasUpdatedToY": "{} frissítve a következőre: {}.", "xWasUpdatedToY": "{} frissítve a következőre: {}.",
"xWasNotUpdatedToY": "A {} frissítése a {}-ra nem sikerült.",
"errorCheckingUpdates": "Hiba a frissítések keresésekor", "errorCheckingUpdates": "Hiba a frissítések keresésekor",
"errorCheckingUpdatesNotifDescription": "Értesítés, amely akkor jelenik meg, ha a háttérbeli frissítések ellenőrzése sikertelen", "errorCheckingUpdatesNotifDescription": "Értesítés, amely akkor jelenik meg, ha a háttérbeli frissítések ellenőrzése sikertelen",
"appsRemoved": "Alkalmazások eltávolítva", "appsRemoved": "Alkalmazások eltávolítva",
@ -183,6 +189,9 @@
"disableVersionDetection": "Verzió érzékelés letiltása", "disableVersionDetection": "Verzió érzékelés letiltása",
"noVersionDetectionExplanation": "Ezt a beállítást csak olyan alkalmazásoknál szabad használni, ahol a verzióérzékelés nem működik megfelelően.", "noVersionDetectionExplanation": "Ezt a beállítást csak olyan alkalmazásoknál szabad használni, ahol a verzióérzékelés nem működik megfelelően.",
"downloadingX": "{} letöltés", "downloadingX": "{} letöltés",
"downloadX": "Letöltés {}",
"downloadedX": "Letöltés {}",
"releaseAsset": "Kiadási tartalom",
"downloadNotifDescription": "Értesíti a felhasználót az app letöltésének előrehaladásáról", "downloadNotifDescription": "Értesíti a felhasználót az app letöltésének előrehaladásáról",
"noAPKFound": "Nem található APK", "noAPKFound": "Nem található APK",
"noVersionDetection": "Nincs verzió érzékelés", "noVersionDetection": "Nincs verzió érzékelés",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Támogatja a rögzített APK URL-eket", "supportFixedAPKURL": "Támogatja a rögzített APK URL-eket",
"selectX": "Kiválaszt {}", "selectX": "Kiválaszt {}",
"parallelDownloads": "Párhuzamos letöltéseket enged", "parallelDownloads": "Párhuzamos letöltéseket enged",
"installMethod": "Telepítési mód", "useShizuku": "Használja Shizuku vagy Sui telepítéséhez",
"normal": "Normál",
"root": "Root",
"shizukuBinderNotFound": "A Shizuku nem fut", "shizukuBinderNotFound": "A Shizuku nem fut",
"shizukuOld": "Régi Shizuku verzió (<11) - frissítsd!",
"shizukuOldAndroidWithADB": "Shizuku fut Android < 8.1 ADB-vel - frissítse az Androidot vagy használja a Sui-t helyette",
"shizukuPretendToBeGooglePlay": "Állítsa be a Google Play-t telepítési forrásként (ha Shizuku-t használ)",
"useSystemFont": "Használja a rendszer betűtípusát", "useSystemFont": "Használja a rendszer betűtípusát",
"systemFontError": "Hiba a rendszer betűtípusának betöltésekor: {}",
"useVersionCodeAsOSVersion": "Az app verziókód használata a rendszer által észlelt verzióként", "useVersionCodeAsOSVersion": "Az app verziókód használata a rendszer által észlelt verzióként",
"requestHeader": "Kérelem fejléc", "requestHeader": "Kérelem fejléc",
"useLatestAssetDateAsReleaseDate": "Használja a legújabb tartalomfeltöltést megjelenési dátumként", "useLatestAssetDateAsReleaseDate": "Használja a legújabb tartalomfeltöltést megjelenési dátumként",
@ -301,6 +310,8 @@
"badDownload": "Az APK-t nem lehetett elemezni (inkompatibilis vagy részleges letöltés)", "badDownload": "Az APK-t nem lehetett elemezni (inkompatibilis vagy részleges letöltés)",
"beforeNewInstallsShareToAppVerifier": "Új alkalmazások megosztása az AppVerifierrel (ha elérhető)", "beforeNewInstallsShareToAppVerifier": "Új alkalmazások megosztása az AppVerifierrel (ha elérhető)",
"appVerifierInstructionToast": "Ossza meg az AppVerifierrel, majd térjen vissza ide, ha kész.", "appVerifierInstructionToast": "Ossza meg az AppVerifierrel, majd térjen vissza ide, ha kész.",
"wiki": "Súgó/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (használat saját felelősségre)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?", "one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazásokat?" "other": "Eltávolítja az alkalmazásokat?"
@ -349,6 +360,10 @@
"one": "A(z) {} és 1 további alkalmazás frissítve.", "one": "A(z) {} és 1 további alkalmazás frissítve.",
"other": "{} és {} további alkalmazás frissítve." "other": "{} és {} további alkalmazás frissítve."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Nem sikerült frissíteni {} és még 1 alkalmazást.",
"other": "Nem sikerült frissíteni {} és {} további alkalmazásokat."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} és 1 további alkalmazás is frissült.", "one": "{} és 1 további alkalmazás is frissült.",
"other": "{} és {} további alkalmazás is frissült." "other": "{} és {} további alkalmazás is frissült."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(richiesto)", "requiredInBrackets": "(richiesto)",
"dropdownNoOptsError": "ERRORE: LA TENDINA DEVE AVERE ALMENO UN'OPZIONE", "dropdownNoOptsError": "ERRORE: LA TENDINA DEVE AVERE ALMENO UN'OPZIONE",
"colour": "Colore", "colour": "Colore",
"standard": "Standard",
"custom": "Personalizzato",
"useMaterialYou": "Utilizzate il materiale che avete a disposizione",
"githubStarredRepos": "repository stellati da GitHub", "githubStarredRepos": "repository stellati da GitHub",
"uname": "Nome utente", "uname": "Nome utente",
"wrongArgNum": "Numero di argomenti forniti errato", "wrongArgNum": "Numero di argomenti forniti errato",
@ -110,6 +113,7 @@
"dark": "Scuro", "dark": "Scuro",
"light": "Chiaro", "light": "Chiaro",
"followSystem": "Segui il sistema", "followSystem": "Segui il sistema",
"followSystemThemeExplanation": "È possibile seguire il tema di sistema solo utilizzando applicazioni di terze parti.",
"useBlackTheme": "Usa il tema nero puro", "useBlackTheme": "Usa il tema nero puro",
"appSortBy": "App ordinate per", "appSortBy": "App ordinate per",
"authorName": "Autore/Nome", "authorName": "Autore/Nome",
@ -143,8 +147,10 @@
"noNewUpdates": "Nessun nuovo aggiornamento.", "noNewUpdates": "Nessun nuovo aggiornamento.",
"xHasAnUpdate": "Aggiornamento disponibile per {}", "xHasAnUpdate": "Aggiornamento disponibile per {}",
"appsUpdated": "App aggiornate", "appsUpdated": "App aggiornate",
"appsNotUpdated": "Impossibile aggiornare le applicazioni",
"appsUpdatedNotifDescription": "Notifica all'utente che una o più app sono state aggiornate in secondo piano", "appsUpdatedNotifDescription": "Notifica all'utente che una o più app sono state aggiornate in secondo piano",
"xWasUpdatedToY": "{} è stato aggiornato alla {}.", "xWasUpdatedToY": "{} è stato aggiornato alla {}.",
"xWasNotUpdatedToY": "Impossibile aggiornare {} a {}.",
"errorCheckingUpdates": "Controllo degli errori per gli aggiornamenti", "errorCheckingUpdates": "Controllo degli errori per gli aggiornamenti",
"errorCheckingUpdatesNotifDescription": "Una notifica che mostra quando il controllo degli aggiornamenti in secondo piano fallisce", "errorCheckingUpdatesNotifDescription": "Una notifica che mostra quando il controllo degli aggiornamenti in secondo piano fallisce",
"appsRemoved": "App rimosse", "appsRemoved": "App rimosse",
@ -183,6 +189,9 @@
"disableVersionDetection": "Disattiva il rilevamento della versione", "disableVersionDetection": "Disattiva il rilevamento della versione",
"noVersionDetectionExplanation": "Questa opzione dovrebbe essere usata solo per le app la cui versione non viene rilevata correttamente.", "noVersionDetectionExplanation": "Questa opzione dovrebbe essere usata solo per le app la cui versione non viene rilevata correttamente.",
"downloadingX": "Scaricamento di {} in corso", "downloadingX": "Scaricamento di {} in corso",
"downloadX": "Scarica {}",
"downloadedX": "Scaricato {}",
"releaseAsset": "Rilascio Asset",
"downloadNotifDescription": "Notifica all'utente lo stato di avanzamento del download di un'app", "downloadNotifDescription": "Notifica all'utente lo stato di avanzamento del download di un'app",
"noAPKFound": "Nessun APK trovato", "noAPKFound": "Nessun APK trovato",
"noVersionDetection": "Disattiva rilevamento di versione", "noVersionDetection": "Disattiva rilevamento di versione",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Supporta URL fissi di APK", "supportFixedAPKURL": "Supporta URL fissi di APK",
"selectX": "Seleziona {}", "selectX": "Seleziona {}",
"parallelDownloads": "Permetti download paralleli", "parallelDownloads": "Permetti download paralleli",
"installMethod": "Metodo d'installazione", "useShizuku": "Utilizzare Shizuku o Sui per installare",
"normal": "Normale",
"root": "Root",
"shizukuBinderNotFound": "Shizuku non è in esecuzione", "shizukuBinderNotFound": "Shizuku non è in esecuzione",
"shizukuOld": "Vecchia versione di Shizuku (<11) - aggiornarla",
"shizukuOldAndroidWithADB": "Shizuku funziona su Android < 8.1 con ADB - aggiornare Android o utilizzare Sui al suo posto",
"shizukuPretendToBeGooglePlay": "Impostare Google Play come fonte di installazione (se si usa Shizuku)",
"useSystemFont": "Usa i caratteri di sistema", "useSystemFont": "Usa i caratteri di sistema",
"systemFontError": "Errore durante il caricamento dei caratteri di sistema: {}",
"useVersionCodeAsOSVersion": "Usa il codice versione dell'app come versione rilevata dal sistema operativo", "useVersionCodeAsOSVersion": "Usa il codice versione dell'app come versione rilevata dal sistema operativo",
"requestHeader": "Intestazione della richiesta", "requestHeader": "Intestazione della richiesta",
"useLatestAssetDateAsReleaseDate": "Usa l'ultimo caricamento della risorsa come data di rilascio", "useLatestAssetDateAsReleaseDate": "Usa l'ultimo caricamento della risorsa come data di rilascio",
@ -301,6 +310,8 @@
"badDownload": "Non è stato possibile analizzare l'APK (download incompatibile o parziale).", "badDownload": "Non è stato possibile analizzare l'APK (download incompatibile o parziale).",
"beforeNewInstallsShareToAppVerifier": "Condividere le nuove applicazioni con AppVerifier (se disponibile)", "beforeNewInstallsShareToAppVerifier": "Condividere le nuove applicazioni con AppVerifier (se disponibile)",
"appVerifierInstructionToast": "Condividete con AppVerifier, quindi tornate qui quando siete pronti.", "appVerifierInstructionToast": "Condividete con AppVerifier, quindi tornate qui quando siete pronti.",
"wiki": "Aiuto/Wiki",
"crowdsourcedConfigsLabel": "Configurazioni di app in crowdsourcing (uso a proprio rischio)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Rimuovere l'app?", "one": "Rimuovere l'app?",
"other": "Rimuovere le app?" "other": "Rimuovere le app?"
@ -349,6 +360,10 @@
"one": "{} e un'altra app sono state aggiornate.", "one": "{} e un'altra app sono state aggiornate.",
"other": "{} e altre {} app sono state aggiornate." "other": "{} e altre {} app sono state aggiornate."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Non è riuscito ad aggiornare {} e altre 1 app.",
"other": "Non è riuscito ad aggiornare {} e {} altre applicazioni."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} e un'altra app potrebbero essere state aggiornate.", "one": "{} e un'altra app potrebbero essere state aggiornate.",
"other": "{} e altre {} app potrebbero essere state aggiornate." "other": "{} e altre {} app potrebbero essere state aggiornate."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(必須)", "requiredInBrackets": "(必須)",
"dropdownNoOptsError": "エラー: ドロップダウンには、少なくとも1つのオプションが必要です", "dropdownNoOptsError": "エラー: ドロップダウンには、少なくとも1つのオプションが必要です",
"colour": "カラー", "colour": "カラー",
"standard": "スタンダード",
"custom": "カスタム",
"useMaterialYou": "Material Youを使用する",
"githubStarredRepos": "Githubでスターしたリポジトリ", "githubStarredRepos": "Githubでスターしたリポジトリ",
"uname": "ユーザー名", "uname": "ユーザー名",
"wrongArgNum": "提供する引数の数が間違っています", "wrongArgNum": "提供する引数の数が間違っています",
@ -110,6 +113,7 @@
"dark": "ダーク", "dark": "ダーク",
"light": "ライト", "light": "ライト",
"followSystem": "システムに従う", "followSystem": "システムに従う",
"followSystemThemeExplanation": "以下のシステムテーマは、サードパーティのアプリケーションを使用することによってのみ可能です。",
"useBlackTheme": "ピュアブラックダークテーマを使用する", "useBlackTheme": "ピュアブラックダークテーマを使用する",
"appSortBy": "アプリの並び方", "appSortBy": "アプリの並び方",
"authorName": "作者名/アプリ名", "authorName": "作者名/アプリ名",
@ -143,8 +147,10 @@
"noNewUpdates": "新しいアップデートはありません", "noNewUpdates": "新しいアップデートはありません",
"xHasAnUpdate": "{} のアップデートが利用可能です。", "xHasAnUpdate": "{} のアップデートが利用可能です。",
"appsUpdated": "アプリをアップデートしました", "appsUpdated": "アプリをアップデートしました",
"appsNotUpdated": "アプリケーションの更新に失敗",
"appsUpdatedNotifDescription": "1つまたは複数のAppのアップデートがバックグラウンドで適用されたことをユーザーに通知する", "appsUpdatedNotifDescription": "1つまたは複数のAppのアップデートがバックグラウンドで適用されたことをユーザーに通知する",
"xWasUpdatedToY": "{} が {} にアップデートされました", "xWasUpdatedToY": "{} が {} にアップデートされました",
"xWasNotUpdatedToY": "への更新に失敗しました。",
"errorCheckingUpdates": "アップデート確認中のエラー", "errorCheckingUpdates": "アップデート確認中のエラー",
"errorCheckingUpdatesNotifDescription": "バックグラウンドでのアップデート確認に失敗した際に表示される通知", "errorCheckingUpdatesNotifDescription": "バックグラウンドでのアップデート確認に失敗した際に表示される通知",
"appsRemoved": "削除されたアプリ", "appsRemoved": "削除されたアプリ",
@ -183,6 +189,9 @@
"disableVersionDetection": "バージョン検出を無効にする", "disableVersionDetection": "バージョン検出を無効にする",
"noVersionDetectionExplanation": "このオプションは、バージョン検出が正しく機能しないアプリにのみ使用する必要があります。", "noVersionDetectionExplanation": "このオプションは、バージョン検出が正しく機能しないアプリにのみ使用する必要があります。",
"downloadingX": "{} をダウンロード中", "downloadingX": "{} をダウンロード中",
"downloadX": "ダウンロード",
"downloadedX": "ダウンロード",
"releaseAsset": "リリース資産",
"downloadNotifDescription": "アプリのダウンロード状況を通知する", "downloadNotifDescription": "アプリのダウンロード状況を通知する",
"noAPKFound": "APKが見つかりません", "noAPKFound": "APKが見つかりません",
"noVersionDetection": "バージョン検出を行わない", "noVersionDetection": "バージョン検出を行わない",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "固定されたAPKのURLをサポートする", "supportFixedAPKURL": "固定されたAPKのURLをサポートする",
"selectX": "{} 選択", "selectX": "{} 選択",
"parallelDownloads": "並行ダウンロードを許可する", "parallelDownloads": "並行ダウンロードを許可する",
"installMethod": "インストール方法", "useShizuku": "ShizukuまたはSuiを使用してインストールする",
"normal": "通常",
"root": "Root",
"shizukuBinderNotFound": "Shizukuが起動していません", "shizukuBinderNotFound": "Shizukuが起動していません",
"shizukuOld": "古いShizukuのバージョン (<11) - アップデートしてください",
"shizukuOldAndroidWithADB": "ShizukuがAndroid 8.1未満でADBを使用して動作しています - Androidをアップデートするか、代わりにSuiを使用してください",
"shizukuPretendToBeGooglePlay": "Google Playをインストール元として設定するShizukuを使用する場合",
"useSystemFont": "システムフォントを使用する", "useSystemFont": "システムフォントを使用する",
"systemFontError": "システムフォントの読み込みエラー: {}",
"useVersionCodeAsOSVersion": "アプリのバージョンコードをOSで検出されたバージョンとして使用する", "useVersionCodeAsOSVersion": "アプリのバージョンコードをOSで検出されたバージョンとして使用する",
"requestHeader": "リクエストヘッダー", "requestHeader": "リクエストヘッダー",
"useLatestAssetDateAsReleaseDate": "最新のアセットアップロードをリリース日として使用する", "useLatestAssetDateAsReleaseDate": "最新のアセットアップロードをリリース日として使用する",
@ -301,6 +310,8 @@
"badDownload": "APK を解析できませんでした(互換性がないか、部分的にダウンロードされています)。", "badDownload": "APK を解析できませんでした(互換性がないか、部分的にダウンロードされています)。",
"beforeNewInstallsShareToAppVerifier": "AppVerifierで新しいアプリを共有する利用可能な場合", "beforeNewInstallsShareToAppVerifier": "AppVerifierで新しいアプリを共有する利用可能な場合",
"appVerifierInstructionToast": "AppVerifierに共有し、準備ができたらここに戻ってください。", "appVerifierInstructionToast": "AppVerifierに共有し、準備ができたらここに戻ってください。",
"wiki": "ヘルプ/ウィキ",
"crowdsourcedConfigsLabel": "クラウドソーシングによるアプリの設定(利用は自己責任で)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "アプリを削除しますか?", "one": "アプリを削除しますか?",
"other": "アプリを削除しますか?" "other": "アプリを削除しますか?"
@ -349,6 +360,10 @@
"one": "{} とさらに {} 個のアプリがアップデートされました。", "one": "{} とさらに {} 個のアプリがアップデートされました。",
"other": "{} とさらに {} 個のアプリがアップデートされました。" "other": "{} とさらに {} 個のアプリがアップデートされました。"
}, },
"xAndNMoreUpdatesFailed": {
"one": "更新に失敗しました。",
"other": "アプリのアップデートに失敗しました。"
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。", "one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。",
"other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。" "other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。"

View File

@ -1,131 +1,135 @@
{ {
"invalidURLForSource": "Geen valide {} app URL", "invalidURLForSource": "Ongeldige app-URL voor {}",
"noReleaseFound": "Kan geen geschikte release vinden", "noReleaseFound": "Geen geschikte release gevonden",
"noVersionFound": "Kan de versie niet bepalen", "noVersionFound": "Geen versie kunnen bepalen",
"urlMatchesNoSource": "URL komt niet overeen met bekende bron", "urlMatchesNoSource": "URL komt niet overeen met bekende bron",
"cantInstallOlderVersion": "Kan geen oudere versie van de app installeren", "cantInstallOlderVersion": "Kan geen oudere versie van de app installeren",
"appIdMismatch": "Gedownloade pakket-ID komt niet overeen met de bestaande app-ID", "appIdMismatch": "Gedownload pakket-ID komt niet overeen met de bestaande app-ID",
"functionNotImplemented": "Deze class heeft deze functie niet geïmplementeerd.", "functionNotImplemented": "Deze klasse heeft deze functie niet geïmplementeerd.",
"placeholder": "Plaatshouder", "placeholder": "Dummy",
"someErrors": "Er zijn enkele fouten opgetreden", "someErrors": "Er zijn enkele fouten opgetreden",
"unexpectedError": "Onverwachte fout", "unexpectedError": "Onverwachte fout",
"ok": "Ok", "ok": "Oké",
"and": "en", "and": "en",
"githubPATLabel": "GitHub Personal Access Token\n(Verhoogt limiet aantal verzoeken)", "githubPATLabel": "GitHub Personal Access Token\n(Verhoogt limiet aantal verzoeken)",
"includePrereleases": "Bevat prereleases", "includePrereleases": "Inclusief pre-releases",
"fallbackToOlderReleases": "Terugvallen op oudere releases", "fallbackToOlderReleases": "Terugvallen op oudere releases",
"filterReleaseTitlesByRegEx": "Filter release-titels met reguliere expressies.", "filterReleaseTitlesByRegEx": "Release-titels filteren met reguliere expressies.",
"invalidRegEx": "Ongeldige reguliere expressie", "invalidRegEx": "Ongeldige reguliere expressie",
"noDescription": "Geen omschrijving", "noDescription": "Geen omschrijving",
"cancel": "Annuleer", "cancel": "Annuleren",
"continue": "Ga verder", "continue": "Doorgaan",
"requiredInBrackets": "(Verplicht)", "requiredInBrackets": "(Verplicht)",
"dropdownNoOptsError": "FOUTMELDING: DROPDOWN MOET TENMINSTE ÉÉN OPT HEBBEN", "dropdownNoOptsError": "FOUTMELDING: UITKLAPMENU MOET TENMINSTE EEN OPT HEBBEN",
"colour": "Kleur", "colour": "Kleur",
"standard": "Standaard",
"custom": "Aangepast",
"useMaterialYou": "Material You gebruiken",
"githubStarredRepos": "GitHub-repo's met ster", "githubStarredRepos": "GitHub-repo's met ster",
"uname": "Gebruikersnaam", "uname": "Gebruikersnaam",
"wrongArgNum": "Onjuist aantal argumenten verstrekt.", "wrongArgNum": "Incorrect aantal argumenten.",
"xIsTrackOnly": "{} is alleen tracken", "xIsTrackOnly": "{} is 'Alleen volgen'",
"source": "Bron", "source": "Bron",
"app": "App", "app": "App",
"appsFromSourceAreTrackOnly": "Apps van deze bron zijn 'Track-Only'.", "appsFromSourceAreTrackOnly": "Apps van deze bron zijn 'Alleen volgen'.",
"youPickedTrackOnly": "Je hebt de 'Track-Only' optie geselecteerd.", "youPickedTrackOnly": "De optie 'Alleen volgen' is geselecteerd.",
"trackOnlyAppDescription": "De app zal worden gevolgd voor updates, maar Obtainium zal niet in staat zijn om deze te downloaden of te installeren.", "trackOnlyAppDescription": "De app zal worden gevolgd voor updates, maar Obtainium zal niet in staat zijn om deze te downloaden of te installeren.",
"cancelled": "Geannuleerd", "cancelled": "Geannuleerd",
"appAlreadyAdded": "App al toegevoegd", "appAlreadyAdded": "App reeds toegevoegd",
"alreadyUpToDateQuestion": "Is de app al up-to-date?", "alreadyUpToDateQuestion": "App al bijgewerkt?",
"addApp": "App toevoegen", "addApp": "App toevoegen",
"appSourceURL": "App bron URL", "appSourceURL": "App-bron URL",
"error": "Foutmelding", "error": "Foutmelding",
"add": "Toevoegen", "add": "Toevoegen",
"searchSomeSourcesLabel": "Zoeken (Alleen sommige bronnen)", "searchSomeSourcesLabel": "Zoeken (sommige bronnen)",
"search": "Zoeken", "search": "Zoeken",
"additionalOptsFor": "Aanvullende opties voor {}", "additionalOptsFor": "Aanvullende opties voor {}",
"supportedSources": "Ondersteunde bronnen", "supportedSources": "Ondersteunde bronnen",
"trackOnlyInBrackets": "(Alleen track)", "trackOnlyInBrackets": "(Alleen volgen)",
"searchableInBrackets": "(Doorzoekbaar)", "searchableInBrackets": "(Doorzoekbaar)",
"appsString": "Apps", "appsString": "Apps",
"noApps": "Geen Apps", "noApps": "Geen Apps",
"noAppsForFilter": "Geen Apps voor filter", "noAppsForFilter": "Geen Apps voor filter",
"byX": "Door {}", "byX": "Door {}",
"percentProgress": "Vooruitgang: {}%", "percentProgress": "Voortgang: {}%",
"pleaseWait": "Even geduld", "pleaseWait": "Even geduld",
"updateAvailable": "Update beschikbaar", "updateAvailable": "Update beschikbaar",
"notInstalled": "Niet geinstalleerd", "notInstalled": "Niet geinstalleerd",
"pseudoVersion": "pseudo-versie", "pseudoVersion": "pseudo-versie",
"selectAll": "Selecteer alles", "selectAll": "Alles selecteren",
"deselectX": "Deselecteer {}", "deselectX": "Selectie opheffen {}",
"xWillBeRemovedButRemainInstalled": "{} zal worden verwijderd uit Obtainium, maar blijft geïnstalleerd op het apparaat.", "xWillBeRemovedButRemainInstalled": "{} zal worden gewist uit Obtainium, maar blijft geïnstalleerd op het apparaat.",
"removeSelectedAppsQuestion": "Geselecteerde apps verwijderen??", "removeSelectedAppsQuestion": "Geselecteerde apps verwijderen?",
"removeSelectedApps": "Geselecteerde apps verwijderen", "removeSelectedApps": "Geselecteerde apps verwijderen",
"updateX": "Update {}", "updateX": "{} bijwerken",
"installX": "Installeer {}", "installX": "{} installeren",
"markXTrackOnlyAsUpdated": "Markeer {}\n(Track-Only)\nals up-to-date", "markXTrackOnlyAsUpdated": "{}\n(Alleen volgen)\nmarkeren als bijgewerkt",
"changeX": "Verander {}", "changeX": "{} wijzigen",
"installUpdateApps": "Installeer/Update apps", "installUpdateApps": "Apps installeren/bijwerken",
"installUpdateSelectedApps": "Installeer/Update geselecteerde apps", "installUpdateSelectedApps": "Geselecteerde apps installeren/bijwerken",
"markXSelectedAppsAsUpdated": "{} geselecteerde apps markeren als up-to-date?", "markXSelectedAppsAsUpdated": "{} geselecteerde apps markeren als bijgewerkt?",
"no": "Nee", "no": "Nee",
"yes": "Ja", "yes": "Ja",
"markSelectedAppsUpdated": "Markeer geselecteerde aps als up-to-date", "markSelectedAppsUpdated": "Geselecteerde apps markeren als bijgewerkt",
"pinToTop": "Vastzetten aan de bovenkant", "pinToTop": "Bovenaan plaatsen",
"unpinFromTop": "Losmaken van de bovenkant", "unpinFromTop": "Bovenaan wegnemen",
"resetInstallStatusForSelectedAppsQuestion": "Installatiestatus resetten voor geselecteerde apps?", "resetInstallStatusForSelectedAppsQuestion": "Installatiestatus herstellen voor geselecteerde apps?",
"installStatusOfXWillBeResetExplanation": "De installatiestatus van alle geselecteerde apps zal worden gereset.\n\nDit kan helpen wanneer de versie van de app die in Obtainium wordt weergegeven onjuist is vanwege mislukte updates of andere problemen.", "installStatusOfXWillBeResetExplanation": "De installatiestatus van alle geselecteerde apps zal worden hersteld.\n\nDit kan helpen wanneer de versie van de app die in Obtainium wordt weergegeven onjuist is vanwege mislukte updates of andere problemen.",
"customLinkMessage": "Deze links werken op apparaten waarop Obtainium is geïnstalleerd", "customLinkMessage": "Deze koppelingen werken op apparaten waarop Obtainium is geïnstalleerd",
"shareAppConfigLinks": "App-configuratie delen als HTML-link", "shareAppConfigLinks": "App-configuratie delen als HTML-link",
"shareSelectedAppURLs": "Deel geselecteerde app URL's", "shareSelectedAppURLs": "Geselecteerde app-URL's delen",
"resetInstallStatus": "Reset installatiestatus", "resetInstallStatus": "Installatiestatus herstellen",
"more": "Meer", "more": "Meer",
"removeOutdatedFilter": "Verwijder out-of-date app filter", "removeOutdatedFilter": "Verouderde apps-filter verwijderen",
"showOutdatedOnly": "Toon alleen out-of-date apps", "showOutdatedOnly": "Alleen verouderde apps weergeven",
"filter": "Filter", "filter": "Filteren",
"filterApps": "Filter apps", "filterApps": "Apps filteren",
"appName": "App naam", "appName": "App-naam",
"author": "Auteur", "author": "Auteur",
"upToDateApps": "Up-to-date apps", "upToDateApps": "Bijgewerkte apps",
"nonInstalledApps": "Niet-geïnstalleerde apps", "nonInstalledApps": "Niet-geïnstalleerde apps",
"importExport": "Importeren/Exporteren", "importExport": "Importeren/exporteren",
"settings": "Instellingen", "settings": "Instellingen",
"exportedTo": "Geëxporteerd naar {}", "exportedTo": "Geëxporteerd naar {}",
"obtainiumExport": "Obtainium export", "obtainiumExport": "Obtainium export",
"invalidInput": "Ongeldige invoer", "invalidInput": "Ongeldige invoer",
"importedX": "Geïmporteerd {}", "importedX": "{} geïmporteerd",
"obtainiumImport": "Obtainium import", "obtainiumImport": "Obtainium import",
"importFromURLList": "Importeer van URL-lijsten", "importFromURLList": "Importeren van URL-lijsten",
"searchQuery": "Zoekopdracht", "searchQuery": "Zoekopdracht",
"appURLList": "App URL-lijst", "appURLList": "App URL-lijst",
"line": "Lijn", "line": "Regel",
"searchX": "Zoek {}", "searchX": "{} zoeken",
"noResults": "Geen resultaten gevonden", "noResults": "Geen resultaten gevonden",
"importX": "Importeer {}", "importX": "{} importeren",
"importedAppsIdDisclaimer": "Geïmporteerde apps kunnen mogelijk onjuist worden weergegeven als \"Niet geïnstalleerd\".\nOm dit op te lossen, herinstalleer ze via Obtainium.\nDit zou geen invloed moeten hebben op app-gegevens.\n\nDit heeft alleen invloed op URL- en importmethoden van derden.", "importedAppsIdDisclaimer": "Geïmporteerde apps kunnen mogelijk onjuist worden weergegeven als \"Niet geïnstalleerd\".\nOm dit op te lossen, installeer deze opnieuw via Obtainium.\nDit zou geen invloed moeten hebben op app-gegevens.\n\nDit heeft alleen invloed op URL- en importmethoden van derden.",
"importErrors": "Import foutmeldingen", "importErrors": "Fouten bij het importeren",
"importedXOfYApps": "{} van {} apps geïmporteerd.", "importedXOfYApps": "{} van {} apps geïmporteerd.",
"followingURLsHadErrors": "De volgende URL's bevatten fouten:", "followingURLsHadErrors": "De volgende URL's bevatten fouten:",
"selectURL": "Selecteer URL", "selectURL": "URL selecteren",
"selectURLs": "Selecteer URL's", "selectURLs": "URL's selecteren",
"pick": "Kies", "pick": "Kiezen",
"theme": "Thema", "theme": "Thema",
"dark": "Donker", "dark": "Donker",
"light": "Licht", "light": "Licht",
"followSystem": "Volg systeem", "followSystem": "Systeem volgen",
"useBlackTheme": "Gebruik zwart thema", "followSystemThemeExplanation": "Het volgen van het systeemthema is alleen mogelijk met applicaties van derden",
"appSortBy": "App sorteren op", "useBlackTheme": "Zwart thema gebruiken",
"appSortBy": "Sortering",
"authorName": "Auteur/Naam", "authorName": "Auteur/Naam",
"nameAuthor": "Naam/Auteur", "nameAuthor": "Naam/Auteur",
"asAdded": "Zoals toegevoegd", "asAdded": "Datum toegevoegd",
"appSortOrder": "App sorteervolgorde", "appSortOrder": "Volgorde",
"ascending": "Oplopend", "ascending": "Oplopend",
"descending": "Aflopend", "descending": "Aflopend",
"bgUpdateCheckInterval": "Frequentie voor achtergrondupdatecontrole", "bgUpdateCheckInterval": "Frequentie voor achtergrond-updatecontrole",
"neverManualOnly": "Nooit - Alleen handmatig", "neverManualOnly": "Nooit - Alleen handmatig",
"appearance": "Weergave", "appearance": "Weergave",
"showWebInAppView": "Toon de bronwebpagina in app-weergave", "showWebInAppView": "Bron-webpagina weergeven in app-weergave",
"pinUpdates": "Updates bovenaan in de apps-weergave vastpinnen", "pinUpdates": "Updates bovenaan plaatsen in de apps-weergave",
"updates": "Updates", "updates": "Updates",
"sourceSpecific": "Bron-specifiek", "sourceSpecific": "Bron-specifiek",
"appSource": "App bron", "appSource": "App-bron",
"noLogs": "Geen logs", "noLogs": "Geen logs",
"appLogs": "App logs", "appLogs": "App logs",
"close": "Sluiten", "close": "Sluiten",
@ -133,30 +137,32 @@
"appNotFound": "App niet gevonden", "appNotFound": "App niet gevonden",
"obtainiumExportHyphenatedLowercase": "obtainium-export", "obtainiumExportHyphenatedLowercase": "obtainium-export",
"pickAnAPK": "Kies een APK", "pickAnAPK": "Kies een APK",
"appHasMoreThanOnePackage": "{} heeft meer dan één package:", "appHasMoreThanOnePackage": "{} biedt verschillende pakketten:",
"deviceSupportsXArch": "Jouw apparaat support de {} CPU-architectuur.", "deviceSupportsXArch": "Dit apparaat ondersteunt de {} CPU-architectuur.",
"deviceSupportsFollowingArchs": "Je apparaat ondersteunt de volgende CPU-architecturen:", "deviceSupportsFollowingArchs": "Dit apparaat ondersteunt de volgende CPU-architecturen:",
"warning": "Waarschuwing", "warning": "Waarschuwing",
"sourceIsXButPackageFromYPrompt": "De appbron is '{}' maar de release package komt van '{}'. Doorgaan?", "sourceIsXButPackageFromYPrompt": "De app-bron is '{}' maar het release-pakket komt van '{}'. Doorgaan?",
"updatesAvailable": "Updates beschikbaar", "updatesAvailable": "Updates beschikbaar",
"updatesAvailableNotifDescription": "Stelt de gebruiker op de hoogte dat er updates beschikbaar zijn voor één of meer apps die worden bijgehouden door Obtainium.", "updatesAvailableNotifDescription": "Stelt de gebruiker op de hoogte dat er updates beschikbaar zijn voor een of meer apps die worden bijgehouden door Obtainium.",
"noNewUpdates": "Geen nieuwe updates.", "noNewUpdates": "Geen nieuwe updates.",
"xHasAnUpdate": "{} heeft een update.", "xHasAnUpdate": "{} heeft een update.",
"appsUpdated": "Apps bijgewerkt", "appsUpdated": "Apps bijgewerkt",
"appsNotUpdated": "Applicaties konden niet worden bijgewerkt",
"appsUpdatedNotifDescription": "Stelt de gebruiker op de hoogte dat updates voor één of meer apps in de achtergrond zijn toegepast.", "appsUpdatedNotifDescription": "Stelt de gebruiker op de hoogte dat updates voor één of meer apps in de achtergrond zijn toegepast.",
"xWasUpdatedToY": "{} is bijgewerkt naar {}.", "xWasUpdatedToY": "{} is bijgewerkt naar {}.",
"xWasNotUpdatedToY": "Het bijwerken van {} naar {} is mislukt.",
"errorCheckingUpdates": "Fout bij het controleren op updates", "errorCheckingUpdates": "Fout bij het controleren op updates",
"errorCheckingUpdatesNotifDescription": "Een melding die verschijnt wanneer het controleren op updates in de achtergrond mislukt", "errorCheckingUpdatesNotifDescription": "Een melding die verschijnt wanneer de achtergrondcontrole op updates mislukt",
"appsRemoved": "Apps verwijderd", "appsRemoved": "Apps verwijderd",
"appsRemovedNotifDescription": "Stelt de gebruiker op de hoogte dat één of meer apps zijn verwijderd vanwege fouten tijdens het laden ervan", "appsRemovedNotifDescription": "Stelt de gebruiker op de hoogte dat een of meer apps zijn verwijderd vanwege fouten tijdens het laden",
"xWasRemovedDueToErrorY": "{} is verwijderd vanwege deze foutmelding: {}", "xWasRemovedDueToErrorY": "{} is verwijderd vanwege de fout: {}",
"completeAppInstallation": "Complete app installatie", "completeAppInstallation": "App-installatie voltooien",
"obtainiumMustBeOpenToInstallApps": "Obtainium moet geopend zijn om apps te installeren", "obtainiumMustBeOpenToInstallApps": "Obtainium moet geopend zijn om apps te installeren",
"completeAppInstallationNotifDescription": "Vraagt de gebruiker om terug te keren naar Obtainium om de installatie van een app af te ronden", "completeAppInstallationNotifDescription": "Vraagt de gebruiker om terug te keren naar Obtainium om de installatie van een app af te ronden",
"checkingForUpdates": "Controleren op updates", "checkingForUpdates": "Controleren op updates",
"checkingForUpdatesNotifDescription": "Tijdelijke melding die verschijnt tijdens het controleren op updates", "checkingForUpdatesNotifDescription": "Tijdelijke melding die verschijnt tijdens het controleren op updates",
"pleaseAllowInstallPerm": "Sta Obtainium toe om apps te installeren", "pleaseAllowInstallPerm": "Toestaan dat Obtainium apps installeert",
"trackOnly": "Alleen track", "trackOnly": "'Alleen volgen'",
"errorWithHttpStatusCode": "Foutmelding {}", "errorWithHttpStatusCode": "Foutmelding {}",
"versionCorrectionDisabled": "Versiecorrectie uitgeschakeld (de plug-in lijkt niet te werken)", "versionCorrectionDisabled": "Versiecorrectie uitgeschakeld (de plug-in lijkt niet te werken)",
"unknown": "Onbekend", "unknown": "Onbekend",
@ -166,23 +172,26 @@
"installedVersionX": "Geïnstalleerde versie: {}", "installedVersionX": "Geïnstalleerde versie: {}",
"lastUpdateCheckX": "Laatste updatecontrole: {}", "lastUpdateCheckX": "Laatste updatecontrole: {}",
"remove": "Verwijderen", "remove": "Verwijderen",
"yesMarkUpdated": "Ja, markeer als bijgewerkt", "yesMarkUpdated": "Ja, markeren als bijgewerkt",
"fdroid": "F-Droid-ambtenaar", "fdroid": "F-Droid (Officieel)",
"appIdOrName": "App ID of naam", "appIdOrName": "App-ID of naam",
"appId": "App-ID", "appId": "App-ID",
"appWithIdOrNameNotFound": "Er werd geen app gevonden met dat ID of die naam", "appWithIdOrNameNotFound": "Er is geen app gevonden met dat ID of die naam",
"reposHaveMultipleApps": "Repositories kunnen meerdere apps bevatten", "reposHaveMultipleApps": "Repositories kunnen meerdere apps bevatten",
"fdroidThirdPartyRepo": "F-Droid Repository van derden", "fdroidThirdPartyRepo": "F-Droid Repository voor derden",
"steamMobile": "Stoommobiel", "steamMobile": "Steam Mobile",
"steamChat": "Steamchat", "steamChat": "Steam Chat",
"install": "Installeren", "install": "Installeren",
"markInstalled": "Als geïnstalleerd markere", "markInstalled": "Als geïnstalleerd markeren",
"update": "Update", "update": "Bijwerken",
"markUpdated": "Markeren als bijgewerkt", "markUpdated": "Als bijgewerkt markeren",
"additionalOptions": "Aanvullende opties", "additionalOptions": "Aanvullende opties",
"disableVersionDetection": "Versieherkenning uitschakelen", "disableVersionDetection": "Versieherkenning uitschakelen",
"noVersionDetectionExplanation": "Deze optie moet alleen worden gebruikt voor apps waar versieherkenning niet correct werkt.", "noVersionDetectionExplanation": "Deze optie moet alleen worden gebruikt voor apps waar versieherkenning niet correct werkt.",
"downloadingX": "Downloaden {}", "downloadingX": "{} downloaden",
"downloadX": "Downloaden",
"downloadedX": "{} gedownload",
"releaseAsset": "Release Activa",
"downloadNotifDescription": "Stelt de gebruiker op de hoogte van de voortgang bij het downloaden van een app", "downloadNotifDescription": "Stelt de gebruiker op de hoogte van de voortgang bij het downloaden van een app",
"noAPKFound": "Geen APK gevonden", "noAPKFound": "Geen APK gevonden",
"noVersionDetection": "Geen versieherkenning", "noVersionDetection": "Geen versieherkenning",
@ -194,100 +203,100 @@
"deleteCategoriesQuestion": "Categorieën verwijderen?", "deleteCategoriesQuestion": "Categorieën verwijderen?",
"categoryDeleteWarning": "Alle apps in verwijderde categorieën worden teruggezet naar 'ongecategoriseerd'.", "categoryDeleteWarning": "Alle apps in verwijderde categorieën worden teruggezet naar 'ongecategoriseerd'.",
"addCategory": "Categorie toevoegen", "addCategory": "Categorie toevoegen",
"label": "Etiket", "label": "Label",
"language": "Taal", "language": "Taal",
"copiedToClipboard": "Gekopieerd naar klembord", "copiedToClipboard": "Gekopieerd naar klembord",
"storagePermissionDenied": "Toegang tot opslag geweigerd", "storagePermissionDenied": "Toegang tot opslag geweigerd",
"selectedCategorizeWarning": "Dit zal eventuele bestaande categorie-instellingen voor de geselecteerde apps vervangen.", "selectedCategorizeWarning": "Dit zal eventuele bestaande categorie-instellingen voor de geselecteerde apps vervangen.",
"filterAPKsByRegEx": "Filter APK's op reguliere expressie", "filterAPKsByRegEx": "APK's flteren met reguliere expressie",
"removeFromObtainium": "Verwijder van Obtainium", "removeFromObtainium": "Uit Obtainium verwijderen",
"uninstallFromDevice": "Verwijder van apparaat", "uninstallFromDevice": "Van apparaat verwijderen",
"onlyWorksWithNonVersionDetectApps": "Werkt alleen voor apps waarbij versieherkenning is uitgeschakeld.", "onlyWorksWithNonVersionDetectApps": "Werkt alleen voor apps waarbij versieherkenning is uitgeschakeld.",
"releaseDateAsVersion": "Gebruik de releasedatum als versie", "releaseDateAsVersion": "Releasedatum als versie gebruiken",
"releaseDateAsVersionExplanation": "Deze optie moet alleen worden gebruikt voor apps waar versieherkenning niet correct werkt, maar waar wel een releasedatum beschikbaar is.", "releaseDateAsVersionExplanation": "Deze optie moet alleen worden gebruikt voor apps waar versieherkenning niet correct werkt, maar waar wel een releasedatum beschikbaar is.",
"changes": "Veranderingen", "changes": "Aanpassingen",
"releaseDate": "Releasedatum", "releaseDate": "Releasedatum",
"importFromURLsInFile": "Importeren vanaf URL's in een bestand (zoals OPML)", "importFromURLsInFile": "Importeren vanaf URL's in een bestand (zoals OPML)",
"versionDetectionExplanation": "Versiereeks afstemmen met versie gedetecteerd door besturingssysteem", "versionDetectionExplanation": "Versiereeks afstemmen met versie gedetecteerd door besturingssysteem",
"versionDetection": "Versieherkenning", "versionDetection": "Versieherkenning",
"standardVersionDetection": "Standaard versieherkenning", "standardVersionDetection": "Standaard versieherkenning",
"groupByCategory": "Groepeer op categorie", "groupByCategory": "Groeperen op categorie",
"autoApkFilterByArch": "Poging om APK's te filteren op CPU-architectuur indien mogelijk", "autoApkFilterByArch": "Probeer APK's te filteren op CPU-architectuur, indien mogelijk",
"overrideSource": "Bron overschrijven", "overrideSource": "Bron overschrijven",
"dontShowAgain": "Laat dit niet meer zien", "dontShowAgain": "Laat dit niet meer zien",
"dontShowTrackOnlyWarnings": "Geen waarschuwingen voor 'Track-Only' weergeven", "dontShowTrackOnlyWarnings": "Geen waarschuwingen weergeven voor 'Alleen volgen'",
"dontShowAPKOriginWarnings": "APK-herkomstwaarschuwingen niet weergeven", "dontShowAPKOriginWarnings": "Geen waarschuwingen weergeven voor APK-herkomst",
"moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave", "moveNonInstalledAppsToBottom": "Niet-geïnstalleerde apps onderaan de apps-lijst plaatsen",
"gitlabPATLabel": "GitLab persoonlijk toegangskenmerk", "gitlabPATLabel": "GitLab persoonlijk toegangskenmerk",
"about": "Over", "about": "Over",
"requiresCredentialsInSettings": "{}: Dit vereist aanvullende referenties (in Instellingen)", "requiresCredentialsInSettings": "{} vereist aanvullende referenties (in Instellingen)",
"checkOnStart": "Controleren op updates bij opstarten", "checkOnStart": "Bij opstarten op updates controleren",
"tryInferAppIdFromCode": "Probeer de app-ID af te leiden uit de broncode", "tryInferAppIdFromCode": "Probeer de app-ID af te leiden uit de broncode",
"removeOnExternalUninstall": "Automatisch extern verwijderde apps verwijderen", "removeOnExternalUninstall": "Extern verwijderde apps automatisch verwijderen",
"pickHighestVersionCode": "Automatisch de APK met de hoogste versiecode selecteren", "pickHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren",
"checkUpdateOnDetailPage": "Controleren op updates bij het openen van een app-detailpagina", "checkUpdateOnDetailPage": "Controleren op updates bij het openen van een app-detailpagina",
"disablePageTransitions": "Schakel overgangsanimaties tussen pagina's uit", "disablePageTransitions": "Overgangsanimaties tussen pagina's uitschakelen",
"reversePageTransitions": "Omgekeerde overgangsanimaties tussen pagina's", "reversePageTransitions": "Overgangsanimaties tussen pagina's herstellen",
"minStarCount": "Minimale Github Stars", "minStarCount": "Minimum Github Stars",
"addInfoBelow": "Voeg deze informatie hieronder toe.", "addInfoBelow": "Deze informatie hieronder toevoegen.",
"addInfoInSettings": "Voeg deze informatie toe in de instellingen.", "addInfoInSettings": "Deze informatie toevoegen in de instellingen.",
"githubSourceNote": "Beperkingen van GitHub kunnen worden vermeden door het gebruik van een API-sleutel.", "githubSourceNote": "Beperkingen van GitHub kunnen worden vermeden door het gebruik van een API-sleutel.",
"sortByLastLinkSegment": "Sorteren op alleen het laatste segment van de link", "sortByLastLinkSegment": "Alleen sorteren op het laatste segment van de link",
"filterReleaseNotesByRegEx": "Filter release-opmerkingen met een reguliere expressie.", "filterReleaseNotesByRegEx": "Release-opmerkingen fiteren met een reguliere expressie.",
"customLinkFilterRegex": "Aangepaste APK-linkfilter met een reguliere expressie (Standaard '.apk$').", "customLinkFilterRegex": "Aangepaste APK-links filteren met een reguliere expressie (Standaard '.apk$').",
"appsPossiblyUpdated": "Poging tot app-updates", "appsPossiblyUpdated": "Pogingen tot app-updates",
"appsPossiblyUpdatedNotifDescription": "Stelt de gebruiker op de hoogte dat updates voor één of meer apps mogelijk in de achtergrond zijn toegepast", "appsPossiblyUpdatedNotifDescription": "Stelt de gebruiker op de hoogte dat updates voor één of meer apps mogelijk in de achtergrond zijn toegepast",
"xWasPossiblyUpdatedToY": "{} mogelijk bijgewerkt naar {}.", "xWasPossiblyUpdatedToY": "{} kan bijgewerkt zijn naar {}.",
"enableBackgroundUpdates": "Achtergrondupdates inschakelen", "enableBackgroundUpdates": "Achtergrond-updates inschakelen",
"backgroundUpdateReqsExplanation": "Achtergrondupdates zijn mogelijk niet voor alle apps mogelijk.", "backgroundUpdateReqsExplanation": "Achtergrond-updates zijn niet voor alle apps mogelijk.",
"backgroundUpdateLimitsExplanation": "Het succes van een installatie in de achtergrond kan alleen worden bepaald wanneer Obtainium is geopend.", "backgroundUpdateLimitsExplanation": "Het succes van een installatie in de achtergrond kan alleen worden bepaald wanneer Obtainium is geopend.",
"verifyLatestTag": "Verifieer de 'Laatste'-tag", "verifyLatestTag": "Het label 'Laatste' verifiëren",
"intermediateLinkRegex": "Filter voor een 'Intermediaire' link om te bezoeken", "intermediateLinkRegex": "Filteren op een 'Intermediaire' link om te bezoeken",
"filterByLinkText": "Links filteren op linktekst", "filterByLinkText": "Links filteren op linktekst",
"intermediateLinkNotFound": "Tussenliggende link niet gevonden", "intermediateLinkNotFound": "Intermediaire link niet gevonden",
"intermediateLink": "Intermediaire link", "intermediateLink": "Intermediaire link",
"exemptFromBackgroundUpdates": "Vrijgesteld van achtergrondupdates (indien ingeschakeld)", "exemptFromBackgroundUpdates": "Vrijgesteld van achtergrond-updates (indien ingeschakeld)",
"bgUpdatesOnWiFiOnly": "Achtergrondupdates uitschakelen wanneer niet verbonden met WiFi", "bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met WiFi",
"autoSelectHighestVersionCode": "Automatisch de APK met de hoogste versiecode selecteren", "autoSelectHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren",
"versionExtractionRegEx": "Reguliere expressie voor versie-extractie", "versionExtractionRegEx": "Reguliere expressie voor versie-extractie",
"matchGroupToUse": "Overeenkomende groep om te gebruiken voor de reguliere expressie voor versie-extractie", "matchGroupToUse": "Overeenkomende groep om te gebruiken voor de reguliere expressie voor versie-extractie",
"highlightTouchTargets": "Markeer minder voor de hand liggende aanraakdoelen.", "highlightTouchTargets": "Minder voor de hand liggende aanraakdoelen markeren.",
"pickExportDir": "Kies de exportmap", "pickExportDir": "Kies de exportmap",
"autoExportOnChanges": "Automatisch exporteren bij wijzigingen", "autoExportOnChanges": "Bij wijzigingen automatisch exporteren",
"includeSettings": "Instellingen opnemen", "includeSettings": "Instellingen opnemen",
"filterVersionsByRegEx": "Filter versies met een reguliere expressie", "filterVersionsByRegEx": "Versies met een reguliere expressie filteren",
"trySelectingSuggestedVersionCode": "Probeer de voorgestelde versiecode APK te selecteren", "trySelectingSuggestedVersionCode": "Probeer de voorgestelde versiecode APK te selecteren",
"dontSortReleasesList": "Volgorde van releases behouden vanuit de API", "dontSortReleasesList": "Volgorde van releases behouden vanuit de API",
"reverseSort": "Sortering omkeren", "reverseSort": "Omgekeerde sortering",
"takeFirstLink": "Neem de eerste link", "takeFirstLink": "Neem de eerste link",
"skipSort": "Sorteren overslaan", "skipSort": "Sortering overslaan",
"debugMenu": "Debug menu", "debugMenu": "Debug-menu",
"bgTaskStarted": "Achtergrondtaak gestart - controleer de logs.", "bgTaskStarted": "Achtergrondtaak gestart - controleer de logs.",
"runBgCheckNow": "Voer nu een achtergrondupdatecontrole uit", "runBgCheckNow": "Nu een achtergrond-updatecontrole uitvoeren",
"versionExtractWholePage": "De reguliere expressie voor versie-extractie toepassen op de hele pagina", "versionExtractWholePage": "De reguliere expressie voor versie-extractie toepassen op de hele pagina",
"installing": "Installeren", "installing": "Installeren",
"skipUpdateNotifications": "Updatemeldingen overslaan", "skipUpdateNotifications": "Updatemeldingen overslaan",
"updatesAvailableNotifChannel": "Updates beschikbaar", "updatesAvailableNotifChannel": "Updates beschikbaar",
"appsUpdatedNotifChannel": "Apps bijgewerkt", "appsUpdatedNotifChannel": "Apps bijgewerkt",
"appsPossiblyUpdatedNotifChannel": "Poging tot app-updates", "appsPossiblyUpdatedNotifChannel": "Pogingen tot app-updates",
"errorCheckingUpdatesNotifChannel": "Foutcontrole bij het zoeken naar updates", "errorCheckingUpdatesNotifChannel": "Foutcontrole bij het zoeken naar updates",
"appsRemovedNotifChannel": "Apps verwijderd", "appsRemovedNotifChannel": "Apps verwijderd",
"downloadingXNotifChannel": "{} downloaden", "downloadingXNotifChannel": "{} downloaden",
"completeAppInstallationNotifChannel": "Voltooien van de app-installatie", "completeAppInstallationNotifChannel": "App-installatie voltooien",
"checkingForUpdatesNotifChannel": "Controleren op updates", "checkingForUpdatesNotifChannel": "Controleren op updates",
"onlyCheckInstalledOrTrackOnlyApps": "Alleen geïnstalleerde en Track-Only apps controleren op updates", "onlyCheckInstalledOrTrackOnlyApps": "Alleen geïnstalleerde apps en 'Alleen volgen' controleren op updates",
"supportFixedAPKURL": "Ondersteuning vaste APK URL's", "supportFixedAPKURL": "Vaste APK-URL's ondersteunen",
"selectX": "Selecteer {}", "selectX": "{} selecteren",
"parallelDownloads": "Parallelle downloads toestaan", "parallelDownloads": "Parallelle downloads toestaan",
"installMethod": "Installatiemethode", "useShizuku": "Shizuku of Sui gebruiken om te installeren",
"normal": "Normaal", "shizukuBinderNotFound": "Shizuku is niet actief",
"root": "Wortel", "shizukuOld": "Verouderde Shizuku-versie (<11) - bijwerken",
"shizukuBinderNotFound": "Shizuku draait niet", "shizukuOldAndroidWithADB": "Shizuku draait op Android < 8.1 met ADB - update Android of gebruik in plaats daarvan Sui",
"useSystemFont": "Gebruik het systeemlettertype", "shizukuPretendToBeGooglePlay": "Google Play instellen als installatiebron (bij Shizuku)",
"systemFontError": "Fout bij het laden van het systeemlettertype: {}", "useSystemFont": "Systeemlettertype gebruiken",
"useVersionCodeAsOSVersion": "Gebruik app versieCode als door OS gedetecteerde versie", "useVersionCodeAsOSVersion": "App versiecode gebruiken als door OS gedetecteerde versie",
"requestHeader": "Verzoekkoptekst", "requestHeader": "Verzoekkoptekst",
"useLatestAssetDateAsReleaseDate": "Gebruik laatste upload als releasedatum", "useLatestAssetDateAsReleaseDate": "Laatste upload als releasedatum gebruiken",
"defaultPseudoVersioningMethod": "Standaard pseudo-versiebeheermethode", "defaultPseudoVersioningMethod": "Standaard pseudo-versiebeheermethode",
"partialAPKHash": "Gedeeltelijke APK-hash", "partialAPKHash": "Gedeeltelijke APK-hash",
"APKLinkHash": "APK-link-hash", "APKLinkHash": "APK-link-hash",
@ -300,22 +309,24 @@
"selfHostedNote": "De \"{}\" dropdown kan gebruikt worden om zelf gehoste/aangepaste instanties van elke bron te bereiken.", "selfHostedNote": "De \"{}\" dropdown kan gebruikt worden om zelf gehoste/aangepaste instanties van elke bron te bereiken.",
"badDownload": "De APK kon niet worden verwerkt (incompatibele of gedeeltelijke download)", "badDownload": "De APK kon niet worden verwerkt (incompatibele of gedeeltelijke download)",
"beforeNewInstallsShareToAppVerifier": "Nieuwe Apps delen met AppVerifier (indien beschikbaar)", "beforeNewInstallsShareToAppVerifier": "Nieuwe Apps delen met AppVerifier (indien beschikbaar)",
"appVerifierInstructionToast": "Deel naar AppVerifier en keer hier terug als je klaar bent.", "appVerifierInstructionToast": "Deel het met AppVerifier en keer daarna hier terug.",
"wiki": "Help/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App-configuraties (gebruik op eigen risico)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App verwijderen?", "one": "App verwijderen?",
"other": "Apps verwijderen?" "other": "Apps verwijderen?"
}, },
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {
"one": "Te veel verzoeken (aantal beperkt) - probeer het opnieuw in {} minuut", "one": "Te veel verzoeken (aantal beperkt) - opnieuw proberen over {} minuut",
"other": "Te veel verzoeken (aantal beperkt) - probeer het opnieuw in {} minuten" "other": "Te veel verzoeken (aantal beperkt) - opnieuw proberen over {} minuten"
}, },
"bgUpdateGotErrorRetryInMinutes": { "bgUpdateGotErrorRetryInMinutes": {
"one": "Achtergrondupdatecontrole heeft een {}, zal een hercontrole plannen over {} minuut", "one": "Achtergrond-updatecontrole heeft een {}, zal een nieuwe controle plannen over {} minuut",
"other": "Achtergrondupdatecontrole heeft een {}, zal een hercontrole plannen over {} minuten" "other": "Achtergrond-updatecontrole heeft een {}, zal een nieuwe controle plannen over {} minuten"
}, },
"bgCheckFoundUpdatesWillNotifyIfNeeded": { "bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "Achtergrondupdatecontrole heeft {} update gevonden - zal de gebruiker op de hoogte stellen indien nodig", "one": "Achtergrond-updatecontrole heeft {} update gevonden - zal de gebruiker op de hoogte stellen indien nodig",
"other": "Achtergrondupdatecontrole heeft {} updates gevonden - zal de gebruiker op de hoogte stellen indien nodig" "other": "Achtergrond-updatecontrole heeft {} updates gevonden - zal de gebruiker op de hoogte stellen indien nodig"
}, },
"apps": { "apps": {
"one": "{} app", "one": "{} app",
@ -343,15 +354,19 @@
}, },
"xAndNMoreUpdatesAvailable": { "xAndNMoreUpdatesAvailable": {
"one": "{} en nog 1 app hebben updates.", "one": "{} en nog 1 app hebben updates.",
"other": "{} en {} meer apps hebben updates." "other": "{} en nog {} apps hebben updates."
}, },
"xAndNMoreUpdatesInstalled": { "xAndNMoreUpdatesInstalled": {
"one": "{} en nog 1 app is bijgewerkt.", "one": "{} en nog 1 app is bijgewerkt.",
"other": "{} en {} meer apps zijn bijgewerkt." "other": "{} en nog {} apps zijn bijgewerkt."
},
"xAndNMoreUpdatesFailed": {
"one": "Bijwerken mislukt voor {} en nog 1 app.",
"other": "Bijwerken mislukt voor {} en nog {} apps."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} en nog 1 app zijn mogelijk bijgewerkt.", "one": "{} en nog 1 app zijn mogelijk bijgewerkt.",
"other": "{} en {} meer apps zijn mogelijk bijgwerkt." "other": "{} en nog {} apps zijn mogelijk bijgwerkt."
}, },
"apk": { "apk": {
"one": "{} APK", "one": "{} APK",

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(Wymagane)", "requiredInBrackets": "(Wymagane)",
"dropdownNoOptsError": "BŁĄD: LISTA ROZWIJANA MUSI MIEĆ CO NAJMNIEJ JEDNĄ OPCJĘ", "dropdownNoOptsError": "BŁĄD: LISTA ROZWIJANA MUSI MIEĆ CO NAJMNIEJ JEDNĄ OPCJĘ",
"colour": "Kolor", "colour": "Kolor",
"standard": "Standard",
"custom": "Niestandardowe",
"useMaterialYou": "Używaj materiałów",
"githubStarredRepos": "Repozytoria GitHub oznaczone gwiazdką", "githubStarredRepos": "Repozytoria GitHub oznaczone gwiazdką",
"uname": "Nazwa użytkownika", "uname": "Nazwa użytkownika",
"wrongArgNum": "Nieprawidłowa liczba podanych argumentów", "wrongArgNum": "Nieprawidłowa liczba podanych argumentów",
@ -110,6 +113,7 @@
"dark": "Ciemny", "dark": "Ciemny",
"light": "Jasny", "light": "Jasny",
"followSystem": "Zgodny z systemem", "followSystem": "Zgodny z systemem",
"followSystemThemeExplanation": "Podążanie za motywem systemowym jest możliwe tylko przy użyciu aplikacji firm trzecich",
"useBlackTheme": "Użyj czarnego motywu", "useBlackTheme": "Użyj czarnego motywu",
"appSortBy": "Sortuj aplikacje według", "appSortBy": "Sortuj aplikacje według",
"authorName": "Autor/Nazwa", "authorName": "Autor/Nazwa",
@ -143,8 +147,10 @@
"noNewUpdates": "Brak nowych aktualizacji.", "noNewUpdates": "Brak nowych aktualizacji.",
"xHasAnUpdate": "{} ma aktualizację.", "xHasAnUpdate": "{} ma aktualizację.",
"appsUpdated": "Zaktualizowano aplikacje", "appsUpdated": "Zaktualizowano aplikacje",
"appsNotUpdated": "Nie udało się zaktualizować aplikacji",
"appsUpdatedNotifDescription": "Informuje, gdy co najmniej jedna aplikacja została zaktualizowana w tle", "appsUpdatedNotifDescription": "Informuje, gdy co najmniej jedna aplikacja została zaktualizowana w tle",
"xWasUpdatedToY": "{} zaktualizowano do {}.", "xWasUpdatedToY": "{} zaktualizowano do {}.",
"xWasNotUpdatedToY": "Nie udało się zaktualizować {} do {}.",
"errorCheckingUpdates": "Błąd sprawdzania aktualizacji", "errorCheckingUpdates": "Błąd sprawdzania aktualizacji",
"errorCheckingUpdatesNotifDescription": "Jest wyświetlane, gdy sprawdzanie aktualizacji w tle nie powiedzie się", "errorCheckingUpdatesNotifDescription": "Jest wyświetlane, gdy sprawdzanie aktualizacji w tle nie powiedzie się",
"appsRemoved": "Usunięte aplikacje", "appsRemoved": "Usunięte aplikacje",
@ -183,6 +189,9 @@
"disableVersionDetection": "Wyłącz wykrywanie wersji", "disableVersionDetection": "Wyłącz wykrywanie wersji",
"noVersionDetectionExplanation": "Opcja ta powinna być używana tylko w przypadku aplikacji, w których wykrywanie wersji nie działa poprawnie.", "noVersionDetectionExplanation": "Opcja ta powinna być używana tylko w przypadku aplikacji, w których wykrywanie wersji nie działa poprawnie.",
"downloadingX": "Pobieranie {}", "downloadingX": "Pobieranie {}",
"downloadX": "Pobierz {}",
"downloadedX": "Pobrano {}",
"releaseAsset": "Release Asset",
"downloadNotifDescription": "Informuje o postępach w pobieraniu aplikacji", "downloadNotifDescription": "Informuje o postępach w pobieraniu aplikacji",
"noAPKFound": "Nie znaleziono pakietu APK", "noAPKFound": "Nie znaleziono pakietu APK",
"noVersionDetection": "Bez wykrywania wersji", "noVersionDetection": "Bez wykrywania wersji",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Obsługuj stałe adresy URL APK", "supportFixedAPKURL": "Obsługuj stałe adresy URL APK",
"selectX": "Wybierz {}", "selectX": "Wybierz {}",
"parallelDownloads": "Zezwól na pobieranie równoległe", "parallelDownloads": "Zezwól na pobieranie równoległe",
"installMethod": "Metoda instalacji", "useShizuku": "Użyj Shizuku lub Sui, aby zainstalować",
"normal": "Normalna",
"root": "Źródło",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"shizukuOld": "Stara wersja Shizuku (<11) - zaktualizuj ją",
"shizukuOldAndroidWithADB": "Shizuku działa na Androidzie < 8.1 z ADB - zaktualizuj Androida lub użyj zamiast tego Sui",
"shizukuPretendToBeGooglePlay": "Ustaw Google Play jako źródło instalacji (jeśli używana jest aplikacja Shizuku).",
"useSystemFont": "Użyj czcionki systemowej", "useSystemFont": "Użyj czcionki systemowej",
"systemFontError": "Błąd podczas ładowania czcionki systemowej: {}",
"useVersionCodeAsOSVersion": "Użyj kodu wersji aplikacji jako wersji wykrytej przez system operacyjny", "useVersionCodeAsOSVersion": "Użyj kodu wersji aplikacji jako wersji wykrytej przez system operacyjny",
"requestHeader": "Nagłówek żądania", "requestHeader": "Nagłówek żądania",
"useLatestAssetDateAsReleaseDate": "Użyj najnowszego przesłanego zasobu jako daty wydania", "useLatestAssetDateAsReleaseDate": "Użyj najnowszego przesłanego zasobu jako daty wydania",
@ -301,6 +310,8 @@
"badDownload": "Nie można przeanalizować pliku APK (niekompatybilny lub częściowo pobrany).", "badDownload": "Nie można przeanalizować pliku APK (niekompatybilny lub częściowo pobrany).",
"beforeNewInstallsShareToAppVerifier": "Udostępnianie nowych aplikacji za pomocą AppVerifier (jeśli dostępne)", "beforeNewInstallsShareToAppVerifier": "Udostępnianie nowych aplikacji za pomocą AppVerifier (jeśli dostępne)",
"appVerifierInstructionToast": "Udostępnij w AppVerifier, a następnie wróć tutaj, gdy będziesz gotowy.", "appVerifierInstructionToast": "Udostępnij w AppVerifier, a następnie wróć tutaj, gdy będziesz gotowy.",
"wiki": "Pomoc/Wiki",
"crowdsourcedConfigsLabel": "Konfiguracje aplikacji pochodzące z crowdsourcingu (korzystanie na własne ryzyko)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Usunąć aplikację?", "one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?", "few": "Usunąć aplikacje?",
@ -373,6 +384,10 @@
"many": "{} i {} innych apek zostało zaktualizowanych.", "many": "{} i {} innych apek zostało zaktualizowanych.",
"other": "{} i {} inne apki zostały zaktualizowane." "other": "{} i {} inne apki zostały zaktualizowane."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Nie udało się zaktualizować {} i 1 innej aplikacji.",
"other": "Nie udało się zaktualizować {} i {} więcej aplikacji."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} i 1 inna apka mogły zostać zaktualizowane.", "one": "{} i 1 inna apka mogły zostać zaktualizowane.",
"few": "{} i {} inne apki mogły zostać zaktualizowane.", "few": "{} i {} inne apki mogły zostać zaktualizowane.",

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(Necessário)", "requiredInBrackets": "(Necessário)",
"dropdownNoOptsError": "ERRO: O DROPDOWN DEVE TER PELO MENOS UMA OPÇÃO", "dropdownNoOptsError": "ERRO: O DROPDOWN DEVE TER PELO MENOS UMA OPÇÃO",
"colour": "Cor", "colour": "Cor",
"standard": "Padrão",
"custom": "Personalizado",
"useMaterialYou": "Utilizar o material que",
"githubStarredRepos": "repositórios favoritos no GitHub", "githubStarredRepos": "repositórios favoritos no GitHub",
"uname": "Nome de usuário", "uname": "Nome de usuário",
"wrongArgNum": "Número de argumentos errado", "wrongArgNum": "Número de argumentos errado",
@ -110,6 +113,7 @@
"dark": "Escuro", "dark": "Escuro",
"light": "Claro", "light": "Claro",
"followSystem": "Padrão do sistema", "followSystem": "Padrão do sistema",
"followSystemThemeExplanation": "O tema do sistema seguinte só é possível através da utilização de aplicações de terceiros",
"useBlackTheme": "Usar tema preto AMOLED", "useBlackTheme": "Usar tema preto AMOLED",
"appSortBy": "Classificar aplicativo por", "appSortBy": "Classificar aplicativo por",
"authorName": "Autor/Nome", "authorName": "Autor/Nome",
@ -143,8 +147,10 @@
"noNewUpdates": "Sem novas atualizações.", "noNewUpdates": "Sem novas atualizações.",
"xHasAnUpdate": "{} tem uma atualização.", "xHasAnUpdate": "{} tem uma atualização.",
"appsUpdated": "Aplicativos atualizados", "appsUpdated": "Aplicativos atualizados",
"appsNotUpdated": "Falha na atualização das aplicações",
"appsUpdatedNotifDescription": "Notifica o usuário quando atualizações foram aplicadas em segundo-plano para um ou mais aplicativos ", "appsUpdatedNotifDescription": "Notifica o usuário quando atualizações foram aplicadas em segundo-plano para um ou mais aplicativos ",
"xWasUpdatedToY": "{} foi atualizado para {}.", "xWasUpdatedToY": "{} foi atualizado para {}.",
"xWasNotUpdatedToY": "Falha ao atualizar {} para {}.",
"errorCheckingUpdates": "Erro ao procurar por atualizações", "errorCheckingUpdates": "Erro ao procurar por atualizações",
"errorCheckingUpdatesNotifDescription": "Uma notificação que mostra quando a checagem por atualizações em segundo-plano falha", "errorCheckingUpdatesNotifDescription": "Uma notificação que mostra quando a checagem por atualizações em segundo-plano falha",
"appsRemoved": "Aplicativos removidos", "appsRemoved": "Aplicativos removidos",
@ -183,6 +189,9 @@
"disableVersionDetection": "Desativar detecção de versão", "disableVersionDetection": "Desativar detecção de versão",
"noVersionDetectionExplanation": "Essa opção deve apenas ser usada por aplicativos onde a detecção de versão não funciona corretamente.", "noVersionDetectionExplanation": "Essa opção deve apenas ser usada por aplicativos onde a detecção de versão não funciona corretamente.",
"downloadingX": "Baixando {}", "downloadingX": "Baixando {}",
"downloadX": "Descarregar {}",
"downloadedX": "Descarregado {}",
"releaseAsset": "Libertação de activos",
"downloadNotifDescription": "Notifica o usuário o progresso do download de um aplicativo", "downloadNotifDescription": "Notifica o usuário o progresso do download de um aplicativo",
"noAPKFound": "APK não encontrado", "noAPKFound": "APK não encontrado",
"noVersionDetection": "Sem detecção de versão", "noVersionDetection": "Sem detecção de versão",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Suporte a APK com URLs fixas", "supportFixedAPKURL": "Suporte a APK com URLs fixas",
"selectX": "Selecionar {}", "selectX": "Selecionar {}",
"parallelDownloads": "Permitir downloads paralelos", "parallelDownloads": "Permitir downloads paralelos",
"installMethod": "Método de instalação", "useShizuku": "Utilizar Shizuku ou Sui para instalar",
"normal": "Normal",
"root": "Root",
"shizukuBinderNotFound": "O Shizuku não está rodando", "shizukuBinderNotFound": "O Shizuku não está rodando",
"shizukuOld": "Versão antiga do Shizuku (<11) - atualizar",
"shizukuOldAndroidWithADB": "Shizuku a funcionar no Android < 8.1 com ADB - atualizar o Android ou utilizar o Sui",
"shizukuPretendToBeGooglePlay": "Definir o Google Play como fonte de instalação (se for utilizado o Shizuku)",
"useSystemFont": "Usar fonte padrão do sistema", "useSystemFont": "Usar fonte padrão do sistema",
"systemFontError": "Erro ao carregar a fonte do sistema: {}",
"useVersionCodeAsOSVersion": "Usar versionCode do aplicativo como versão detectada pelo sistema operacional", "useVersionCodeAsOSVersion": "Usar versionCode do aplicativo como versão detectada pelo sistema operacional",
"requestHeader": "Requisitar cabeçalho", "requestHeader": "Requisitar cabeçalho",
"useLatestAssetDateAsReleaseDate": "Use o último upload de recursos como data de lançamento", "useLatestAssetDateAsReleaseDate": "Use o último upload de recursos como data de lançamento",
@ -301,6 +310,8 @@
"badDownload": "Não foi possível analisar o APK (transferência incompatível ou parcial)", "badDownload": "Não foi possível analisar o APK (transferência incompatível ou parcial)",
"beforeNewInstallsShareToAppVerifier": "Partilhar novas aplicações com o AppVerifier (se disponível)", "beforeNewInstallsShareToAppVerifier": "Partilhar novas aplicações com o AppVerifier (se disponível)",
"appVerifierInstructionToast": "Partilhe com o AppVerifier e, em seguida, regresse aqui quando estiver pronto.", "appVerifierInstructionToast": "Partilhe com o AppVerifier e, em seguida, regresse aqui quando estiver pronto.",
"wiki": "Ajuda/Wiki",
"crowdsourcedConfigsLabel": "Configurações de aplicações de crowdsourcing (utilização por sua conta e risco)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remover aplicativo?", "one": "Remover aplicativo?",
"other": "Remover aplicativos?" "other": "Remover aplicativos?"
@ -349,6 +360,10 @@
"one": "{} e um outro aplicativo foram atualizado.", "one": "{} e um outro aplicativo foram atualizado.",
"other": "{} e {} outros aplicativos foram atualizados." "other": "{} e {} outros aplicativos foram atualizados."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Falha ao atualizar {} e mais 1 aplicação.",
"other": "Falha ao atualizar {} e {} mais aplicações."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} e um outro aplicativo podem ter sido atualizados.", "one": "{} e um outro aplicativo podem ter sido atualizados.",
"other": "{} e {} outros aplicativos podem ter sido atualizados." "other": "{} e {} outros aplicativos podem ter sido atualizados."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(обязательно)", "requiredInBrackets": "(обязательно)",
"dropdownNoOptsError": "Ошибка: в выпадающем списке должна быть выбрана хотя бы одна настройка", "dropdownNoOptsError": "Ошибка: в выпадающем списке должна быть выбрана хотя бы одна настройка",
"colour": "Цвет", "colour": "Цвет",
"standard": "Стандартный",
"custom": "Индивидуальный",
"useMaterialYou": "Использовать Material You",
"githubStarredRepos": "Избранные репозитории GitHub", "githubStarredRepos": "Избранные репозитории GitHub",
"uname": "Имя пользователя", "uname": "Имя пользователя",
"wrongArgNum": "Неправильное количество предоставленных аргументов", "wrongArgNum": "Неправильное количество предоставленных аргументов",
@ -110,6 +113,7 @@
"dark": "Тёмная", "dark": "Тёмная",
"light": "Светлая", "light": "Светлая",
"followSystem": "Системная", "followSystem": "Системная",
"followSystemThemeExplanation": "Следование системной теме возможно только при использовании сторонних приложений",
"useBlackTheme": "Использовать чёрную тему", "useBlackTheme": "Использовать чёрную тему",
"appSortBy": "Сортировка приложений", "appSortBy": "Сортировка приложений",
"authorName": "Автор/Название", "authorName": "Автор/Название",
@ -143,8 +147,10 @@
"noNewUpdates": "Нет новых обновлений", "noNewUpdates": "Нет новых обновлений",
"xHasAnUpdate": "{} есть обновление", "xHasAnUpdate": "{} есть обновление",
"appsUpdated": "Приложения обновлены", "appsUpdated": "Приложения обновлены",
"appsNotUpdated": "Не удалось обновить приложения",
"appsUpdatedNotifDescription": "Уведомляет об обновлении одного или нескольких приложений в фоновом режиме", "appsUpdatedNotifDescription": "Уведомляет об обновлении одного или нескольких приложений в фоновом режиме",
"xWasUpdatedToY": "{} была обновлена до версии {}", "xWasUpdatedToY": "{} была обновлена до версии {}",
"xWasNotUpdatedToY": "Не удалось обновить {} до версии {}",
"errorCheckingUpdates": "Ошибка при проверке обновлений", "errorCheckingUpdates": "Ошибка при проверке обновлений",
"errorCheckingUpdatesNotifDescription": "Уведомление о завершении проверки обновлений в фоновом режиме с ошибкой", "errorCheckingUpdatesNotifDescription": "Уведомление о завершении проверки обновлений в фоновом режиме с ошибкой",
"appsRemoved": "Приложение удалено", "appsRemoved": "Приложение удалено",
@ -183,6 +189,9 @@
"disableVersionDetection": "Отключить обнаружение версии", "disableVersionDetection": "Отключить обнаружение версии",
"noVersionDetectionExplanation": "Эта настройка должна использоваться только для приложений, где обнаружение версии не работает корректно", "noVersionDetectionExplanation": "Эта настройка должна использоваться только для приложений, где обнаружение версии не работает корректно",
"downloadingX": "Загрузка {}", "downloadingX": "Загрузка {}",
"downloadX": "Скачать {}",
"downloadedX": "Загружено {}",
"releaseAsset": "Освобождение актива",
"downloadNotifDescription": "Уведомляет пользователя о прогрессе загрузки приложения", "downloadNotifDescription": "Уведомляет пользователя о прогрессе загрузки приложения",
"noAPKFound": "APK не найден", "noAPKFound": "APK не найден",
"noVersionDetection": "Обнаружение версий отключено", "noVersionDetection": "Обнаружение версий отключено",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Поддержка фиксированных URL-адресов APK", "supportFixedAPKURL": "Поддержка фиксированных URL-адресов APK",
"selectX": "Выбрать {}", "selectX": "Выбрать {}",
"parallelDownloads": "Разрешить параллельные загрузки", "parallelDownloads": "Разрешить параллельные загрузки",
"installMethod": "Метод установки", "useShizuku": "Использовать Shizuku или Sui для установки",
"normal": "Нормальный", "shizukuBinderNotFound": "Совместимый сервис Shizuku не найден, возможно он не запущен",
"root": "Суперпользователь", "shizukuOld": "Устаревшая версия Shizuku (<11), обновите",
"shizukuBinderNotFound": "Совместимый сервис Shizuku не найден", "shizukuOldAndroidWithADB": "Shizuku работает на Android < 8.1 с ADB, обновите Android или используйте Sui",
"shizukuPretendToBeGooglePlay": "Указать Google Play как источник установки (если используется Shizuku)",
"useSystemFont": "Использовать системный шрифт", "useSystemFont": "Использовать системный шрифт",
"systemFontError": "Ошибка загрузки системного шрифта: {}",
"useVersionCodeAsOSVersion": "Использовать код версии приложения как версию, обнаруженную ОС", "useVersionCodeAsOSVersion": "Использовать код версии приложения как версию, обнаруженную ОС",
"requestHeader": "Заголовок запроса", "requestHeader": "Заголовок запроса",
"useLatestAssetDateAsReleaseDate": "Использовать последнюю загрузку ресурса в качестве даты выпуска", "useLatestAssetDateAsReleaseDate": "Использовать последнюю загрузку ресурса в качестве даты выпуска",
@ -301,6 +310,8 @@
"badDownload": "APK не удалось разобрать (несовместимая или неполная загрузка)", "badDownload": "APK не удалось разобрать (несовместимая или неполная загрузка)",
"beforeNewInstallsShareToAppVerifier": "Поделитесь новыми приложениями с AppVerifier (если доступно)", "beforeNewInstallsShareToAppVerifier": "Поделитесь новыми приложениями с AppVerifier (если доступно)",
"appVerifierInstructionToast": "Поделитесь с AppVerifier, а затем вернитесь сюда, когда будете готовы.", "appVerifierInstructionToast": "Поделитесь с AppVerifier, а затем вернитесь сюда, когда будете готовы.",
"wiki": "Помощь/Вики",
"crowdsourcedConfigsLabel": "Конфигурации приложений на основе краудсорсинга (используйте на свой страх и риск)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Удалить приложение?", "one": "Удалить приложение?",
"other": "Удалить приложения?" "other": "Удалить приложения?"
@ -349,12 +360,16 @@
"one": "{} и ещё 1 приложение были обновлены", "one": "{} и ещё 1 приложение были обновлены",
"other": "{} и ещё {} приложений были обновлены" "other": "{} и ещё {} приложений были обновлены"
}, },
"xAndNMoreUpdatesFailed": {
"one": "Не удалось обновить {} и ещё 1 приложение",
"other": "Не удалось обновить {} и ещё {} приложений"
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} и ещё 1 приложение могли быть обновлены", "one": "{} и ещё 1 приложение могли быть обновлены",
"other": "{} и ещё {} приложений могли быть обновлены" "other": "{} и ещё {} приложений могли быть обновлены"
}, },
"apk": { "apk": {
"one": "{} APK", "one": "{} APK",
"other": "{} APKs" "other": "{} APKи"
} }
} }

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(Kräver)", "requiredInBrackets": "(Kräver)",
"dropdownNoOptsError": "FEL: DROPDOWN MÅSTE HA MINST ETT OPT", "dropdownNoOptsError": "FEL: DROPDOWN MÅSTE HA MINST ETT OPT",
"colour": "Färg", "colour": "Färg",
"standard": "Standard",
"custom": "Anpassad",
"useMaterialYou": "Använd material Du",
"githubStarredRepos": "GitHub Stjärnmärkta Förråd", "githubStarredRepos": "GitHub Stjärnmärkta Förråd",
"uname": "Användarnamn", "uname": "Användarnamn",
"wrongArgNum": "Fel antal argument har angetts", "wrongArgNum": "Fel antal argument har angetts",
@ -110,6 +113,7 @@
"dark": "Mörkt", "dark": "Mörkt",
"light": "Ljust", "light": "Ljust",
"followSystem": "Följ System", "followSystem": "Följ System",
"followSystemThemeExplanation": "Följande systemtema är endast möjligt med hjälp av tredjepartsapplikationer",
"useBlackTheme": "Använd svart tema", "useBlackTheme": "Använd svart tema",
"appSortBy": "Sortera Appar via", "appSortBy": "Sortera Appar via",
"authorName": "Utvecklare/Namn", "authorName": "Utvecklare/Namn",
@ -143,8 +147,10 @@
"noNewUpdates": "Inga nya uppdateringar.", "noNewUpdates": "Inga nya uppdateringar.",
"xHasAnUpdate": "{} har en uppdatering.", "xHasAnUpdate": "{} har en uppdatering.",
"appsUpdated": "Appar Uppdaterade", "appsUpdated": "Appar Uppdaterade",
"appsNotUpdated": "Misslyckades med att uppdatera applikationer",
"appsUpdatedNotifDescription": "Meddelar användaren att uppdateringar av en eller flera appar har tillämpats i bakgrunden", "appsUpdatedNotifDescription": "Meddelar användaren att uppdateringar av en eller flera appar har tillämpats i bakgrunden",
"xWasUpdatedToY": "{} uppdaterades till {}.", "xWasUpdatedToY": "{} uppdaterades till {}.",
"xWasNotUpdatedToY": "Det gick inte att uppdatera {} till {}.",
"errorCheckingUpdates": "Fel vid uppdateringskoll", "errorCheckingUpdates": "Fel vid uppdateringskoll",
"errorCheckingUpdatesNotifDescription": "En aviserings som visar när bakgrundsuppdateringarkollar misslyckas", "errorCheckingUpdatesNotifDescription": "En aviserings som visar när bakgrundsuppdateringarkollar misslyckas",
"appsRemoved": "Appar borttagna", "appsRemoved": "Appar borttagna",
@ -183,6 +189,9 @@
"disableVersionDetection": "Inaktivera versionsdetektering", "disableVersionDetection": "Inaktivera versionsdetektering",
"noVersionDetectionExplanation": "Det här alternativet bör endast användas för appar där versionsidentifiering inte fungerar korrekt.", "noVersionDetectionExplanation": "Det här alternativet bör endast användas för appar där versionsidentifiering inte fungerar korrekt.",
"downloadingX": "Laddar ner {}", "downloadingX": "Laddar ner {}",
"downloadX": "Ladda ner {}",
"downloadedX": "Nedladdad {}",
"releaseAsset": "Frigör tillgång",
"downloadNotifDescription": "Meddelar användaren om framstegen med att ladda ner en app", "downloadNotifDescription": "Meddelar användaren om framstegen med att ladda ner en app",
"noAPKFound": "Ingen APK funnen", "noAPKFound": "Ingen APK funnen",
"noVersionDetection": "Ingen versiondetektering", "noVersionDetection": "Ingen versiondetektering",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Stöd fasta APK-webbadresser", "supportFixedAPKURL": "Stöd fasta APK-webbadresser",
"selectX": "Välj {}", "selectX": "Välj {}",
"parallelDownloads": "Tillåt parallella nedladdningar", "parallelDownloads": "Tillåt parallella nedladdningar",
"installMethod": "Installationsmetod", "useShizuku": "Använd Shizuku eller Sui för att installera",
"normal": "Vanligt",
"root": "Rot",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"shizukuOld": "Gammal Shizuku-version (<11) - uppdatera den",
"shizukuOldAndroidWithADB": "Shizuku körs på Android < 8.1 med ADB - uppdatera Android eller använd Sui istället",
"shizukuPretendToBeGooglePlay": "Ange Google Play som installationskälla (om Shizuku används)",
"useSystemFont": "Använd systemteckensnittet", "useSystemFont": "Använd systemteckensnittet",
"systemFontError": "Fel vid laddning av systemteckensnittet: {}",
"useVersionCodeAsOSVersion": "Använd appversionskoden som OS-upptäckt version", "useVersionCodeAsOSVersion": "Använd appversionskoden som OS-upptäckt version",
"requestHeader": "Rubrik för begäran", "requestHeader": "Rubrik för begäran",
"useLatestAssetDateAsReleaseDate": "Använd senaste tillgångsuppladdning som releasedatum", "useLatestAssetDateAsReleaseDate": "Använd senaste tillgångsuppladdning som releasedatum",
@ -301,6 +310,8 @@
"badDownload": "APK kunde inte analyseras (inkompatibel eller partiell nedladdning)", "badDownload": "APK kunde inte analyseras (inkompatibel eller partiell nedladdning)",
"beforeNewInstallsShareToAppVerifier": "Dela nya appar med AppVerifier (om tillgängligt)", "beforeNewInstallsShareToAppVerifier": "Dela nya appar med AppVerifier (om tillgängligt)",
"appVerifierInstructionToast": "Dela till AppVerifier och återvänd sedan hit när du är klar.", "appVerifierInstructionToast": "Dela till AppVerifier och återvänd sedan hit när du är klar.",
"wiki": "Hjälp/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourcade appkonfigurationer (använd på egen risk)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Ta Bort App?", "one": "Ta Bort App?",
"other": "Ta Bort Appar?" "other": "Ta Bort Appar?"
@ -349,6 +360,10 @@
"one": "{} och 1 till app uppdaterades.", "one": "{} och 1 till app uppdaterades.",
"other": "{} och {} appar till uppdaterades." "other": "{} och {} appar till uppdaterades."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Misslyckades med att uppdatera {} och ytterligare 1 app.",
"other": "Det gick inte att uppdatera {} och {} fler appar."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} och 1 till app kan ha uppdaterats.", "one": "{} och 1 till app kan ha uppdaterats.",
"other": "{} och {} appar till kan ha uppdaterats." "other": "{} och {} appar till kan ha uppdaterats."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(Gerekli)", "requiredInBrackets": "(Gerekli)",
"dropdownNoOptsError": "HATA: DİPLOMADA EN AZ BİR SEÇENEK OLMALI", "dropdownNoOptsError": "HATA: DİPLOMADA EN AZ BİR SEÇENEK OLMALI",
"colour": "Renk", "colour": "Renk",
"standard": "Standart",
"custom": "Özel",
"useMaterialYou": "Sizin Malzemenizi Kullanın",
"githubStarredRepos": "GitHub'a Yıldızlı Depolar", "githubStarredRepos": "GitHub'a Yıldızlı Depolar",
"uname": "Kullanıcı Adı", "uname": "Kullanıcı Adı",
"wrongArgNum": "Hatalı argüman sayısı sağlandı", "wrongArgNum": "Hatalı argüman sayısı sağlandı",
@ -110,6 +113,7 @@
"dark": "Koyu", "dark": "Koyu",
"light": "Aydınlık", "light": "Aydınlık",
"followSystem": "Sistemi Takip Et", "followSystem": "Sistemi Takip Et",
"followSystemThemeExplanation": "Sistem temasını takip etmek yalnızca üçüncü taraf uygulamaları kullanarak mümkündür",
"useBlackTheme": "Saf siyah koyu temasını kullan", "useBlackTheme": "Saf siyah koyu temasını kullan",
"appSortBy": "Uygulama Sıralama Ölçütü", "appSortBy": "Uygulama Sıralama Ölçütü",
"authorName": "Yazar/Ad", "authorName": "Yazar/Ad",
@ -143,8 +147,10 @@
"noNewUpdates": "Yeni güncelleme yok.", "noNewUpdates": "Yeni güncelleme yok.",
"xHasAnUpdate": "{} güncelleme alıyor.", "xHasAnUpdate": "{} güncelleme alıyor.",
"appsUpdated": "Uygulamalar Güncellendi", "appsUpdated": "Uygulamalar Güncellendi",
"appsNotUpdated": "Uygulamalar güncellenemedi",
"appsUpdatedNotifDescription": "Kullanıcıya bir veya daha fazla uygulamanın arka planda güncellendiğine dair bilgi verir", "appsUpdatedNotifDescription": "Kullanıcıya bir veya daha fazla uygulamanın arka planda güncellendiğine dair bilgi verir",
"xWasUpdatedToY": "{} şu sürüme güncellendi: {}.", "xWasUpdatedToY": "{} şu sürüme güncellendi: {}.",
"xWasNotUpdatedToY": "{} öğesi {} olarak güncellenemedi.",
"errorCheckingUpdates": "Güncellemeler Kontrol Edilirken Hata Oluştu", "errorCheckingUpdates": "Güncellemeler Kontrol Edilirken Hata Oluştu",
"errorCheckingUpdatesNotifDescription": "Arka planda güncelleme kontrolü sırasında hata oluştuğunda görünen bir bildirim", "errorCheckingUpdatesNotifDescription": "Arka planda güncelleme kontrolü sırasında hata oluştuğunda görünen bir bildirim",
"appsRemoved": "Uygulamalar Kaldırıldı", "appsRemoved": "Uygulamalar Kaldırıldı",
@ -183,6 +189,9 @@
"disableVersionDetection": "Sürüm Algılama Devre Dışı", "disableVersionDetection": "Sürüm Algılama Devre Dışı",
"noVersionDetectionExplanation": "Bu seçenek, sürüm algılamanın doğru çalışmadığı uygulamalar için kullanılmalıdır.", "noVersionDetectionExplanation": "Bu seçenek, sürüm algılamanın doğru çalışmadığı uygulamalar için kullanılmalıdır.",
"downloadingX": "{} İndiriliyor", "downloadingX": "{} İndiriliyor",
"downloadX": "İndir {}",
"downloadedX": "İndirildi {}",
"releaseAsset": "Varlık Serbest Bırakma",
"downloadNotifDescription": "Bir uygulamanın indirme sürecinde ilerlemeyi bildiren bir bildirim", "downloadNotifDescription": "Bir uygulamanın indirme sürecinde ilerlemeyi bildiren bir bildirim",
"noAPKFound": "APK bulunamadı", "noAPKFound": "APK bulunamadı",
"noVersionDetection": "Sürüm Algılanamıyor", "noVersionDetection": "Sürüm Algılanamıyor",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Sabit APK URL'lerini destekleyin", "supportFixedAPKURL": "Sabit APK URL'lerini destekleyin",
"selectX": "Seçme {}", "selectX": "Seçme {}",
"parallelDownloads": "Paralel indirmelere izin ver", "parallelDownloads": "Paralel indirmelere izin ver",
"installMethod": "Kurulum yöntemi", "useShizuku": "Yüklemek için Shizuku veya Sui'yi kullanın",
"normal": "Normal",
"root": "Kök",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"shizukuOld": "Eski Shizuku sürümü (<11) - güncelleyin",
"shizukuOldAndroidWithADB": "Shizuku ADB ile Android < 8.1 üzerinde çalışıyor - Android'i güncelleyin veya bunun yerine Sui kullanın",
"shizukuPretendToBeGooglePlay": "Google Play'i yükleme kaynağı olarak ayarlayın (Shizuku kullanılıyorsa)",
"useSystemFont": "Sistem yazı tipini kullan", "useSystemFont": "Sistem yazı tipini kullan",
"systemFontError": "Sistem yazı tipi yüklenirken hata oluştu: {}",
"useVersionCodeAsOSVersion": "Uygulama versionCode'unu işletim sistemi tarafından algılanan sürüm olarak kullan", "useVersionCodeAsOSVersion": "Uygulama versionCode'unu işletim sistemi tarafından algılanan sürüm olarak kullan",
"requestHeader": "Başlık talep et", "requestHeader": "Başlık talep et",
"useLatestAssetDateAsReleaseDate": "Yayın tarihi olarak en son öğe yüklemesini kullan", "useLatestAssetDateAsReleaseDate": "Yayın tarihi olarak en son öğe yüklemesini kullan",
@ -301,6 +310,8 @@
"badDownload": "APK ayrıştırılamadı (uyumsuz veya kısmi indirme)", "badDownload": "APK ayrıştırılamadı (uyumsuz veya kısmi indirme)",
"beforeNewInstallsShareToAppVerifier": "Yeni Uygulamaları AppVerifier ile paylaşın (varsa)", "beforeNewInstallsShareToAppVerifier": "Yeni Uygulamaları AppVerifier ile paylaşın (varsa)",
"appVerifierInstructionToast": "AppVerifier ile paylaşın, hazır olduğunuzda buraya dönün.", "appVerifierInstructionToast": "AppVerifier ile paylaşın, hazır olduğunuzda buraya dönün.",
"wiki": "Yardım/Wiki",
"crowdsourcedConfigsLabel": "Kitle Kaynaklı Uygulama Yapılandırmaları (riski size ait olmak üzere kullanın)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Uygulamayı Kaldır?", "one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?" "other": "Uygulamaları Kaldır?"
@ -349,6 +360,10 @@
"one": "{} ve 1 diğer uygulama güncellendi.", "one": "{} ve 1 diğer uygulama güncellendi.",
"other": "{} ve {} daha fazla uygulama güncellendi." "other": "{} ve {} daha fazla uygulama güncellendi."
}, },
"xAndNMoreUpdatesFailed": {
"one": "{} ve 1 uygulama daha güncellenemedi.",
"other": "{} ve {} daha fazla uygulama güncellenemedi."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} ve 1 diğer uygulama muhtemelen güncellendi.", "one": "{} ve 1 diğer uygulama muhtemelen güncellendi.",
"other": "{} ve {} daha fazla uygulama muhtemelen güncellendi." "other": "{} ve {} daha fazla uygulama muhtemelen güncellendi."

View File

@ -22,6 +22,9 @@
"requiredInBrackets": "(Обов'язково)", "requiredInBrackets": "(Обов'язково)",
"dropdownNoOptsError": "ПОМИЛКА: В ВИПАДАЮЧОМУ СПИСКУ МАЄ БУТИ ХОЧА Б ОДИН ЕЛЕМЕНТ", "dropdownNoOptsError": "ПОМИЛКА: В ВИПАДАЮЧОМУ СПИСКУ МАЄ БУТИ ХОЧА Б ОДИН ЕЛЕМЕНТ",
"colour": "Колір", "colour": "Колір",
"standard": "Стандартний",
"custom": "Нестандартний",
"useMaterialYou": "Використовуйте матеріал, який ви",
"githubStarredRepos": "Відзначені репозиторії GitHub", "githubStarredRepos": "Відзначені репозиторії GitHub",
"uname": "Ім'я користувача", "uname": "Ім'я користувача",
"wrongArgNum": "Надано неправильну кількість аргументів", "wrongArgNum": "Надано неправильну кількість аргументів",
@ -110,6 +113,7 @@
"dark": "Темна", "dark": "Темна",
"light": "Світла", "light": "Світла",
"followSystem": "Дотримуватися системи", "followSystem": "Дотримуватися системи",
"followSystemThemeExplanation": "Зміна теми системи можлива лише за допомогою сторонніх додатків",
"useBlackTheme": "Використовувати чорну тему (Amoled)", "useBlackTheme": "Використовувати чорну тему (Amoled)",
"appSortBy": "Сортувати застосунки за", "appSortBy": "Сортувати застосунки за",
"authorName": "Автор/Назва", "authorName": "Автор/Назва",
@ -143,8 +147,10 @@
"noNewUpdates": "Немає нових оновлень.", "noNewUpdates": "Немає нових оновлень.",
"xHasAnUpdate": "{} має оновлення.", "xHasAnUpdate": "{} має оновлення.",
"appsUpdated": "Застосунки оновлено", "appsUpdated": "Застосунки оновлено",
"appsNotUpdated": "Не вдалося оновити програми",
"appsUpdatedNotifDescription": "Повідомляє користувача, що оновлення одного чи декількох застосунків було застосовано в фоновому режимі", "appsUpdatedNotifDescription": "Повідомляє користувача, що оновлення одного чи декількох застосунків було застосовано в фоновому режимі",
"xWasUpdatedToY": "{} було оновлено до {}.", "xWasUpdatedToY": "{} було оновлено до {}.",
"xWasNotUpdatedToY": "Не вдалося оновити {} на {}.",
"errorCheckingUpdates": "Помилка перевірки оновлень", "errorCheckingUpdates": "Помилка перевірки оновлень",
"errorCheckingUpdatesNotifDescription": "Повідомлення, яке з'являється, коли перевірка оновлень в фоновому режимі завершується невдачею", "errorCheckingUpdatesNotifDescription": "Повідомлення, яке з'являється, коли перевірка оновлень в фоновому режимі завершується невдачею",
"appsRemoved": "Застосунки видалено", "appsRemoved": "Застосунки видалено",
@ -183,6 +189,9 @@
"disableVersionDetection": "Вимкнути визначення версії", "disableVersionDetection": "Вимкнути визначення версії",
"noVersionDetectionExplanation": "Цю опцію слід використовувати лише для застосунків, де визначення версії працює неправильно.", "noVersionDetectionExplanation": "Цю опцію слід використовувати лише для застосунків, де визначення версії працює неправильно.",
"downloadingX": "Завантаження {}", "downloadingX": "Завантаження {}",
"downloadX": "Завантажити {}",
"downloadedX": "Завантажено {}",
"releaseAsset": "Звільнити актив",
"downloadNotifDescription": "Повідомляє користувача про прогрес завантаження застосунку", "downloadNotifDescription": "Повідомляє користувача про прогрес завантаження застосунку",
"noAPKFound": "APK не знайдено", "noAPKFound": "APK не знайдено",
"noVersionDetection": "Визначення версії відключено", "noVersionDetection": "Визначення версії відключено",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Підтримка фіксованих посилань на APK", "supportFixedAPKURL": "Підтримка фіксованих посилань на APK",
"selectX": "Вибрати {}", "selectX": "Вибрати {}",
"parallelDownloads": "Дозволити паралельні завантаження", "parallelDownloads": "Дозволити паралельні завантаження",
"installMethod": "Метод встановлення", "useShizuku": "Використовуйте Shizuku або Sui для встановлення",
"normal": "Звичайний",
"root": "Root",
"shizukuBinderNotFound": "Сумісний сервіс Shizuku не було знайдено", "shizukuBinderNotFound": "Сумісний сервіс Shizuku не було знайдено",
"shizukuOld": "Стара версія Shizuku (<11) - оновіть її",
"shizukuOldAndroidWithADB": "Shizuku працює на Android < 8.1 з ADB - оновіть Android або використовуйте Sui замість нього",
"shizukuPretendToBeGooglePlay": "Виберіть Google Play як джерело встановлення (якщо використовується Shizuku)",
"useSystemFont": "Використовувати системний шрифт", "useSystemFont": "Використовувати системний шрифт",
"systemFontError": "Помилка завантаження системного шрифту: {}",
"useVersionCodeAsOSVersion": "Використовувати код версії застосунку як версію, визначену операційною системою", "useVersionCodeAsOSVersion": "Використовувати код версії застосунку як версію, визначену операційною системою",
"requestHeader": "Заголовок запиту", "requestHeader": "Заголовок запиту",
"useLatestAssetDateAsReleaseDate": "Використовувати останню дату завантаження ресурсу як дату випуску", "useLatestAssetDateAsReleaseDate": "Використовувати останню дату завантаження ресурсу як дату випуску",
@ -301,6 +310,8 @@
"badDownload": "APK не вдалося розпарсити (несумісний або часткове завантаження)", "badDownload": "APK не вдалося розпарсити (несумісний або часткове завантаження)",
"beforeNewInstallsShareToAppVerifier": "Діліться новими додатками з AppVerifier (якщо доступно)", "beforeNewInstallsShareToAppVerifier": "Діліться новими додатками з AppVerifier (якщо доступно)",
"appVerifierInstructionToast": "Надішліть на AppVerifier, а потім поверніться сюди, коли будете готові.", "appVerifierInstructionToast": "Надішліть на AppVerifier, а потім поверніться сюди, коли будете готові.",
"wiki": "Довідка/Вікі",
"crowdsourcedConfigsLabel": "Краудсорсингові конфігурації додатків (використовуйте на свій страх і ризик)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Видалити застосунок?", "one": "Видалити застосунок?",
"other": "Видалити застосунки?" "other": "Видалити застосунки?"
@ -349,6 +360,10 @@
"one": "{} та ще 1 застосунок було оновлено.", "one": "{} та ще 1 застосунок було оновлено.",
"other": "{} та ще {} застосунків було оновлено." "other": "{} та ще {} застосунків було оновлено."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Не вдалося оновити {} та ще 1 програму.",
"other": "Не вдалося оновити {} і {} та інші програми."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} та ще 1 застосунок можливо було оновлено.", "one": "{} та ще 1 застосунок можливо було оновлено.",
"other": "{} та ще {} застосунків можливо було оновлено." "other": "{} та ще {} застосунків можливо було оновлено."

View File

@ -11,7 +11,7 @@
"unexpectedError": "Lỗi không mong đợi", "unexpectedError": "Lỗi không mong đợi",
"ok": "OK", "ok": "OK",
"and": "và", "and": "và",
"githubPATLabel": "GitHub Token (Tăng tốc độ, giới hạn)", "githubPATLabel": "Token truy cập cá nhân GitHub (Cải thiện tốc độ giới hạn)",
"includePrereleases": "Bao gồm các bản phát hành trước", "includePrereleases": "Bao gồm các bản phát hành trước",
"fallbackToOlderReleases": "Dự phòng về bản phát hành cũ hơn", "fallbackToOlderReleases": "Dự phòng về bản phát hành cũ hơn",
"filterReleaseTitlesByRegEx": "Lọc tiêu đề bản phát hành theo biểu thức chính quy", "filterReleaseTitlesByRegEx": "Lọc tiêu đề bản phát hành theo biểu thức chính quy",
@ -22,6 +22,9 @@
"requiredInBrackets": "(Yêu cầu)", "requiredInBrackets": "(Yêu cầu)",
"dropdownNoOptsError": "LỖI: TẢI XUỐNG PHẢI CÓ ÍT NHẤT MỘT LỰA CHỌN", "dropdownNoOptsError": "LỖI: TẢI XUỐNG PHẢI CÓ ÍT NHẤT MỘT LỰA CHỌN",
"colour": "Màu sắc", "colour": "Màu sắc",
"standard": "Standard",
"custom": "Custom",
"useMaterialYou": "Use Material You",
"githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub", "githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub",
"uname": "Tên người dùng", "uname": "Tên người dùng",
"wrongArgNum": "Số lượng đối số được cung cấp sai", "wrongArgNum": "Số lượng đối số được cung cấp sai",
@ -110,6 +113,7 @@
"dark": "Tối", "dark": "Tối",
"light": "Sáng", "light": "Sáng",
"followSystem": "Theo hệ thống", "followSystem": "Theo hệ thống",
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications",
"useBlackTheme": "Nền đen", "useBlackTheme": "Nền đen",
"appSortBy": "Sắp xếp ứng dụng", "appSortBy": "Sắp xếp ứng dụng",
"authorName": "Tác giả", "authorName": "Tác giả",
@ -143,8 +147,10 @@
"noNewUpdates": "Không có bản cập nhật mới.", "noNewUpdates": "Không có bản cập nhật mới.",
"xHasAnUpdate": "{} có bản cập nhật.", "xHasAnUpdate": "{} có bản cập nhật.",
"appsUpdated": "Ứng dụng đã cập nhật ", "appsUpdated": "Ứng dụng đã cập nhật ",
"appsNotUpdated": "Failed to update applications",
"appsUpdatedNotifDescription": "Thông báo cho người dùng rằng các bản cập nhật cho một hoặc nhiều Ứng dụng đã được áp dụng trong nền", "appsUpdatedNotifDescription": "Thông báo cho người dùng rằng các bản cập nhật cho một hoặc nhiều Ứng dụng đã được áp dụng trong nền",
"xWasUpdatedToY": "{} đã được cập nhật thành {}.", "xWasUpdatedToY": "{} đã được cập nhật thành {}.",
"xWasNotUpdatedToY": "Failed to update {} to {}.",
"errorCheckingUpdates": "Lỗi kiểm tra bản cập nhật", "errorCheckingUpdates": "Lỗi kiểm tra bản cập nhật",
"errorCheckingUpdatesNotifDescription": "Thông báo hiển thị khi kiểm tra cập nhật nền không thành công", "errorCheckingUpdatesNotifDescription": "Thông báo hiển thị khi kiểm tra cập nhật nền không thành công",
"appsRemoved": "Ứng dụng đã loại bỏ", "appsRemoved": "Ứng dụng đã loại bỏ",
@ -183,6 +189,9 @@
"disableVersionDetection": "Tắt tính năng phát hiện phiên bản", "disableVersionDetection": "Tắt tính năng phát hiện phiên bản",
"noVersionDetectionExplanation": "Chỉ nên sử dụng tùy chọn này cho Ứng dụng mà tính năng phát hiện phiên bản không hoạt động chính xác.", "noVersionDetectionExplanation": "Chỉ nên sử dụng tùy chọn này cho Ứng dụng mà tính năng phát hiện phiên bản không hoạt động chính xác.",
"downloadingX": "Đang tải xuống {}", "downloadingX": "Đang tải xuống {}",
"downloadX": "Download {}",
"downloadedX": "Downloaded {}",
"releaseAsset": "Release Asset",
"downloadNotifDescription": "Thông báo cho người dùng về tiến trình tải xuống Ứng dụng", "downloadNotifDescription": "Thông báo cho người dùng về tiến trình tải xuống Ứng dụng",
"noAPKFound": "Không tìm thấy APK", "noAPKFound": "Không tìm thấy APK",
"noVersionDetection": "Không phát hiện phiên bản", "noVersionDetection": "Không phát hiện phiên bản",
@ -218,7 +227,7 @@
"dontShowTrackOnlyWarnings": "Không hiển thị cảnh báo 'Chỉ theo dõi'", "dontShowTrackOnlyWarnings": "Không hiển thị cảnh báo 'Chỉ theo dõi'",
"dontShowAPKOriginWarnings": "Không hiển thị cảnh báo nguồn gốc APK", "dontShowAPKOriginWarnings": "Không hiển thị cảnh báo nguồn gốc APK",
"moveNonInstalledAppsToBottom": "Chuyển Ứng dụng chưa được cài đặt xuống cuối danh sách", "moveNonInstalledAppsToBottom": "Chuyển Ứng dụng chưa được cài đặt xuống cuối danh sách",
"gitlabPATLabel": "GitLab Token", "gitlabPATLabel": "Token truy cập cá nhân GitLab",
"about": "Giới thiệu", "about": "Giới thiệu",
"requiresCredentialsInSettings": "{}: Điều này cần thông tin xác thực bổ sung (trong Thiết đặt)", "requiresCredentialsInSettings": "{}: Điều này cần thông tin xác thực bổ sung (trong Thiết đặt)",
"checkOnStart": "Kiểm tra các bản cập nhật khi khởi động", "checkOnStart": "Kiểm tra các bản cập nhật khi khởi động",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "Hỗ trợ URL APK cố định", "supportFixedAPKURL": "Hỗ trợ URL APK cố định",
"selectX": "Lựa chọn {}", "selectX": "Lựa chọn {}",
"parallelDownloads": "Cho phép tải đa luồng", "parallelDownloads": "Cho phép tải đa luồng",
"installMethod": "Phương thức cài đặt", "useShizuku": "Use Shizuku or Sui to install",
"normal": "Mặc định",
"root": "Root",
"shizukuBinderNotFound": "Shizuku chưa khởi động", "shizukuBinderNotFound": "Shizuku chưa khởi động",
"shizukuOld": "Old Shizuku version (<11) - update it",
"shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead",
"shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)",
"useSystemFont": "Sử dụng phông chữ hệ thống", "useSystemFont": "Sử dụng phông chữ hệ thống",
"systemFontError": "Lỗi tải phông chữ hệ thống: {}",
"useVersionCodeAsOSVersion": "Sử dụng Mã phiên bản ứng dụng làm phiên bản do hệ điều hành phát hiện", "useVersionCodeAsOSVersion": "Sử dụng Mã phiên bản ứng dụng làm phiên bản do hệ điều hành phát hiện",
"requestHeader": "Tiêu đề yêu cầu", "requestHeader": "Tiêu đề yêu cầu",
"useLatestAssetDateAsReleaseDate": "Sử dụng nội dung tải lên mới nhất làm ngày phát hành", "useLatestAssetDateAsReleaseDate": "Sử dụng nội dung tải lên mới nhất làm ngày phát hành",
@ -299,8 +308,10 @@
"note": "Ghi chú", "note": "Ghi chú",
"selfHostedNote": "Trình đơn thả xuống \"{}\" có thể được dùng để tiếp cận các phiên bản tự lưu trữ/tùy chỉnh của bất kỳ nguồn nào.", "selfHostedNote": "Trình đơn thả xuống \"{}\" có thể được dùng để tiếp cận các phiên bản tự lưu trữ/tùy chỉnh của bất kỳ nguồn nào.",
"badDownload": "Không thể phân tích cú pháp APK (tải xuống một phần hoặc không tương thích)", "badDownload": "Không thể phân tích cú pháp APK (tải xuống một phần hoặc không tương thích)",
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", "beforeNewInstallsShareToAppVerifier": "Chia sẻ ứng dụng mới với AppVerifier (nếu có)",
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", "appVerifierInstructionToast": "Chia sẻ lên AppVerifier, sau đó quay lại đây khi sẵn sàng.",
"wiki": "Help/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Gỡ ứng dụng?", "one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?" "other": "Gỡ ứng dụng?"
@ -349,6 +360,10 @@
"one": "{} và 1 ứng dụng khác đã được cập nhật.", "one": "{} và 1 ứng dụng khác đã được cập nhật.",
"other": "{} và {} ứng dụng khác đã được cập nhật." "other": "{} và {} ứng dụng khác đã được cập nhật."
}, },
"xAndNMoreUpdatesFailed": {
"one": "Failed to update {} and 1 more app.",
"other": "Failed to update {} and {} more apps."
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} và 1 ứng dụng khác có thể đã được cập nhật.", "one": "{} và 1 ứng dụng khác có thể đã được cập nhật.",
"other": "{} và {} ứng dụng khác có thể đã được cập nhật." "other": "{} và {} ứng dụng khác có thể đã được cập nhật."

View File

@ -13,8 +13,8 @@
"and": "和", "and": "和",
"githubPATLabel": "GitHub 个人访问令牌(提升 API 请求限额)", "githubPATLabel": "GitHub 个人访问令牌(提升 API 请求限额)",
"includePrereleases": "包含预发行版", "includePrereleases": "包含预发行版",
"fallbackToOlderReleases": "将发行版作为备选", "fallbackToOlderReleases": "将过往的发行版作为备选",
"filterReleaseTitlesByRegEx": "筛选发行标题正则表达式", "filterReleaseTitlesByRegEx": "筛选发行标题正则表达式",
"invalidRegEx": "无效的正则表达式", "invalidRegEx": "无效的正则表达式",
"noDescription": "无描述", "noDescription": "无描述",
"cancel": "取消", "cancel": "取消",
@ -22,6 +22,9 @@
"requiredInBrackets": "(必填)", "requiredInBrackets": "(必填)",
"dropdownNoOptsError": "错误:下拉菜单必须包含至少一个选项", "dropdownNoOptsError": "错误:下拉菜单必须包含至少一个选项",
"colour": "配色", "colour": "配色",
"standard": "标准",
"custom": "定制",
"useMaterialYou": "使用 Material You 配色",
"githubStarredRepos": "已星标的 GitHub 仓库", "githubStarredRepos": "已星标的 GitHub 仓库",
"uname": "用户名", "uname": "用户名",
"wrongArgNum": "参数数量错误", "wrongArgNum": "参数数量错误",
@ -72,8 +75,8 @@
"unpinFromTop": "取消置顶", "unpinFromTop": "取消置顶",
"resetInstallStatusForSelectedAppsQuestion": "是否重置选中应用的安装状态?", "resetInstallStatusForSelectedAppsQuestion": "是否重置选中应用的安装状态?",
"installStatusOfXWillBeResetExplanation": "选中应用的安装状态将会被重置。\n\n当更新安装失败或其他问题导致 Obtainium 中的应用版本显示错误时,可以尝试通过此方法解决。", "installStatusOfXWillBeResetExplanation": "选中应用的安装状态将会被重置。\n\n当更新安装失败或其他问题导致 Obtainium 中的应用版本显示错误时,可以尝试通过此方法解决。",
"customLinkMessage": "这些链接适用于安装了 Gettingium 的设备", "customLinkMessage": "分享链接适用于安装 Obtainium 的设备",
"shareAppConfigLinks": "将应用程序配置共享为 HTML 链接", "shareAppConfigLinks": "通过链接分享应用配置",
"shareSelectedAppURLs": "分享选中应用的 URL", "shareSelectedAppURLs": "分享选中应用的 URL",
"resetInstallStatus": "重置安装状态", "resetInstallStatus": "重置安装状态",
"more": "更多", "more": "更多",
@ -110,6 +113,7 @@
"dark": "深色", "dark": "深色",
"light": "浅色", "light": "浅色",
"followSystem": "跟随系统", "followSystem": "跟随系统",
"followSystemThemeExplanation": "跟随系统主题仅在使用第三方应用时有效",
"useBlackTheme": "使用纯黑深色主题", "useBlackTheme": "使用纯黑深色主题",
"appSortBy": "排序依据", "appSortBy": "排序依据",
"authorName": "作者 / 应用名称", "authorName": "作者 / 应用名称",
@ -131,7 +135,7 @@
"close": "关闭", "close": "关闭",
"share": "分享", "share": "分享",
"appNotFound": "未找到应用", "appNotFound": "未找到应用",
"obtainiumExportHyphenatedLowercase": "获取出口", "obtainiumExportHyphenatedLowercase": "obtainium-export",
"pickAnAPK": "选择一个 APK 文件", "pickAnAPK": "选择一个 APK 文件",
"appHasMoreThanOnePackage": "“{}”有多个架构可用:", "appHasMoreThanOnePackage": "“{}”有多个架构可用:",
"deviceSupportsXArch": "您的设备支持 {} 架构。", "deviceSupportsXArch": "您的设备支持 {} 架构。",
@ -143,8 +147,10 @@
"noNewUpdates": "全部应用已是最新。", "noNewUpdates": "全部应用已是最新。",
"xHasAnUpdate": "“{}”可以更新了。", "xHasAnUpdate": "“{}”可以更新了。",
"appsUpdated": "应用已更新", "appsUpdated": "应用已更新",
"appsNotUpdated": "更新应用程序失败",
"appsUpdatedNotifDescription": "当应用在后台安装更新时发送通知", "appsUpdatedNotifDescription": "当应用在后台安装更新时发送通知",
"xWasUpdatedToY": "“{}”已更新至 {}。", "xWasUpdatedToY": "“{}”已更新至 {}。",
"xWasNotUpdatedToY": "未能将 {} 更新为 {}。",
"errorCheckingUpdates": "检查更新出错", "errorCheckingUpdates": "检查更新出错",
"errorCheckingUpdatesNotifDescription": "当后台检查更新失败时显示的通知", "errorCheckingUpdatesNotifDescription": "当后台检查更新失败时显示的通知",
"appsRemoved": "应用已删除", "appsRemoved": "应用已删除",
@ -173,8 +179,8 @@
"appWithIdOrNameNotFound": "未找到符合此 ID 或名称的应用", "appWithIdOrNameNotFound": "未找到符合此 ID 或名称的应用",
"reposHaveMultipleApps": "存储库中可能包含多个应用", "reposHaveMultipleApps": "存储库中可能包含多个应用",
"fdroidThirdPartyRepo": "F-Droid 第三方存储库", "fdroidThirdPartyRepo": "F-Droid 第三方存储库",
"steamMobile": "蒸汽手机", "steamMobile": "Steam Mobile",
"steamChat": "蒸汽聊天", "steamChat": "Steam Chat",
"install": "安装", "install": "安装",
"markInstalled": "标记为已安装", "markInstalled": "标记为已安装",
"update": "更新", "update": "更新",
@ -183,6 +189,9 @@
"disableVersionDetection": "禁用版本检测", "disableVersionDetection": "禁用版本检测",
"noVersionDetectionExplanation": "此选项应该仅用于无法进行版本检测的应用。", "noVersionDetectionExplanation": "此选项应该仅用于无法进行版本检测的应用。",
"downloadingX": "正在下载“{}”", "downloadingX": "正在下载“{}”",
"downloadX": "下载 {}",
"downloadedX": "下载 {}",
"releaseAsset": "APK 文件",
"downloadNotifDescription": "提示应用的下载进度", "downloadNotifDescription": "提示应用的下载进度",
"noAPKFound": "未找到 APK 文件", "noAPKFound": "未找到 APK 文件",
"noVersionDetection": "禁用版本检测", "noVersionDetection": "禁用版本检测",
@ -199,7 +208,7 @@
"copiedToClipboard": "已复制至剪贴板", "copiedToClipboard": "已复制至剪贴板",
"storagePermissionDenied": "已拒绝授予存储权限", "storagePermissionDenied": "已拒绝授予存储权限",
"selectedCategorizeWarning": "这将覆盖选中应用当前的类别设置。", "selectedCategorizeWarning": "这将覆盖选中应用当前的类别设置。",
"filterAPKsByRegEx": "筛选 APK 文件正则表达式", "filterAPKsByRegEx": "筛选 APK 文件正则表达式",
"removeFromObtainium": "从 Obtainium 中删除", "removeFromObtainium": "从 Obtainium 中删除",
"uninstallFromDevice": "从设备中卸载", "uninstallFromDevice": "从设备中卸载",
"onlyWorksWithNonVersionDetectApps": "仅适用于禁用版本检测的应用。", "onlyWorksWithNonVersionDetectApps": "仅适用于禁用版本检测的应用。",
@ -233,7 +242,7 @@
"addInfoInSettings": "在“设置”中添加此凭据。", "addInfoInSettings": "在“设置”中添加此凭据。",
"githubSourceNote": "使用访问令牌可避免触发 GitHub 的 API 请求限制。", "githubSourceNote": "使用访问令牌可避免触发 GitHub 的 API 请求限制。",
"sortByLastLinkSegment": "仅根据链接的末尾部分进行筛选", "sortByLastLinkSegment": "仅根据链接的末尾部分进行筛选",
"filterReleaseNotesByRegEx": "筛选发行说明正则表达式", "filterReleaseNotesByRegEx": "筛选发行说明正则表达式",
"customLinkFilterRegex": "筛选自定义来源的 APK 文件链接\n正则表达式默认匹配模式为“.apk$”)", "customLinkFilterRegex": "筛选自定义来源的 APK 文件链接\n正则表达式默认匹配模式为“.apk$”)",
"appsPossiblyUpdated": "已尝试更新应用", "appsPossiblyUpdated": "已尝试更新应用",
"appsPossiblyUpdatedNotifDescription": "当应用已尝试在后台更新时发送通知", "appsPossiblyUpdatedNotifDescription": "当应用已尝试在后台更新时发送通知",
@ -242,20 +251,20 @@
"backgroundUpdateReqsExplanation": "后台更新未必适用于所有的应用。", "backgroundUpdateReqsExplanation": "后台更新未必适用于所有的应用。",
"backgroundUpdateLimitsExplanation": "只有在启动 Obtainium 时才能确认安装是否成功。", "backgroundUpdateLimitsExplanation": "只有在启动 Obtainium 时才能确认安装是否成功。",
"verifyLatestTag": "验证“Latest”标签", "verifyLatestTag": "验证“Latest”标签",
"intermediateLinkRegex": "筛选中转链接正则表达式", "intermediateLinkRegex": "筛选中转链接正则表达式",
"filterByLinkText": "根据链接文本进行筛选", "filterByLinkText": "根据链接文本进行筛选",
"intermediateLinkNotFound": "未找到中转链接", "intermediateLinkNotFound": "未找到中转链接",
"intermediateLink": "中转链接", "intermediateLink": "中转链接",
"exemptFromBackgroundUpdates": "禁用后台更新(如果已经全局启用)", "exemptFromBackgroundUpdates": "禁用后台更新(如果已经全局启用)",
"bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新", "bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新",
"autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件", "autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件",
"versionExtractionRegEx": "版本号提取规则(正则表达式", "versionExtractionRegEx": "提取版本号正则表达式",
"matchGroupToUse": "引用的捕获组", "matchGroupToUse": "从上述匹配结果中引用的捕获组",
"highlightTouchTargets": "突出展示不明显的触摸区域", "highlightTouchTargets": "突出展示不明显的触摸区域",
"pickExportDir": "选择导出文件夹", "pickExportDir": "选择导出文件夹",
"autoExportOnChanges": "数据变更时自动导出", "autoExportOnChanges": "数据变更时自动导出",
"includeSettings": "同时导出应用设置", "includeSettings": "同时导出应用设置",
"filterVersionsByRegEx": "筛选版本号正则表达式", "filterVersionsByRegEx": "筛选版本号正则表达式",
"trySelectingSuggestedVersionCode": "尝试选择推荐版本的 APK 文件", "trySelectingSuggestedVersionCode": "尝试选择推荐版本的 APK 文件",
"dontSortReleasesList": "保持来自 API 的发行顺序", "dontSortReleasesList": "保持来自 API 的发行顺序",
"reverseSort": "反转排序", "reverseSort": "反转排序",
@ -279,12 +288,12 @@
"supportFixedAPKURL": "支持固定的 APK 文件链接", "supportFixedAPKURL": "支持固定的 APK 文件链接",
"selectX": "选择{}", "selectX": "选择{}",
"parallelDownloads": "启用并行下载", "parallelDownloads": "启用并行下载",
"installMethod": "安装方式", "useShizuku": "使用 Shizuku 或 Sui 安装",
"normal": "常规",
"root": "root",
"shizukuBinderNotFound": "未发现兼容的 Shizuku 服务", "shizukuBinderNotFound": "未发现兼容的 Shizuku 服务",
"shizukuOld": "Shizuku 版本过低(<11- 请更新",
"shizukuOldAndroidWithADB": "正在低版本 Android<8.1)系统中以 ADB 模式运行 Shizuku - 请更新 Android 版本或使用 Sui 代替",
"shizukuPretendToBeGooglePlay": "使用 Shizuku 时将安装来源伪装为“Google Play”",
"useSystemFont": "使用系统字体", "useSystemFont": "使用系统字体",
"systemFontError": "加载系统字体出错:{}",
"useVersionCodeAsOSVersion": "使用内部版本号代替应用定义的版本号", "useVersionCodeAsOSVersion": "使用内部版本号代替应用定义的版本号",
"requestHeader": "请求标头", "requestHeader": "请求标头",
"useLatestAssetDateAsReleaseDate": "使用最近文件上传时间作为发行日期", "useLatestAssetDateAsReleaseDate": "使用最近文件上传时间作为发行日期",
@ -299,8 +308,10 @@
"note": "备注", "note": "备注",
"selfHostedNote": "可以通过“{}”下拉菜单来指向任意来源的自托管/自定义实例。", "selfHostedNote": "可以通过“{}”下拉菜单来指向任意来源的自托管/自定义实例。",
"badDownload": "无法解析 APK 文件(不兼容或文件不完整)", "badDownload": "无法解析 APK 文件(不兼容或文件不完整)",
"beforeNewInstallsShareToAppVerifier": " AppVerifier 共享新应用程序(如有", "beforeNewInstallsShareToAppVerifier": "通过 AppVerifier 校验新应用(如果可用",
"appVerifierInstructionToast": "分享 AppVerifier准备就绪后返回此处。", "appVerifierInstructionToast": "分享 AppVerifier完成后返回此处。",
"wiki": "帮助/维基",
"crowdsourcedConfigsLabel": "众包应用程序配置(使用风险自负)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "是否删除应用?", "one": "是否删除应用?",
"other": "是否删除应用?" "other": "是否删除应用?"
@ -349,6 +360,10 @@
"one": "{} 和另外 1 个应用已更新。", "one": "{} 和另外 1 个应用已更新。",
"other": "“{}”和另外 {} 个应用已更新。" "other": "“{}”和另外 {} 个应用已更新。"
}, },
"xAndNMoreUpdatesFailed": {
"one": "更新 {} 和另外 1 个应用程序失败。",
"other": "未能更新 {} 和 {} 更多应用程序。"
},
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} 和另外 1 个应用已尝试更新。", "one": "{} 和另外 1 个应用已尝试更新。",
"other": "“{}”和另外 {} 个应用已尝试更新。" "other": "“{}”和另外 {} 个应用已尝试更新。"
@ -357,4 +372,4 @@
"one": "{}APK", "one": "{}APK",
"other": "{}APK" "other": "{}APK"
} }
} }

View File

@ -0,0 +1,54 @@
<p>Obtainium позволяет вам устанавливать и обновлять приложения прямо с их объявлений о выпусках и получать уведомления о новых выпусках.</p>
<p>Для деталей читайте <a href="https://github.com/ImranR98/Obtainium/wiki">Вики</a></p>
<p>
<b>Поддерживаемые источники приложений:</b>
</p>
<ul>
<li>
<p>Свободное ПО - Общие:</p>
<ul>
<li>GitHub</li>
<li>GitLab</li>
<li>Codeberg</li>
<li>F-Droid</li>
<li>Third Party F-Droid Repos</li>
<li>IzzyOnDroid</li>
<li>SourceForge</li>
<li>SourceHut</li>
</ul>
</li>
<li>
<p>Другие - Общие:</p>
<ul>
<li>APKPure</li>
<li>Aptoide</li>
<li>Uptodowng</li>
<li>APKMirror (Track-Only)</li>
<li>Huawei AppGallery</li>
<li>Jenkins Jobs</li>
</ul>
</li>
<li>
<p>Свободное ПО - Для отдельных приложений:</p>
<ul>
<li>Mullvad</li>
<li>Signal</li>
<li>VLC</li>
</ul>
</li>
<li>
<p>Другие - Для отдельных приложений:</p>
<ul>
<li>WhatsApp</li>
<li>Telegram App</li>
<li>Neutron Code</li>
</ul>
</li>
<li><p>"HTML" (Подстраховка): Любой другой URL-адрес, который возвращает HTML-страницу со ссылками на APK-файлы.</p></li>
</ul>
<p>
<b>Ограничения:</b>
</p>
<p>
Для некоторых источников данные собираются с помощью веб-скрапинга и могут легко сломаться из-за изменений в дизайне веб-сайта. В таких случаях более надежные методы могут быть недоступны.
</p>

View File

@ -0,0 +1 @@
Получайте обновления приложений прямо из источника

View File

@ -271,17 +271,15 @@ class GitHub extends AppSource {
} }
} }
List<MapEntry<String, String>> getReleaseAPKUrls(dynamic release) => List<MapEntry<String, String>> getReleaseAssetUrls(dynamic release) =>
(release['assets'] as List<dynamic>?) (release['assets'] as List<dynamic>?)?.map((e) {
?.map((e) { var url = !e['name'].toString().toLowerCase().endsWith('.apk')
return (e['name'] != null) && ? (e['browser_download_url'] ?? e['url'])
((e['url'] ?? e['browser_download_url']) != null) : (e['url'] ?? e['browser_download_url']);
? MapEntry(e['name'] as String, return (e['name'] != null) && (url != null)
(e['url'] ?? e['browser_download_url']) as String) ? MapEntry(e['name'] as String, url as String)
: const MapEntry('', ''); : const MapEntry('', '');
}) }).toList() ??
.where((element) => element.key.toLowerCase().endsWith('.apk'))
.toList() ??
[]; [];
DateTime? getPublishDateFromRelease(dynamic rel) => DateTime? getPublishDateFromRelease(dynamic rel) =>
@ -383,7 +381,11 @@ class GitHub extends AppSource {
.hasMatch(((releases[i]['body'] as String?) ?? '').trim())) { .hasMatch(((releases[i]['body'] as String?) ?? '').trim())) {
continue; continue;
} }
var apkUrls = getReleaseAPKUrls(releases[i]); var allAssetUrls = getReleaseAssetUrls(releases[i]);
List<MapEntry<String, String>> apkUrls = allAssetUrls
.where((element) => element.key.toLowerCase().endsWith('.apk'))
.toList();
apkUrls = filterApks(apkUrls, additionalSettings['apkFilterRegEx'], apkUrls = filterApks(apkUrls, additionalSettings['apkFilterRegEx'],
additionalSettings['invertAPKFilter']); additionalSettings['invertAPKFilter']);
if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) { if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) {
@ -391,12 +393,25 @@ class GitHub extends AppSource {
} }
targetRelease = releases[i]; targetRelease = releases[i];
targetRelease['apkUrls'] = apkUrls; targetRelease['apkUrls'] = apkUrls;
targetRelease['version'] =
targetRelease['tag_name'] ?? targetRelease['name'];
if (targetRelease['tarball_url'] != null) {
allAssetUrls.add(MapEntry(
(targetRelease['version'] ?? 'source') + '.tar.gz',
targetRelease['tarball_url']));
}
if (targetRelease['zipball_url'] != null) {
allAssetUrls.add(MapEntry(
(targetRelease['version'] ?? 'source') + '.zip',
targetRelease['zipball_url']));
}
targetRelease['allAssetUrls'] = allAssetUrls;
break; break;
} }
if (targetRelease == null) { if (targetRelease == null) {
throw NoReleasesError(); throw NoReleasesError();
} }
String? version = targetRelease['tag_name'] ?? targetRelease['name']; String? version = targetRelease['version'];
DateTime? releaseDate = getReleaseDateFromRelease( DateTime? releaseDate = getReleaseDateFromRelease(
targetRelease, useLatestAssetDateAsReleaseDate); targetRelease, useLatestAssetDateAsReleaseDate);
if (version == null) { if (version == null) {
@ -408,7 +423,9 @@ class GitHub extends AppSource {
targetRelease['apkUrls'] as List<MapEntry<String, String>>, targetRelease['apkUrls'] as List<MapEntry<String, String>>,
getAppNames(standardUrl), getAppNames(standardUrl),
releaseDate: releaseDate, releaseDate: releaseDate,
changeLog: changeLog.isEmpty ? null : changeLog); changeLog: changeLog.isEmpty ? null : changeLog,
allAssetUrls:
targetRelease['allAssetUrls'] as List<MapEntry<String, String>>);
} else { } else {
if (onHttpErrorCode != null) { if (onHttpErrorCode != null) {
onHttpErrorCode(res); onHttpErrorCode(res);

View File

@ -180,6 +180,16 @@ class GitLab extends AppSource {
throw NoAPKError(); throw NoAPKError();
} }
return apkDetailsList.first; finalResult.apkUrls = finalResult.apkUrls.map((apkUrl) {
if (RegExp('^$standardUrl/-/jobs/[0-9]+/artifacts/file/[^/]+\$')
.hasMatch(apkUrl.value)) {
return MapEntry(
apkUrl.key, apkUrl.value.replaceFirst('/file/', '/raw/'));
} else {
return apkUrl;
}
}).toList();
return finalResult;
} }
} }

View File

@ -243,18 +243,28 @@ class HTML extends AppSource {
if ((additionalSettings['customLinkFilterRegex'] as String?)?.isNotEmpty == if ((additionalSettings['customLinkFilterRegex'] as String?)?.isNotEmpty ==
true) { true) {
var reg = RegExp(additionalSettings['customLinkFilterRegex']); var reg = RegExp(additionalSettings['customLinkFilterRegex']);
links = allLinks links = allLinks.where((element) {
.where((element) => var link = element.key;
reg.hasMatch(filterLinkByText ? element.value : element.key)) try {
.toList(); link = Uri.decodeFull(element.key);
} catch (e) {
// Some links may not have valid encoding
}
return reg.hasMatch(filterLinkByText ? element.value : link);
}).toList();
} else { } else {
links = allLinks links = allLinks.where((element) {
.where((element) => var link = element.key;
Uri.parse(filterLinkByText ? element.value : element.key) try {
.path link = Uri.decodeFull(element.key);
.toLowerCase() } catch (e) {
.endsWith('.apk')) // Some links may not have valid encoding
.toList(); }
return Uri.parse(filterLinkByText ? element.value : link)
.path
.toLowerCase()
.endsWith('.apk');
}).toList();
} }
if (!skipSort) { if (!skipSort) {
links.sort((a, b) => additionalSettings['sortByLastLinkSegment'] == true links.sort((a, b) => additionalSettings['sortByLastLinkSegment'] == true
@ -309,13 +319,19 @@ class HTML extends AppSource {
links = [MapEntry(currentUrl, currentUrl)]; links = [MapEntry(currentUrl, currentUrl)];
} }
var rel = links.last.key; var rel = links.last.key;
var relDecoded = rel;
try {
relDecoded = Uri.decodeFull(rel);
} catch (e) {
// Some links may not have valid encoding
}
String? version; String? version;
version = extractVersion( version = extractVersion(
additionalSettings['versionExtractionRegEx'] as String?, additionalSettings['versionExtractionRegEx'] as String?,
additionalSettings['matchGroupToUse'] as String?, additionalSettings['matchGroupToUse'] as String?,
additionalSettings['versionExtractWholePage'] == true additionalSettings['versionExtractWholePage'] == true
? versionExtractionWholePageString ? versionExtractionWholePageString
: rel); : relDecoded);
version ??= version ??=
additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash' additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash'
? rel.hashCode.toString() ? rel.hashCode.toString()

View File

@ -6,7 +6,7 @@ import 'package:obtainium/providers/source_provider.dart';
class HuaweiAppGallery extends AppSource { class HuaweiAppGallery extends AppSource {
HuaweiAppGallery() { HuaweiAppGallery() {
name = 'Huawei AppGallery'; name = 'Huawei AppGallery';
hosts = ['appgallery.huawei.com']; hosts = ['appgallery.huawei.com', 'appgallery.cloud.huawei.com'];
versionDetectionDisallowed = true; versionDetectionDisallowed = true;
showReleaseDateAsVersionToggle = true; showReleaseDateAsVersionToggle = true;
} }
@ -14,7 +14,7 @@ class HuaweiAppGallery extends AppSource {
@override @override
String sourceSpecificStandardizeURL(String url) { String sourceSpecificStandardizeURL(String url) {
RegExp standardUrlRegEx = RegExp( RegExp standardUrlRegEx = RegExp(
'^https?://(www\\.)?${getSourceRegex(hosts)}/app/[^/]+', '^https?://(www\\.)?${getSourceRegex(hosts)}(/#)?/(app|appdl)/[^/]+',
caseSensitive: false); caseSensitive: false);
RegExpMatch? match = standardUrlRegEx.firstMatch(url); RegExpMatch? match = standardUrlRegEx.firstMatch(url);
if (match == null) { if (match == null) {
@ -24,7 +24,7 @@ class HuaweiAppGallery extends AppSource {
} }
getDlUrl(String standardUrl) => getDlUrl(String standardUrl) =>
'https://${hosts[0].replaceAll('appgallery.', 'appgallery.cloud.')}/appdl/${standardUrl.split('/').last}'; 'https://${hosts[0].replaceAll('appgallery.huawei', 'appgallery.cloud.huawei')}/appdl/${standardUrl.split('/').last}';
requestAppdlRedirect( requestAppdlRedirect(
String dlUrl, Map<String, dynamic> additionalSettings) async { String dlUrl, Map<String, dynamic> additionalSettings) async {
@ -84,7 +84,7 @@ class HuaweiAppGallery extends AppSource {
} }
var relDate = relDateStrAdj == null var relDate = relDateStrAdj == null
? null ? null
: DateFormat('yy-MM-dd-HH-mm').parse(relDateStrAdj.join('')); : DateFormat('yy-MM-dd-HH-mm', 'en_US').parse(relDateStrAdj.join(''));
if (relDateStr == null) { if (relDateStr == null) {
throw NoVersionError(); throw NoVersionError();
} }

View File

@ -245,8 +245,8 @@ class _GeneratedFormState extends State<GeneratedForm> {
void someValueChanged({bool isBuilding = false, bool forceInvalid = false}) { void someValueChanged({bool isBuilding = false, bool forceInvalid = false}) {
Map<String, dynamic> returnValues = values; Map<String, dynamic> returnValues = values;
var valid = true; var valid = true;
for (int r = 0; r < widget.items.length; r++) { for (int r = 0; r < formInputs.length; r++) {
for (int i = 0; i < widget.items[r].length; i++) { for (int i = 0; i < formInputs[r].length; i++) {
if (formInputs[r][i] is TextFormField) { if (formInputs[r][i] is TextFormField) {
valid = valid && validateTextField(formInputs[r][i] as TextFormField); valid = valid && validateTextField(formInputs[r][i] as TextFormField);
} }

View File

@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:obtainium/pages/home.dart'; import 'package:obtainium/pages/home.dart';
import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/logs_provider.dart'; import 'package:obtainium/providers/logs_provider.dart';
import 'package:obtainium/providers/native_provider.dart';
import 'package:obtainium/providers/notifications_provider.dart'; import 'package:obtainium/providers/notifications_provider.dart';
import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
@ -118,8 +119,6 @@ void main() async {
BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask); BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
} }
var defaultThemeColour = Colors.deepPurple;
class Obtainium extends StatefulWidget { class Obtainium extends StatefulWidget {
const Obtainium({super.key}); const Obtainium({super.key});
@ -213,15 +212,13 @@ class _ObtainiumState extends State<Obtainium> {
// Decide on a colour/brightness scheme based on OS and user settings // Decide on a colour/brightness scheme based on OS and user settings
ColorScheme lightColorScheme; ColorScheme lightColorScheme;
ColorScheme darkColorScheme; ColorScheme darkColorScheme;
if (lightDynamic != null && if (lightDynamic != null && darkDynamic != null && settingsProvider.useMaterialYou) {
darkDynamic != null &&
settingsProvider.colour == ColourSettings.materialYou) {
lightColorScheme = lightDynamic.harmonized(); lightColorScheme = lightDynamic.harmonized();
darkColorScheme = darkDynamic.harmonized(); darkColorScheme = darkDynamic.harmonized();
} else { } else {
lightColorScheme = ColorScheme.fromSeed(seedColor: defaultThemeColour); lightColorScheme = ColorScheme.fromSeed(seedColor: settingsProvider.themeColor);
darkColorScheme = ColorScheme.fromSeed( darkColorScheme = ColorScheme.fromSeed(
seedColor: defaultThemeColour, brightness: Brightness.dark); seedColor: settingsProvider.themeColor, brightness: Brightness.dark);
} }
// set the background and surface colors to pure black in the amoled theme // set the background and surface colors to pure black in the amoled theme
@ -231,6 +228,8 @@ class _ObtainiumState extends State<Obtainium> {
.harmonized(); .harmonized();
} }
if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont();
return MaterialApp( return MaterialApp(
title: 'Obtainium', title: 'Obtainium',
localizationsDelegates: context.localizationDelegates, localizationsDelegates: context.localizationDelegates,

View File

@ -155,7 +155,8 @@ class AddAppPageState extends State<AddAppPage> {
// Only download the APK here if you need to for the package ID // Only download the APK here if you need to for the package ID
if (isTempId(app) && app.additionalSettings['trackOnly'] != true) { if (isTempId(app) && app.additionalSettings['trackOnly'] != true) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
var apkUrl = await appsProvider.confirmApkUrl(app, context); var apkUrl =
await appsProvider.confirmAppFileUrl(app, context, false);
if (apkUrl == null) { if (apkUrl == null) {
throw ObtainiumError(tr('cancelled')); throw ObtainiumError(tr('cancelled'));
} }

View File

@ -133,7 +133,7 @@ class _AppPageState extends State<AppPage> {
child: Text( child: Text(
app?.app.releaseDate == null app?.app.releaseDate == null
? tr('changes') ? tr('changes')
: app!.app.releaseDate.toString(), : app!.app.releaseDate!.toLocal().toString(),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: style:
Theme.of(context).textTheme.labelSmall!.copyWith( Theme.of(context).textTheme.labelSmall!.copyWith(
@ -158,6 +158,28 @@ class _AppPageState extends State<AppPage> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12), style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12),
), ),
if (app?.app.apkUrls.isNotEmpty == true ||
app?.app.otherAssetUrls.isNotEmpty == true)
GestureDetector(
onTap: app?.app == null || updating
? null
: () async {
try {
await appsProvider
.downloadAppAssets([app!.app.id], context);
} catch (e) {
showError(e, context);
}
},
child: Text(
tr('downloadX', args: [tr('releaseAsset').toLowerCase()]),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.labelSmall!.copyWith(
decoration: TextDecoration.underline,
fontStyle: FontStyle.italic,
),
),
),
const SizedBox( const SizedBox(
height: 48, height: 48,
), ),

View File

@ -437,7 +437,7 @@ class AppsPageState extends State<AppsPage> {
? tr('changes') ? tr('changes')
: '' : ''
: DateFormat('yyyy-MM-dd') : DateFormat('yyyy-MM-dd')
.format(listedApps[appIndex].app.releaseDate!); .format(listedApps[appIndex].app.releaseDate!.toLocal());
} }
getSingleAppHorizTile(int index) { getSingleAppHorizTile(int index) {
@ -854,69 +854,75 @@ class AppsPageState extends State<AppsPage> {
scrollable: true, scrollable: true,
content: Padding( content: Padding(
padding: const EdgeInsets.only(top: 6), padding: const EdgeInsets.only(top: 6),
child: Row( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
IconButton( TextButton(
onPressed: pinSelectedApps,
child: Text(selectedApps
.where((element) => element.pinned)
.isEmpty
? tr('pinToTop')
: tr('unpinFromTop'))),
const Divider(),
TextButton(
onPressed: () {
String urls = '';
for (var a in selectedApps) {
urls += '${a.url}\n';
}
urls = urls.substring(0, urls.length - 1);
Share.share(urls,
subject: 'Obtainium - ${tr('appsString')}');
Navigator.of(context).pop();
},
child: Text(tr('shareSelectedAppURLs'))),
const Divider(),
TextButton(
onPressed: selectedAppIds.isEmpty
? null
: () {
String urls = '';
for (var a in selectedApps) {
urls +=
'https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/${Uri.encodeComponent(jsonEncode({
'id': a.id,
'url': a.url,
'author': a.author,
'name': a.name,
'preferredApkIndex':
a.preferredApkIndex,
'additionalSettings':
jsonEncode(a.additionalSettings)
}))}\n\n';
}
Share.share(urls,
subject:
'Obtainium - ${tr('appsString')}');
},
child: Text(tr('shareAppConfigLinks'))),
const Divider(),
TextButton(
onPressed: () {
appsProvider
.downloadAppAssets(
selectedApps.map((e) => e.id).toList(),
globalNavigatorKey.currentContext ??
context)
.catchError((e) => showError(
e,
globalNavigatorKey.currentContext ??
context));
Navigator.of(context).pop();
},
child: Text(tr('downloadX',
args: [tr('releaseAsset').toLowerCase()]))),
const Divider(),
TextButton(
onPressed: appsProvider.areDownloadsRunning() onPressed: appsProvider.areDownloadsRunning()
? null ? null
: showMassMarkDialog, : showMassMarkDialog,
tooltip: tr('markSelectedAppsUpdated'), child: Text(tr('markSelectedAppsUpdated'))),
icon: const Icon(Icons.done)),
IconButton(
onPressed: pinSelectedApps,
tooltip: selectedApps
.where((element) => element.pinned)
.isEmpty
? tr('pinToTop')
: tr('unpinFromTop'),
icon: Icon(selectedApps
.where((element) => element.pinned)
.isEmpty
? Icons.bookmark_outline_rounded
: Icons.bookmark_remove_outlined),
),
IconButton(
onPressed: () {
String urls = '';
for (var a in selectedApps) {
urls += '${a.url}\n';
}
urls = urls.substring(0, urls.length - 1);
Share.share(urls,
subject: 'Obtainium - ${tr('appsString')}');
Navigator.of(context).pop();
},
tooltip: tr('shareSelectedAppURLs'),
icon: const Icon(Icons.share_rounded),
),
IconButton(
onPressed: selectedAppIds.isEmpty
? null
: () {
String urls =
'<p>${tr('customLinkMessage')}:</p>\n\n<ul>\n';
for (var a in selectedApps) {
urls +=
' <li><a href="obtainium://app/${Uri.encodeComponent(jsonEncode({
'id': a.id,
'url': a.url,
'author': a.author,
'name': a.name,
'preferredApkIndex':
a.preferredApkIndex,
'additionalSettings':
jsonEncode(a.additionalSettings)
}))}">${a.name}</a></li>\n';
}
urls +=
'</ul>\n\n<p><a href="$obtainiumUrl">${tr('about')}</a></p>';
Share.share(urls,
subject: 'Obtainium - ${tr('appsString')}');
},
tooltip: tr('shareAppConfigLinks'),
icon: const Icon(Icons.ios_share),
),
]), ]),
), ),
); );

View File

@ -119,7 +119,7 @@ class _HomePageState extends State<HomePage> {
} }
// Check initial link if app was in cold state (terminated) // Check initial link if app was in cold state (terminated)
final appLink = await _appLinks.getInitialAppLink(); final appLink = await _appLinks.getInitialLink();
if (appLink != null) { if (appLink != null) {
await interpretLink(appLink); await interpretLink(appLink);
} }

View File

@ -1,5 +1,7 @@
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:equations/equations.dart';
import 'package:flex_color_picker/flex_color_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:obtainium/components/custom_app_bar.dart'; import 'package:obtainium/components/custom_app_bar.dart';
import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/components/generated_form.dart';
@ -12,6 +14,7 @@ import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:shizuku_apk_installer/shizuku_apk_installer.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
class SettingsPage extends StatefulWidget { class SettingsPage extends StatefulWidget {
@ -22,78 +25,184 @@ class SettingsPage extends StatefulWidget {
} }
class _SettingsPageState extends State<SettingsPage> { class _SettingsPageState extends State<SettingsPage> {
List<int> updateIntervalNodes = [
15,
30,
60,
120,
180,
360,
720,
1440,
4320,
10080,
20160,
43200
];
int updateInterval = 0;
late SplineInterpolation updateIntervalInterpolator; // 🤓
String updateIntervalLabel = tr('neverManualOnly');
bool showIntervalLabel = true;
final Map<ColorSwatch<Object>, String> colorsNameMap =
<ColorSwatch<Object>, String>{
ColorTools.createPrimarySwatch(obtainiumThemeColor): 'Obtainium'
};
void initUpdateIntervalInterpolator() {
List<InterpolationNode> nodes = [];
for (final (index, element) in updateIntervalNodes.indexed) {
nodes.add(
InterpolationNode(x: index.toDouble() + 1, y: element.toDouble()));
}
updateIntervalInterpolator = SplineInterpolation(nodes: nodes);
}
void processIntervalSliderValue(double val) {
if (val < 0.5) {
updateInterval = 0;
updateIntervalLabel = tr('neverManualOnly');
return;
}
int valInterpolated = 0;
if (val < 1) {
valInterpolated = 15;
} else {
valInterpolated = updateIntervalInterpolator.compute(val).round();
}
if (valInterpolated < 60) {
updateInterval = valInterpolated;
updateIntervalLabel = plural('minute', valInterpolated);
} else if (valInterpolated < 8 * 60) {
int valRounded = (valInterpolated / 15).floor() * 15;
updateInterval = valRounded;
updateIntervalLabel = plural('hour', valRounded ~/ 60);
int mins = valRounded % 60;
if (mins != 0) updateIntervalLabel += " ${plural('minute', mins)}";
} else if (valInterpolated < 24 * 60) {
int valRounded = (valInterpolated / 30).floor() * 30;
updateInterval = valRounded;
updateIntervalLabel = plural('hour', valRounded / 60);
} else if (valInterpolated < 7 * 24 * 60) {
int valRounded = (valInterpolated / (12 * 60)).floor() * 12 * 60;
updateInterval = valRounded;
updateIntervalLabel = plural('day', valRounded / (24 * 60));
} else {
int valRounded = (valInterpolated / (24 * 60)).floor() * 24 * 60;
updateInterval = valRounded;
updateIntervalLabel = plural('day', valRounded ~/ (24 * 60));
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SettingsProvider settingsProvider = context.watch<SettingsProvider>(); SettingsProvider settingsProvider = context.watch<SettingsProvider>();
SourceProvider sourceProvider = SourceProvider(); SourceProvider sourceProvider = SourceProvider();
if (settingsProvider.prefs == null) { if (settingsProvider.prefs == null) settingsProvider.initializeSettings();
settingsProvider.initializeSettings(); initUpdateIntervalInterpolator();
processIntervalSliderValue(settingsProvider.updateIntervalSliderVal);
var followSystemThemeExplanation = FutureBuilder(
builder: (ctx, val) {
return ((val.data?.version.sdkInt ?? 30) < 29)
? Text(tr('followSystemThemeExplanation'),
style: Theme.of(context).textTheme.labelSmall)
: const SizedBox.shrink();
},
future: DeviceInfoPlugin().androidInfo);
Future<bool> colorPickerDialog() async {
return ColorPicker(
color: settingsProvider.themeColor,
onColorChanged: (Color color) =>
setState(() => settingsProvider.themeColor = color),
actionButtons: const ColorPickerActionButtons(
okButton: true,
closeButton: true,
dialogActionButtons: false,
),
pickersEnabled: const <ColorPickerType, bool>{
ColorPickerType.both: false,
ColorPickerType.primary: false,
ColorPickerType.accent: false,
ColorPickerType.bw: false,
ColorPickerType.custom: true,
ColorPickerType.wheel: true,
},
pickerTypeLabels: <ColorPickerType, String>{
ColorPickerType.custom: tr('standard'),
ColorPickerType.wheel: tr('custom')
},
title: Text(tr('selectX', args: [tr('colour')]),
style: Theme.of(context).textTheme.titleLarge),
wheelDiameter: 192,
wheelSquareBorderRadius: 32,
width: 48,
height: 48,
borderRadius: 24,
spacing: 8,
runSpacing: 8,
enableShadesSelection: false,
customColorSwatchesAndNames: colorsNameMap,
showMaterialName: true,
showColorName: true,
materialNameTextStyle: Theme.of(context).textTheme.bodySmall,
colorNameTextStyle: Theme.of(context).textTheme.bodySmall,
copyPasteBehavior:
const ColorPickerCopyPasteBehavior(longPressMenu: true),
).showPickerDialog(
context,
transitionBuilder: (BuildContext context, Animation<double> a1,
Animation<double> a2, Widget widget) {
final double curvedValue = Curves.easeInCubic.transform(a1.value);
return Transform(
alignment: Alignment.center,
transform: Matrix4.diagonal3Values(curvedValue, curvedValue, 1),
child: Opacity(opacity: curvedValue, child: widget),
);
},
transitionDuration: const Duration(milliseconds: 250),
);
} }
var installMethodDropdown = DropdownButtonFormField( var colorPicker = ListTile(
decoration: InputDecoration(labelText: tr('installMethod')), dense: true,
value: settingsProvider.installMethod, contentPadding: EdgeInsets.zero,
items: [ title: Text(tr('selectX', args: [tr('colour')])),
DropdownMenuItem( subtitle: Text(
value: InstallMethodSettings.normal, "${ColorTools.nameThatColor(settingsProvider.themeColor)} "
child: Text(tr('normal')), "(${ColorTools.materialNameAndCode(settingsProvider.themeColor, colorSwatchNameMap: colorsNameMap)})"),
), trailing: ColorIndicator(
const DropdownMenuItem( width: 40,
value: InstallMethodSettings.shizuku, height: 40,
child: Text('Shizuku'), borderRadius: 20,
), color: settingsProvider.themeColor,
DropdownMenuItem( onSelectFocus: false,
value: InstallMethodSettings.root, onSelect: () async {
child: Text(tr('root')), final Color colorBeforeDialog = settingsProvider.themeColor;
) if (!(await colorPickerDialog())) {
], setState(() {
onChanged: (value) { settingsProvider.themeColor = colorBeforeDialog;
if (value != null) { });
settingsProvider.installMethod = value; }
} }));
});
var themeDropdown = DropdownButtonFormField( var useMaterialThemeSwitch = FutureBuilder(
decoration: InputDecoration(labelText: tr('theme')), builder: (ctx, val) {
value: settingsProvider.theme, return ((val.data?.version.sdkInt ?? 0) >= 31)
items: [ ? Row(
DropdownMenuItem( mainAxisAlignment: MainAxisAlignment.spaceBetween,
value: ThemeSettings.dark, children: [
child: Text(tr('dark')), Flexible(child: Text(tr('useMaterialYou'))),
), Switch(
DropdownMenuItem( value: settingsProvider.useMaterialYou,
value: ThemeSettings.light, onChanged: (value) {
child: Text(tr('light')), settingsProvider.useMaterialYou = value;
), })
DropdownMenuItem( ],
value: ThemeSettings.system, )
child: Text(tr('followSystem')), : const SizedBox.shrink();
) },
], future: DeviceInfoPlugin().androidInfo);
onChanged: (value) {
if (value != null) {
settingsProvider.theme = value;
}
});
var colourDropdown = DropdownButtonFormField(
decoration: InputDecoration(labelText: tr('colour')),
value: settingsProvider.colour,
items: const [
DropdownMenuItem(
value: ColourSettings.basic,
child: Text('Obtainium'),
),
DropdownMenuItem(
value: ColourSettings.materialYou,
child: Text('Material You'),
)
],
onChanged: (value) {
if (value != null) {
settingsProvider.colour = value;
}
});
var sortDropdown = DropdownButtonFormField( var sortDropdown = DropdownButtonFormField(
isExpanded: true, isExpanded: true,
@ -165,30 +274,29 @@ class _SettingsPageState extends State<SettingsPage> {
} }
}); });
var intervalDropdown = DropdownButtonFormField( var intervalSlider = Slider(
decoration: InputDecoration(labelText: tr('bgUpdateCheckInterval')), value: settingsProvider.updateIntervalSliderVal,
value: settingsProvider.updateInterval, max: updateIntervalNodes.length.toDouble(),
items: updateIntervals.map((e) { divisions: updateIntervalNodes.length * 20,
int displayNum = (e < 60 label: updateIntervalLabel,
? e onChanged: (double value) {
: e < 1440 setState(() {
? e / 60 settingsProvider.updateIntervalSliderVal = value;
: e / 1440) processIntervalSliderValue(value);
.round();
String display = e == 0
? tr('neverManualOnly')
: (e < 60
? plural('minute', displayNum)
: e < 1440
? plural('hour', displayNum)
: plural('day', displayNum));
return DropdownMenuItem(value: e, child: Text(display));
}).toList(),
onChanged: (value) {
if (value != null) {
settingsProvider.updateInterval = value;
}
}); });
},
onChangeStart: (double value) {
setState(() {
showIntervalLabel = false;
});
},
onChangeEnd: (double value) {
setState(() {
showIntervalLabel = true;
settingsProvider.updateInterval = updateInterval;
});
},
);
var sourceSpecificFields = sourceProvider.sources.map((e) { var sourceSpecificFields = sourceProvider.sources.map((e) {
if (e.sourceConfigSettingFormItems.isNotEmpty) { if (e.sourceConfigSettingFormItems.isNotEmpty) {
@ -239,15 +347,26 @@ class _SettingsPageState extends State<SettingsPage> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary), color: Theme.of(context).colorScheme.primary),
), ),
intervalDropdown, //intervalDropdown,
height16,
if (showIntervalLabel)
SizedBox(
child: Text(
"${tr('bgUpdateCheckInterval')}: $updateIntervalLabel"))
else
const SizedBox(height: 16),
intervalSlider,
FutureBuilder( FutureBuilder(
builder: (ctx, val) { builder: (ctx, val) {
return (val.data?.version.sdkInt ?? 0) >= 30 return (settingsProvider.updateInterval >
0) &&
(((val.data?.version.sdkInt ?? 0) >=
30) ||
settingsProvider.useShizuku)
? Column( ? Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
height16,
Row( Row(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment MainAxisAlignment
@ -416,7 +535,48 @@ class _SettingsPageState extends State<SettingsPage> {
}) })
], ],
), ),
installMethodDropdown, height16,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: Text(tr('useShizuku'))),
Switch(
value: settingsProvider.useShizuku,
onChanged: (useShizuku) {
if (useShizuku) {
ShizukuApkInstaller.checkPermission()
.then((resCode) {
settingsProvider.useShizuku =
resCode!.startsWith('granted');
switch (resCode) {
case 'binder_not_found':
showError(
ObtainiumError(tr(
'shizukuBinderNotFound')),
context);
case 'old_shizuku':
showError(
ObtainiumError(
tr('shizukuOld')),
context);
case 'old_android_with_adb':
showError(
ObtainiumError(tr(
'shizukuOldAndroidWithADB')),
context);
case 'denied':
showError(
ObtainiumError(
tr('cancelled')),
context);
}
});
} else {
settingsProvider.useShizuku = false;
}
})
],
),
height32, height32,
Text( Text(
tr('sourceSpecific'), tr('sourceSpecific'),
@ -432,21 +592,49 @@ class _SettingsPageState extends State<SettingsPage> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary), color: Theme.of(context).colorScheme.primary),
), ),
themeDropdown, DropdownButtonFormField(
height16, decoration:
Row( InputDecoration(labelText: tr('theme')),
mainAxisAlignment: MainAxisAlignment.spaceBetween, value: settingsProvider.theme,
children: [ items: [
Flexible(child: Text(tr('useBlackTheme'))), DropdownMenuItem(
Switch( value: ThemeSettings.system,
value: settingsProvider.useBlackTheme, child: Text(tr('followSystem')),
onChanged: (value) { ),
settingsProvider.useBlackTheme = value; DropdownMenuItem(
}) value: ThemeSettings.light,
], child: Text(tr('light')),
), ),
colourDropdown, DropdownMenuItem(
value: ThemeSettings.dark,
child: Text(tr('dark')),
)
],
onChanged: (value) {
if (value != null) {
settingsProvider.theme = value;
}
}),
height8,
if (settingsProvider.theme == ThemeSettings.system)
followSystemThemeExplanation,
height16, height16,
if (settingsProvider.theme != ThemeSettings.light)
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Flexible(child: Text(tr('useBlackTheme'))),
Switch(
value: settingsProvider.useBlackTheme,
onChanged: (value) {
settingsProvider.useBlackTheme =
value;
})
]),
height8,
useMaterialThemeSwitch,
if (!settingsProvider.useMaterialYou) colorPicker,
Row( Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -460,34 +648,46 @@ class _SettingsPageState extends State<SettingsPage> {
), ),
height16, height16,
localeDropdown, localeDropdown,
height16, FutureBuilder(
Row( builder: (ctx, val) {
mainAxisAlignment: MainAxisAlignment.spaceBetween, return (val.data?.version.sdkInt ?? 0) >= 34
children: [ ? Column(
Flexible(child: Text(tr('useSystemFont'))), crossAxisAlignment:
Switch( CrossAxisAlignment.start,
value: settingsProvider.useSystemFont, children: [
onChanged: (useSystemFont) { height16,
if (useSystemFont) { Row(
NativeFeatures.loadSystemFont() mainAxisAlignment:
.then((fontLoadRes) { MainAxisAlignment
if (fontLoadRes == 'ok') { .spaceBetween,
settingsProvider.useSystemFont = children: [
true; Flexible(
} else { child: Text(tr(
showError( 'useSystemFont'))),
ObtainiumError(tr( Switch(
'systemFontError', value: settingsProvider
args: [fontLoadRes])), .useSystemFont,
context); onChanged:
} (useSystemFont) {
}); if (useSystemFont) {
} else { NativeFeatures
settingsProvider.useSystemFont = false; .loadSystemFont()
} .then((val) {
}) settingsProvider
], .useSystemFont =
), true;
});
} else {
settingsProvider
.useSystemFont =
false;
}
})
])
])
: const SizedBox.shrink();
},
future: DeviceInfoPlugin().androidInfo),
height16, height16,
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -640,17 +840,31 @@ class _SettingsPageState extends State<SettingsPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
TextButton.icon( IconButton(
onPressed: () { onPressed: () {
launchUrlString(settingsProvider.sourceUrl, launchUrlString(settingsProvider.sourceUrl,
mode: LaunchMode.externalApplication); mode: LaunchMode.externalApplication);
}, },
icon: const Icon(Icons.code), icon: const Icon(Icons.code),
label: Text( tooltip: tr('appSource'),
tr('appSource'),
),
), ),
TextButton.icon( IconButton(
onPressed: () {
launchUrlString('${settingsProvider.sourceUrl}/wiki',
mode: LaunchMode.externalApplication);
},
icon: const Icon(Icons.help_outline_rounded),
tooltip: tr('wiki'),
),
IconButton(
onPressed: () {
launchUrlString('https://apps.obtainium.imranr.dev/',
mode: LaunchMode.externalApplication);
},
icon: const Icon(Icons.apps_rounded),
tooltip: tr('crowdsourcedConfigsLabel'),
),
IconButton(
onPressed: () { onPressed: () {
context.read<LogsProvider>().get().then((logs) { context.read<LogsProvider>().get().then((logs) {
if (logs.isEmpty) { if (logs.isEmpty) {
@ -666,7 +880,7 @@ class _SettingsPageState extends State<SettingsPage> {
}); });
}, },
icon: const Icon(Icons.bug_report_outlined), icon: const Icon(Icons.bug_report_outlined),
label: Text(tr('appLogs'))), tooltip: tr('appLogs'))
], ],
), ),
const SizedBox( const SizedBox(

View File

@ -34,7 +34,7 @@ import 'package:android_intent_plus/android_intent.dart';
import 'package:flutter_archive/flutter_archive.dart'; import 'package:flutter_archive/flutter_archive.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:shared_storage/shared_storage.dart' as saf; import 'package:shared_storage/shared_storage.dart' as saf;
import 'native_provider.dart'; import 'package:shizuku_apk_installer/shizuku_apk_installer.dart';
final pm = AndroidPackageManager(); final pm = AndroidPackageManager();
@ -142,19 +142,20 @@ List<MapEntry<String, int>> moveStrToEndMapEntryWithCount(
return arr; return arr;
} }
Future<File> downloadFileWithRetry( Future<File> downloadFileWithRetry(String url, String fileName,
String url, String fileNameNoExt, Function? onProgress, String destDir, bool fileNameHasExt, Function? onProgress, String destDir,
{bool useExisting = true, {bool useExisting = true,
Map<String, String>? headers, Map<String, String>? headers,
int retries = 3}) async { int retries = 3}) async {
try { try {
return await downloadFile(url, fileNameNoExt, onProgress, destDir, return await downloadFile(
url, fileName, fileNameHasExt, onProgress, destDir,
useExisting: useExisting, headers: headers); useExisting: useExisting, headers: headers);
} catch (e) { } catch (e) {
if (retries > 0 && e is ClientException) { if (retries > 0 && e is ClientException) {
await Future.delayed(const Duration(seconds: 5)); await Future.delayed(const Duration(seconds: 5));
return await downloadFileWithRetry( return await downloadFileWithRetry(
url, fileNameNoExt, onProgress, destDir, url, fileName, fileNameHasExt, onProgress, destDir,
useExisting: useExisting, headers: headers, retries: (retries - 1)); useExisting: useExisting, headers: headers, retries: (retries - 1));
} else { } else {
rethrow; rethrow;
@ -201,8 +202,8 @@ Future<String> checkPartialDownloadHash(String url, int bytesToGrab,
return hashListOfLists(bytes); return hashListOfLists(bytes);
} }
Future<File> downloadFile( Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
String url, String fileNameNoExt, Function? onProgress, String destDir, Function? onProgress, String destDir,
{bool useExisting = true, Map<String, String>? headers}) async { {bool useExisting = true, Map<String, String>? headers}) async {
// Send the initial request but cancel it as soon as you have the headers // Send the initial request but cancel it as soon as you have the headers
var reqHeaders = headers ?? {}; var reqHeaders = headers ?? {};
@ -222,7 +223,12 @@ Future<File> downloadFile(
if (url.toLowerCase().endsWith('.apk') && ext != 'apk') { if (url.toLowerCase().endsWith('.apk') && ext != 'apk') {
ext = 'apk'; ext = 'apk';
} }
File downloadedFile = File('$destDir/$fileNameNoExt.$ext'); fileName = fileName.split('/').last; // Ensure the fileName is a file name
File downloadedFile = File('$destDir/$fileName.$ext');
if (fileNameHasExt) {
// If the user says the filename already has an ext, ignore whatever you inferred from above
downloadedFile = File('$destDir/$fileName');
}
bool rangeFeatureEnabled = false; bool rangeFeatureEnabled = false;
if (resHeaders['accept-ranges']?.isNotEmpty == true) { if (resHeaders['accept-ranges']?.isNotEmpty == true) {
@ -235,8 +241,9 @@ Future<File> downloadFile(
var fullContentLength = response.contentLength; var fullContentLength = response.contentLength;
if (useExisting && downloadedFile.existsSync()) { if (useExisting && downloadedFile.existsSync()) {
var length = downloadedFile.lengthSync(); var length = downloadedFile.lengthSync();
if (fullContentLength == null) { if (fullContentLength == null || !rangeFeatureEnabled) {
// Assume full // If there is no content length reported, assume it the existing file is fully downloaded
// Also if the range feature is not supported, don't trust the content length if any (#1542)
client.close(); client.close();
return downloadedFile; return downloadedFile;
} else { } else {
@ -291,14 +298,11 @@ Future<File> downloadFile(
return s; return s;
}).pipe(sink); }).pipe(sink);
await sink.close(); await sink.close();
bool likelyCorruptFile = (progress ?? 0) > 101;
progress = null; progress = null;
if (onProgress != null) { if (onProgress != null) {
onProgress(progress); onProgress(progress);
} }
if (response.statusCode < 200 || if (response.statusCode < 200 || response.statusCode > 299) {
response.statusCode > 299 ||
likelyCorruptFile) {
tempDownloadedFile.deleteSync(recursive: true); tempDownloadedFile.deleteSync(recursive: true);
throw response.reasonPhrase ?? tr('unexpectedError'); throw response.reasonPhrase ?? tr('unexpectedError');
} }
@ -360,7 +364,7 @@ class AppsProvider with ChangeNotifier {
foregroundStream = FGBGEvents.stream.asBroadcastStream(); foregroundStream = FGBGEvents.stream.asBroadcastStream();
foregroundSubscription = foregroundStream?.listen((event) async { foregroundSubscription = foregroundStream?.listen((event) async {
isForeground = event == FGBGType.foreground; isForeground = event == FGBGType.foreground;
if (isForeground) await loadApps(); if (isForeground) loadApps();
}); });
() async { () async {
await settingsProvider.initializeSettings(); await settingsProvider.initializeSettings();
@ -392,30 +396,26 @@ class AppsProvider with ChangeNotifier {
}(); }();
} }
Future<File> handleAPKIDChange(App app, PackageInfo? newInfo, Future<File> handleAPKIDChange(App app, PackageInfo newInfo,
File downloadedFile, String downloadUrl) async { File downloadedFile, String downloadUrl) async {
// If the APK package ID is different from the App ID, it is either new (using a placeholder ID) or the ID has changed // If the APK package ID is different from the App ID, it is either new (using a placeholder ID) or the ID has changed
// The former case should be handled (give the App its real ID), the latter is a security issue // The former case should be handled (give the App its real ID), the latter is a security issue
var isTempIdBool = isTempId(app); var isTempIdBool = isTempId(app);
if (newInfo != null) { if (app.id != newInfo.packageName) {
if (app.id != newInfo.packageName) { if (apps[app.id] != null && !isTempIdBool && !app.allowIdChange) {
if (apps[app.id] != null && !isTempIdBool && !app.allowIdChange) { throw IDChangedError(newInfo.packageName!);
throw IDChangedError(newInfo.packageName!); }
} var idChangeWasAllowed = app.allowIdChange;
var idChangeWasAllowed = app.allowIdChange; app.allowIdChange = false;
app.allowIdChange = false; var originalAppId = app.id;
var originalAppId = app.id; app.id = newInfo.packageName!;
app.id = newInfo.packageName!; downloadedFile = downloadedFile.renameSync(
downloadedFile = downloadedFile.renameSync( '${downloadedFile.parent.path}/${app.id}-${downloadUrl.hashCode}.${downloadedFile.path.split('.').last}');
'${downloadedFile.parent.path}/${app.id}-${downloadUrl.hashCode}.${downloadedFile.path.split('.').last}'); if (apps[originalAppId] != null) {
if (apps[originalAppId] != null) { await removeApps([originalAppId]);
await removeApps([originalAppId]); await saveApps([app],
await saveApps([app], onlyIfExists: !isTempIdBool && !idChangeWasAllowed);
onlyIfExists: !isTempIdBool && !idChangeWasAllowed);
}
} }
} else if (isTempIdBool) {
throw ObtainiumError('Could not get ID from APK');
} }
return downloadedFile; return downloadedFile;
} }
@ -441,8 +441,8 @@ class AppsProvider with ChangeNotifier {
var headers = await source.getRequestHeaders(app.additionalSettings, var headers = await source.getRequestHeaders(app.additionalSettings,
forAPKDownload: true); forAPKDownload: true);
var downloadedFile = await downloadFileWithRetry( var downloadedFile = await downloadFileWithRetry(
downloadUrl, fileNameNoExt, downloadUrl, fileNameNoExt, false, headers: headers,
headers: headers, (double? progress) { (double? progress) {
int? prog = progress?.ceil(); int? prog = progress?.ceil();
if (apps[app.id] != null) { if (apps[app.id] != null) {
apps[app.id]!.downloadProgress = progress; apps[app.id]!.downloadProgress = progress;
@ -479,6 +479,10 @@ class AppsProvider with ChangeNotifier {
newInfo = newInfo =
await pm.getPackageArchiveInfo(archiveFilePath: apks.first.path); await pm.getPackageArchiveInfo(archiveFilePath: apks.first.path);
} }
if (newInfo == null) {
downloadedFile.delete();
throw ObtainiumError('Could not get ID from APK');
}
downloadedFile = downloadedFile =
await handleAPKIDChange(app, newInfo, downloadedFile, downloadUrl); await handleAPKIDChange(app, newInfo, downloadedFile, downloadUrl);
// Delete older versions of the file if any // Delete older versions of the file if any
@ -509,9 +513,6 @@ class AppsProvider with ChangeNotifier {
.isNotEmpty; .isNotEmpty;
Future<bool> canInstallSilently(App app) async { Future<bool> canInstallSilently(App app) async {
if (app.id == obtainiumId) {
return false;
}
if (!settingsProvider.enableBackgroundUpdates) { if (!settingsProvider.enableBackgroundUpdates) {
return false; return false;
} }
@ -519,8 +520,7 @@ class AppsProvider with ChangeNotifier {
return false; return false;
} }
if (app.apkUrls.length > 1) { if (app.apkUrls.length > 1) {
// Manual API selection means silent install is not possible return false; // Manual API selection means silent install is not possible
return false;
} }
var osInfo = await DeviceInfoPlugin().androidInfo; var osInfo = await DeviceInfoPlugin().androidInfo;
@ -531,20 +531,30 @@ class AppsProvider with ChangeNotifier {
?.installingPackageName ?.installingPackageName
: (await pm.getInstallerPackageName(packageName: app.id)); : (await pm.getInstallerPackageName(packageName: app.id));
} catch (e) { } catch (e) {
// Probably not installed - ignore return false; // App probably not installed
}
if (installerPackageName != obtainiumId) {
// If we did not install the app (or it isn't installed), silent install is not possible
return false;
} }
int? targetSDK = int? targetSDK =
(await getInstalledInfo(app.id))?.applicationInfo?.targetSdkVersion; (await getInstalledInfo(app.id))?.applicationInfo?.targetSdkVersion;
// The APK should target a new enough API
// https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int)
if (!(targetSDK != null && targetSDK >= (osInfo.version.sdkInt - 3))) {
return false;
}
// The OS must also be new enough and the APK should target a new enough API if (settingsProvider.useShizuku) {
return osInfo.version.sdkInt >= 31 && return true;
targetSDK != null && }
targetSDK >= // https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int)
(osInfo.version.sdkInt - 3); if (app.id == obtainiumId) {
return false;
}
if (installerPackageName != obtainiumId) {
// If we did not install the app, silent install is not possible
return false;
}
// The OS must also be new enough
return osInfo.version.sdkInt >= 31;
} }
Future<void> waitForUserToReturnToForeground(BuildContext context) async { Future<void> waitForUserToReturnToForeground(BuildContext context) async {
@ -568,7 +578,8 @@ class AppsProvider with ChangeNotifier {
Future<bool> installXApkDir( Future<bool> installXApkDir(
DownloadedXApkDir dir, BuildContext? firstTimeWithContext, DownloadedXApkDir dir, BuildContext? firstTimeWithContext,
{bool needsBGWorkaround = false}) async { {bool needsBGWorkaround = false,
bool shizukuPretendToBeGooglePlay = false}) async {
// We don't know which APKs in an XAPK are supported by the user's device // We don't know which APKs in an XAPK are supported by the user's device
// So we try installing all of them and assume success if at least one installed // So we try installing all of them and assume success if at least one installed
// If 0 APKs installed, throw the first install error encountered // If 0 APKs installed, throw the first install error encountered
@ -583,7 +594,8 @@ class AppsProvider with ChangeNotifier {
somethingInstalled = somethingInstalled || somethingInstalled = somethingInstalled ||
await installApk( await installApk(
DownloadedApk(dir.appId, file), firstTimeWithContext, DownloadedApk(dir.appId, file), firstTimeWithContext,
needsBGWorkaround: needsBGWorkaround); needsBGWorkaround: needsBGWorkaround,
shizukuPretendToBeGooglePlay: shizukuPretendToBeGooglePlay);
} catch (e) { } catch (e) {
logs.add( logs.add(
'Could not install APK from XAPK \'${file.path}\': ${e.toString()}'); 'Could not install APK from XAPK \'${file.path}\': ${e.toString()}');
@ -606,7 +618,8 @@ class AppsProvider with ChangeNotifier {
Future<bool> installApk( Future<bool> installApk(
DownloadedApk file, BuildContext? firstTimeWithContext, DownloadedApk file, BuildContext? firstTimeWithContext,
{bool needsBGWorkaround = false}) async { {bool needsBGWorkaround = false,
bool shizukuPretendToBeGooglePlay = false}) async {
if (firstTimeWithContext != null && if (firstTimeWithContext != null &&
settingsProvider.beforeNewInstallsShareToAppVerifier && settingsProvider.beforeNewInstallsShareToAppVerifier &&
(await getInstalledInfo('dev.soupslurpr.appverifier')) != null) { (await getInstalledInfo('dev.soupslurpr.appverifier')) != null) {
@ -634,8 +647,7 @@ class AppsProvider with ChangeNotifier {
!(await canDowngradeApps())) { !(await canDowngradeApps())) {
throw DowngradeError(); throw DowngradeError();
} }
if (needsBGWorkaround && if (needsBGWorkaround) {
settingsProvider.installMethod == InstallMethodSettings.normal) {
// The below 'await' will never return if we are in a background process // The below 'await' will never return if we are in a background process
// To work around this, we should assume the install will be successful // To work around this, we should assume the install will be successful
// So we update the app's installed version first as we will never get to the later code // So we update the app's installed version first as we will never get to the later code
@ -647,20 +659,12 @@ class AppsProvider with ChangeNotifier {
attemptToCorrectInstallStatus: false); attemptToCorrectInstallStatus: false);
} }
int? code; int? code;
switch (settingsProvider.installMethod) { if (!settingsProvider.useShizuku) {
case InstallMethodSettings.normal: code =
code = await AndroidPackageInstaller.installApk( await AndroidPackageInstaller.installApk(apkFilePath: file.file.path);
apkFilePath: file.file.path); } else {
case InstallMethodSettings.shizuku: code = await ShizukuApkInstaller.installAPK(file.file.uri.toString(),
code = (await NativeFeatures.installWithShizuku( shizukuPretendToBeGooglePlay ? "com.android.vending" : "");
apkFileUri: file.file.uri.toString()))
? 0
: 1;
case InstallMethodSettings.root:
code =
(await NativeFeatures.installWithRoot(apkFilePath: file.file.path))
? 0
: 1;
} }
bool installed = false; bool installed = false;
if (code != null && code != 0 && code != 3) { if (code != null && code != 0 && code != 3) {
@ -705,23 +709,28 @@ class AppsProvider with ChangeNotifier {
await intent.launch(); await intent.launch();
} }
Future<MapEntry<String, String>?> confirmApkUrl( Future<MapEntry<String, String>?> confirmAppFileUrl(
App app, BuildContext? context) async { App app, BuildContext? context, bool pickAnyAsset) async {
var urlsToSelectFrom = app.apkUrls;
if (pickAnyAsset) {
urlsToSelectFrom = [...urlsToSelectFrom, ...app.otherAssetUrls];
}
// If the App has more than one APK, the user should pick one (if context provided) // If the App has more than one APK, the user should pick one (if context provided)
MapEntry<String, String>? apkUrl = MapEntry<String, String>? appFileUrl = urlsToSelectFrom[
app.apkUrls[app.preferredApkIndex >= 0 ? app.preferredApkIndex : 0]; app.preferredApkIndex >= 0 ? app.preferredApkIndex : 0];
// get device supported architecture // get device supported architecture
List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis; List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
if (app.apkUrls.length > 1 && context != null) { if (urlsToSelectFrom.length > 1 && context != null) {
// ignore: use_build_context_synchronously appFileUrl = await showDialog(
apkUrl = await showDialog( // ignore: use_build_context_synchronously
context: context, context: context,
builder: (BuildContext ctx) { builder: (BuildContext ctx) {
return APKPicker( return AppFilePicker(
app: app, app: app,
initVal: apkUrl, initVal: appFileUrl,
archs: archs, archs: archs,
pickAnyAsset: pickAnyAsset,
); );
}); });
} }
@ -731,23 +740,22 @@ class AppsProvider with ChangeNotifier {
} }
// If the picked APK comes from an origin different from the source, get user confirmation (if context provided) // If the picked APK comes from an origin different from the source, get user confirmation (if context provided)
if (apkUrl != null && if (appFileUrl != null &&
getHost(apkUrl.value) != getHost(app.url) && getHost(appFileUrl.value) != getHost(app.url) &&
context != null) { context != null) {
// ignore: use_build_context_synchronously
if (!(settingsProvider.hideAPKOriginWarning) && if (!(settingsProvider.hideAPKOriginWarning) &&
// ignore: use_build_context_synchronously
await showDialog( await showDialog(
// ignore: use_build_context_synchronously
context: context, context: context,
builder: (BuildContext ctx) { builder: (BuildContext ctx) {
return APKOriginWarningDialog( return APKOriginWarningDialog(
sourceUrl: app.url, apkUrl: apkUrl!.value); sourceUrl: app.url, apkUrl: appFileUrl!.value);
}) != }) !=
true) { true) {
apkUrl = null; appFileUrl = null;
} }
} }
return apkUrl; return appFileUrl;
} }
// Given a list of AppIds, uses stored info about the apps to download APKs and install them // Given a list of AppIds, uses stored info about the apps to download APKs and install them
@ -774,7 +782,7 @@ class AppsProvider with ChangeNotifier {
var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true; var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true;
if (!trackOnly) { if (!trackOnly) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
apkUrl = await confirmApkUrl(apps[id]!.app, context); apkUrl = await confirmAppFileUrl(apps[id]!.app, context, false);
} }
if (apkUrl != null) { if (apkUrl != null) {
int urlInd = apps[id]! int urlInd = apps[id]!
@ -825,25 +833,23 @@ class AppsProvider with ChangeNotifier {
} }
id = downloadedFile?.appId ?? downloadedDir!.appId; id = downloadedFile?.appId ?? downloadedDir!.appId;
bool willBeSilent = await canInstallSilently(apps[id]!.app); bool willBeSilent = await canInstallSilently(apps[id]!.app);
switch (settingsProvider.installMethod) { if (!settingsProvider.useShizuku) {
case InstallMethodSettings.normal: if (!(await settingsProvider.getInstallPermission(enforce: false))) {
if (!(await settingsProvider.getInstallPermission( throw ObtainiumError(tr('cancelled'));
enforce: false))) { }
throw ObtainiumError(tr('cancelled')); } else {
} switch ((await ShizukuApkInstaller.checkPermission())!) {
case InstallMethodSettings.shizuku: case 'binder_not_found':
int code = await NativeFeatures.checkPermissionShizuku();
if (code == -1) {
throw ObtainiumError(tr('shizukuBinderNotFound')); throw ObtainiumError(tr('shizukuBinderNotFound'));
} else if (code == 0) { case 'old_shizuku':
throw ObtainiumError(tr('shizukuOld'));
case 'old_android_with_adb':
throw ObtainiumError(tr('shizukuOldAndroidWithADB'));
case 'denied':
throw ObtainiumError(tr('cancelled')); throw ObtainiumError(tr('cancelled'));
} }
case InstallMethodSettings.root:
if (!(await NativeFeatures.checkPermissionRoot())) {
throw ObtainiumError(tr('cancelled'));
}
} }
if (!willBeSilent && context != null) { if (!willBeSilent && context != null && !settingsProvider.useShizuku) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
await waitForUserToReturnToForeground(context); await waitForUserToReturnToForeground(context);
} }
@ -854,27 +860,47 @@ class AppsProvider with ChangeNotifier {
bool sayInstalled = true; bool sayInstalled = true;
var contextIfNewInstall = var contextIfNewInstall =
apps[id]?.installedInfo == null ? context : null; apps[id]?.installedInfo == null ? context : null;
bool needBGWorkaround =
willBeSilent && context == null && !settingsProvider.useShizuku;
if (downloadedFile != null) { if (downloadedFile != null) {
if (willBeSilent && context == null) { if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installApk(downloadedFile, contextIfNewInstall, installApk(downloadedFile, contextIfNewInstall,
needsBGWorkaround: true); needsBGWorkaround: true);
} else { } else {
sayInstalled = // ignore: use_build_context_synchronously
await installApk(downloadedFile, contextIfNewInstall); sayInstalled = await installApk(
downloadedFile, contextIfNewInstall,
shizukuPretendToBeGooglePlay:
apps[id]!.app.additionalSettings[
'shizukuPretendToBeGooglePlay'] ==
true);
} }
} else { } else {
if (willBeSilent && context == null) { if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installXApkDir(downloadedDir!, contextIfNewInstall, installXApkDir(downloadedDir!, contextIfNewInstall,
needsBGWorkaround: true); needsBGWorkaround: true);
} else { } else {
sayInstalled = // ignore: use_build_context_synchronously
await installXApkDir(downloadedDir!, contextIfNewInstall); sayInstalled = await installXApkDir(
downloadedDir!, contextIfNewInstall,
shizukuPretendToBeGooglePlay:
apps[id]!.app.additionalSettings[
'shizukuPretendToBeGooglePlay'] ==
true);
} }
} }
if (willBeSilent && context == null) { if (willBeSilent && context == null) {
notificationsProvider?.notify(SilentUpdateAttemptNotification( if (!settingsProvider.useShizuku) {
[apps[id]!.app], notificationsProvider?.notify(SilentUpdateAttemptNotification(
id: id.hashCode)); [apps[id]!.app],
id: id.hashCode));
} else {
notificationsProvider?.notify(SilentUpdateNotification(
[apps[id]!.app], sayInstalled,
id: id.hashCode));
}
} }
if (sayInstalled) { if (sayInstalled) {
installedIds.add(id); installedIds.add(id);
@ -911,6 +937,78 @@ class AppsProvider with ChangeNotifier {
return installedIds; return installedIds;
} }
Future<List<String>> downloadAppAssets(
List<String> appIds, BuildContext context,
{bool forceParallelDownloads = false}) async {
NotificationsProvider notificationsProvider =
context.read<NotificationsProvider>();
List<MapEntry<MapEntry<String, String>, App>> filesToDownload = [];
for (var id in appIds) {
if (apps[id] == null) {
throw ObtainiumError(tr('appNotFound'));
}
MapEntry<String, String>? fileUrl;
if (apps[id]!.app.apkUrls.isNotEmpty ||
apps[id]!.app.otherAssetUrls.isNotEmpty) {
// ignore: use_build_context_synchronously
fileUrl = await confirmAppFileUrl(apps[id]!.app, context, true);
}
if (fileUrl != null) {
filesToDownload.add(MapEntry(fileUrl, apps[id]!.app));
}
}
// Prepare to download+install Apps
MultiAppMultiError errors = MultiAppMultiError();
List<String> downloadedIds = [];
Future<void> downloadFn(MapEntry<String, String> fileUrl, App app) async {
try {
var exportDir = await settingsProvider.getExportDir();
String downloadPath = '/storage/emulated/0/Download';
bool downloadsAccessible = false;
try {
downloadsAccessible = Directory(downloadPath).existsSync();
} catch (e) {
//
}
if (!downloadsAccessible && exportDir != null) {
downloadPath = exportDir.path;
}
await downloadFile(fileUrl.value, fileUrl.key, true,
(double? progress) {
notificationsProvider
.notify(DownloadNotification(fileUrl.key, progress?.ceil() ?? 0));
}, downloadPath,
headers: await SourceProvider()
.getSource(app.url, overrideSource: app.overrideSource)
.getRequestHeaders(app.additionalSettings,
forAPKDownload:
fileUrl.key.endsWith('.apk') ? true : false),
useExisting: false);
notificationsProvider
.notify(DownloadedNotification(fileUrl.key, fileUrl.value));
} catch (e) {
errors.add(fileUrl.key, e);
} finally {
notificationsProvider.cancel(DownloadNotification(fileUrl.key, 0).id);
}
}
if (forceParallelDownloads || !settingsProvider.parallelDownloads) {
for (var urlWithApp in filesToDownload) {
await downloadFn(urlWithApp.key, urlWithApp.value);
}
} else {
await Future.wait(filesToDownload
.map((urlWithApp) => downloadFn(urlWithApp.key, urlWithApp.value)));
}
if (errors.idsByErrorString.isNotEmpty) {
throw errors;
}
return downloadedIds;
}
Future<Directory> getAppsDir() async { Future<Directory> getAppsDir() async {
Directory appsDir = Directory appsDir =
Directory('${(await getExternalStorageDirectory())!.path}/app_data'); Directory('${(await getExternalStorageDirectory())!.path}/app_data');
@ -1482,38 +1580,49 @@ class AppsProvider with ChangeNotifier {
} }
} }
class APKPicker extends StatefulWidget { class AppFilePicker extends StatefulWidget {
const APKPicker({super.key, required this.app, this.initVal, this.archs}); const AppFilePicker(
{super.key,
required this.app,
this.initVal,
this.archs,
this.pickAnyAsset = false});
final App app; final App app;
final MapEntry<String, String>? initVal; final MapEntry<String, String>? initVal;
final List<String>? archs; final List<String>? archs;
final bool pickAnyAsset;
@override @override
State<APKPicker> createState() => _APKPickerState(); State<AppFilePicker> createState() => _AppFilePickerState();
} }
class _APKPickerState extends State<APKPicker> { class _AppFilePickerState extends State<AppFilePicker> {
MapEntry<String, String>? apkUrl; MapEntry<String, String>? fileUrl;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
apkUrl ??= widget.initVal; fileUrl ??= widget.initVal;
var urlsToSelectFrom = widget.app.apkUrls;
if (widget.pickAnyAsset) {
urlsToSelectFrom = [...urlsToSelectFrom, ...widget.app.otherAssetUrls];
}
return AlertDialog( return AlertDialog(
scrollable: true, scrollable: true,
title: Text(tr('pickAnAPK')), title: Text(widget.pickAnyAsset
? tr('selectX', args: [tr('releaseAsset').toLowerCase()])
: tr('pickAnAPK')),
content: Column(children: [ content: Column(children: [
Text(tr('appHasMoreThanOnePackage', args: [widget.app.finalName])), Text(tr('appHasMoreThanOnePackage', args: [widget.app.finalName])),
const SizedBox(height: 16), const SizedBox(height: 16),
...widget.app.apkUrls.map( ...urlsToSelectFrom.map(
(u) => RadioListTile<String>( (u) => RadioListTile<String>(
title: Text(u.key), title: Text(u.key),
value: u.value, value: u.value,
groupValue: apkUrl!.value, groupValue: fileUrl!.value,
onChanged: (String? val) { onChanged: (String? val) {
setState(() { setState(() {
apkUrl = fileUrl = urlsToSelectFrom.where((e) => e.value == val).first;
widget.app.apkUrls.where((e) => e.value == val).first;
}); });
}), }),
), ),
@ -1540,7 +1649,7 @@ class _APKPickerState extends State<APKPicker> {
TextButton( TextButton(
onPressed: () { onPressed: () {
HapticFeedback.selectionClick(); HapticFeedback.selectionClick();
Navigator.of(context).pop(apkUrl); Navigator.of(context).pop(fileUrl);
}, },
child: Text(tr('continue'))) child: Text(tr('continue')))
], ],
@ -1617,7 +1726,7 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async {
int maxRetryWaitSeconds = 5; int maxRetryWaitSeconds = 5;
var netResult = await (Connectivity().checkConnectivity()); var netResult = await (Connectivity().checkConnectivity());
if (netResult == ConnectivityResult.none) { if (netResult.contains(ConnectivityResult.none)) {
logs.add('BG update task: No network.'); logs.add('BG update task: No network.');
return; return;
} }
@ -1654,8 +1763,8 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async {
var networkRestricted = false; var networkRestricted = false;
if (appsProvider.settingsProvider.bgUpdatesOnWiFiOnly) { if (appsProvider.settingsProvider.bgUpdatesOnWiFiOnly) {
networkRestricted = (netResult != ConnectivityResult.wifi) && networkRestricted = !netResult.contains(ConnectivityResult.wifi) &&
(netResult != ConnectivityResult.ethernet); !netResult.contains(ConnectivityResult.ethernet);
} }
if (toCheck.isNotEmpty) { if (toCheck.isNotEmpty) {
@ -1699,8 +1808,8 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async {
var networkRestricted = false; var networkRestricted = false;
if (appsProvider.settingsProvider.bgUpdatesOnWiFiOnly) { if (appsProvider.settingsProvider.bgUpdatesOnWiFiOnly) {
var netResult = await (Connectivity().checkConnectivity()); var netResult = await (Connectivity().checkConnectivity());
networkRestricted = (netResult != ConnectivityResult.wifi) && networkRestricted = !netResult.contains(ConnectivityResult.wifi) &&
(netResult != ConnectivityResult.ethernet); !netResult.contains(ConnectivityResult.ethernet);
} }
try { try {

View File

@ -1,75 +1,22 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:android_system_font/android_system_font.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
class NativeFeatures { class NativeFeatures {
static const MethodChannel _channel = MethodChannel('native');
static bool _systemFontLoaded = false; static bool _systemFontLoaded = false;
static bool _callbacksApplied = false;
static int _resPermShizuku = -2; // not set
static Future<ByteData> _readFileBytes(String path) async { static Future<ByteData> _readFileBytes(String path) async {
var file = File(path); var bytes = await File(path).readAsBytes();
var bytes = await file.readAsBytes();
return ByteData.view(bytes.buffer); return ByteData.view(bytes.buffer);
} }
static Future _handleCalls(MethodCall call) async { static Future loadSystemFont() async {
if (call.method == 'resPermShizuku') { if (_systemFontLoaded) return;
_resPermShizuku = call.arguments['res'];
}
}
static Future _waitWhile(bool Function() test,
[Duration pollInterval = const Duration(milliseconds: 250)]) {
var completer = Completer();
check() {
if (test()) {
Timer(pollInterval, check);
} else {
completer.complete();
}
}
check();
return completer.future;
}
static Future<String> loadSystemFont() async {
if (_systemFontLoaded) { return "ok"; }
var getFontRes = await _channel.invokeMethod('getSystemFont');
if (getFontRes[0] != '/') { return getFontRes; } // Error
var fontLoader = FontLoader('SystemFont'); var fontLoader = FontLoader('SystemFont');
fontLoader.addFont(_readFileBytes(getFontRes)); var fontFilePath = await AndroidSystemFont().getFilePath();
await fontLoader.load(); fontLoader.addFont(_readFileBytes(fontFilePath!));
fontLoader.load();
_systemFontLoaded = true; _systemFontLoaded = true;
return "ok";
}
static Future<int> checkPermissionShizuku() async {
if (!_callbacksApplied) {
_channel.setMethodCallHandler(_handleCalls);
_callbacksApplied = true;
}
int res = await _channel.invokeMethod('checkPermissionShizuku');
if (res == -2) {
await _waitWhile(() => _resPermShizuku == -2);
res = _resPermShizuku;
_resPermShizuku = -2;
}
return res;
}
static Future<bool> checkPermissionRoot() async {
return await _channel.invokeMethod('checkPermissionRoot');
}
static Future<bool> installWithShizuku({required String apkFileUri}) async {
return await _channel.invokeMethod(
'installWithShizuku', {'apkFileUri': apkFileUri});
}
static Future<bool> installWithRoot({required String apkFilePath}) async {
return await _channel.invokeMethod(
'installWithRoot', {'apkFilePath': apkFilePath});
} }
} }

View File

@ -41,20 +41,26 @@ class UpdateNotification extends ObtainiumNotification {
} }
class SilentUpdateNotification extends ObtainiumNotification { class SilentUpdateNotification extends ObtainiumNotification {
SilentUpdateNotification(List<App> updates, {int? id}) SilentUpdateNotification(List<App> updates, bool succeeded, {int? id})
: super( : super(
id ?? 3, id ?? 3,
tr('appsUpdated'), succeeded
? tr('appsUpdated')
: tr('appsNotUpdated'),
'', '',
'APPS_UPDATED', 'APPS_UPDATED',
tr('appsUpdatedNotifChannel'), tr('appsUpdatedNotifChannel'),
tr('appsUpdatedNotifDescription'), tr('appsUpdatedNotifDescription'),
Importance.defaultImportance) { Importance.defaultImportance) {
message = updates.length == 1 message = updates.length == 1
? tr('xWasUpdatedToY', ? tr(succeeded
args: [updates[0].finalName, updates[0].latestVersion]) ? 'xWasUpdatedToY'
: plural('xAndNMoreUpdatesInstalled', updates.length - 1, : 'xWasNotUpdatedToY',
args: [updates[0].finalName, (updates.length - 1).toString()]); args: [updates[0].finalName, updates[0].latestVersion])
: plural(succeeded
? 'xAndNMoreUpdatesInstalled'
: "xAndNMoreUpdatesFailed",
updates.length - 1, args: [updates[0].finalName, (updates.length - 1).toString()]);
} }
} }
@ -120,6 +126,18 @@ class DownloadNotification extends ObtainiumNotification {
progPercent: progPercent); progPercent: progPercent);
} }
class DownloadedNotification extends ObtainiumNotification {
DownloadedNotification(String fileName, String downloadUrl)
: super(
downloadUrl.hashCode,
tr('downloadedX', args: [fileName]),
'',
'FILE_DOWNLOADED',
tr('downloadedXNotifChannel', args: [tr('app')]),
tr('downloadedX', args: [tr('app')]),
Importance.defaultImportance);
}
final completeInstallationNotification = ObtainiumNotification( final completeInstallationNotification = ObtainiumNotification(
1, 1,
tr('completeAppInstallation'), tr('completeAppInstallation'),

View File

@ -17,41 +17,14 @@ import 'package:shared_storage/shared_storage.dart' as saf;
String obtainiumTempId = 'imranr98_obtainium_${GitHub().hosts[0]}'; String obtainiumTempId = 'imranr98_obtainium_${GitHub().hosts[0]}';
String obtainiumId = 'dev.imranr.obtainium'; String obtainiumId = 'dev.imranr.obtainium';
String obtainiumUrl = 'https://github.com/ImranR98/Obtainium'; String obtainiumUrl = 'https://github.com/ImranR98/Obtainium';
Color obtainiumThemeColor = const Color(0xFF6438B5);
enum InstallMethodSettings { normal, shizuku, root }
enum ThemeSettings { system, light, dark } enum ThemeSettings { system, light, dark }
enum ColourSettings { basic, materialYou }
enum SortColumnSettings { added, nameAuthor, authorName, releaseDate } enum SortColumnSettings { added, nameAuthor, authorName, releaseDate }
enum SortOrderSettings { ascending, descending } enum SortOrderSettings { ascending, descending }
const maxAPIRateLimitMinutes = 30;
const minUpdateIntervalMinutes = maxAPIRateLimitMinutes + 30;
const maxUpdateIntervalMinutes = 43200;
List<int> updateIntervals = [
15,
30,
60,
120,
180,
360,
720,
1440,
4320,
10080,
20160,
43200,
0
]
.where((element) =>
(element >= minUpdateIntervalMinutes &&
element <= maxUpdateIntervalMinutes) ||
element == 0)
.toList();
class SettingsProvider with ChangeNotifier { class SettingsProvider with ChangeNotifier {
SharedPreferences? prefs; SharedPreferences? prefs;
String? defaultAppDir; String? defaultAppDir;
@ -75,13 +48,12 @@ class SettingsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
InstallMethodSettings get installMethod { bool get useShizuku{
return InstallMethodSettings.values[ return prefs?.getBool('useShizuku') ?? false;
prefs?.getInt('installMethod') ?? InstallMethodSettings.normal.index];
} }
set installMethod(InstallMethodSettings t) { set useShizuku(bool useShizuku) {
prefs?.setInt('installMethod', t.index); prefs?.setBool('useShizuku', useShizuku);
notifyListeners(); notifyListeners();
} }
@ -95,13 +67,23 @@ class SettingsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
ColourSettings get colour { Color get themeColor {
return ColourSettings int? colorCode = prefs?.getInt('themeColor');
.values[prefs?.getInt('colour') ?? ColourSettings.basic.index]; return (colorCode != null) ?
Color(colorCode) : obtainiumThemeColor;
} }
set colour(ColourSettings t) { set themeColor(Color themeColor) {
prefs?.setInt('colour', t.index); prefs?.setInt('themeColor', themeColor.value);
notifyListeners();
}
bool get useMaterialYou {
return prefs?.getBool('useMaterialYou') ?? false;
}
set useMaterialYou(bool useMaterialYou) {
prefs?.setBool('useMaterialYou', useMaterialYou);
notifyListeners(); notifyListeners();
} }
@ -115,21 +97,20 @@ class SettingsProvider with ChangeNotifier {
} }
int get updateInterval { int get updateInterval {
var min = prefs?.getInt('updateInterval') ?? 360; return prefs?.getInt('updateInterval') ?? 360;
if (!updateIntervals.contains(min)) {
var temp = updateIntervals[0];
for (var i in updateIntervals) {
if (min > i && i != 0) {
temp = i;
}
}
min = temp;
}
return min;
} }
set updateInterval(int min) { set updateInterval(int min) {
prefs?.setInt('updateInterval', (min < 15 && min != 0) ? 15 : min); prefs?.setInt('updateInterval', min);
notifyListeners();
}
double get updateIntervalSliderVal {
return prefs?.getDouble('updateIntervalSliderVal') ?? 6.0;
}
set updateIntervalSliderVal(double val) {
prefs?.setDouble('updateIntervalSliderVal', val);
notifyListeners(); notifyListeners();
} }

View File

@ -47,9 +47,10 @@ class APKDetails {
late AppNames names; late AppNames names;
late DateTime? releaseDate; late DateTime? releaseDate;
late String? changeLog; late String? changeLog;
late List<MapEntry<String, String>> allAssetUrls;
APKDetails(this.version, this.apkUrls, this.names, APKDetails(this.version, this.apkUrls, this.names,
{this.releaseDate, this.changeLog}); {this.releaseDate, this.changeLog, this.allAssetUrls = const []});
} }
stringMapListTo2DList(List<MapEntry<String, String>> mapList) => stringMapListTo2DList(List<MapEntry<String, String>> mapList) =>
@ -223,6 +224,7 @@ class App {
String? installedVersion; String? installedVersion;
late String latestVersion; late String latestVersion;
List<MapEntry<String, String>> apkUrls = []; List<MapEntry<String, String>> apkUrls = [];
List<MapEntry<String, String>> otherAssetUrls = [];
late int preferredApkIndex; late int preferredApkIndex;
late Map<String, dynamic> additionalSettings; late Map<String, dynamic> additionalSettings;
late DateTime? lastUpdateCheck; late DateTime? lastUpdateCheck;
@ -248,7 +250,8 @@ class App {
this.releaseDate, this.releaseDate,
this.changeLog, this.changeLog,
this.overrideSource, this.overrideSource,
this.allowIdChange = false}); this.allowIdChange = false,
this.otherAssetUrls = const []});
@override @override
String toString() { String toString() {
@ -280,41 +283,44 @@ class App {
changeLog: changeLog, changeLog: changeLog,
releaseDate: releaseDate, releaseDate: releaseDate,
overrideSource: overrideSource, overrideSource: overrideSource,
allowIdChange: allowIdChange); allowIdChange: allowIdChange,
otherAssetUrls: otherAssetUrls);
factory App.fromJson(Map<String, dynamic> json) { factory App.fromJson(Map<String, dynamic> json) {
json = appJSONCompatibilityModifiers(json); json = appJSONCompatibilityModifiers(json);
return App( return App(
json['id'] as String, json['id'] as String,
json['url'] as String, json['url'] as String,
json['author'] as String, json['author'] as String,
json['name'] as String, json['name'] as String,
json['installedVersion'] == null json['installedVersion'] == null
? null ? null
: json['installedVersion'] as String, : json['installedVersion'] as String,
(json['latestVersion'] ?? tr('unknown')) as String, (json['latestVersion'] ?? tr('unknown')) as String,
assumed2DlistToStringMapList(jsonDecode( assumed2DlistToStringMapList(
(json['apkUrls'] ?? '[["placeholder", "placeholder"]]'))), jsonDecode((json['apkUrls'] ?? '[["placeholder", "placeholder"]]'))),
(json['preferredApkIndex'] ?? -1) as int, (json['preferredApkIndex'] ?? -1) as int,
jsonDecode(json['additionalSettings']) as Map<String, dynamic>, jsonDecode(json['additionalSettings']) as Map<String, dynamic>,
json['lastUpdateCheck'] == null json['lastUpdateCheck'] == null
? null ? null
: DateTime.fromMicrosecondsSinceEpoch(json['lastUpdateCheck']), : DateTime.fromMicrosecondsSinceEpoch(json['lastUpdateCheck']),
json['pinned'] ?? false, json['pinned'] ?? false,
categories: json['categories'] != null categories: json['categories'] != null
? (json['categories'] as List<dynamic>) ? (json['categories'] as List<dynamic>)
.map((e) => e.toString()) .map((e) => e.toString())
.toList() .toList()
: json['category'] != null : json['category'] != null
? [json['category'] as String] ? [json['category'] as String]
: [], : [],
releaseDate: json['releaseDate'] == null releaseDate: json['releaseDate'] == null
? null ? null
: DateTime.fromMicrosecondsSinceEpoch(json['releaseDate']), : DateTime.fromMicrosecondsSinceEpoch(json['releaseDate']),
changeLog: changeLog: json['changeLog'] == null ? null : json['changeLog'] as String,
json['changeLog'] == null ? null : json['changeLog'] as String, overrideSource: json['overrideSource'],
overrideSource: json['overrideSource'], allowIdChange: json['allowIdChange'] ?? false,
allowIdChange: json['allowIdChange'] ?? false); otherAssetUrls: assumed2DlistToStringMapList(
jsonDecode((json['otherAssetUrls'] ?? '[]'))),
);
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -325,6 +331,7 @@ class App {
'installedVersion': installedVersion, 'installedVersion': installedVersion,
'latestVersion': latestVersion, 'latestVersion': latestVersion,
'apkUrls': jsonEncode(stringMapListTo2DList(apkUrls)), 'apkUrls': jsonEncode(stringMapListTo2DList(apkUrls)),
'otherAssetUrls': jsonEncode(stringMapListTo2DList(otherAssetUrls)),
'preferredApkIndex': preferredApkIndex, 'preferredApkIndex': preferredApkIndex,
'additionalSettings': jsonEncode(additionalSettings), 'additionalSettings': jsonEncode(additionalSettings),
'lastUpdateCheck': lastUpdateCheck?.microsecondsSinceEpoch, 'lastUpdateCheck': lastUpdateCheck?.microsecondsSinceEpoch,
@ -514,6 +521,11 @@ abstract class AppSource {
label: tr('autoApkFilterByArch'), defaultValue: true) label: tr('autoApkFilterByArch'), defaultValue: true)
], ],
[GeneratedFormTextField('appName', label: tr('appName'), required: false)], [GeneratedFormTextField('appName', label: tr('appName'), required: false)],
[
GeneratedFormSwitch('shizukuPretendToBeGooglePlay',
label: tr('shizukuPretendToBeGooglePlay'),
defaultValue: false)
],
[ [
GeneratedFormSwitch('exemptFromBackgroundUpdates', GeneratedFormSwitch('exemptFromBackgroundUpdates',
label: tr('exemptFromBackgroundUpdates')) label: tr('exemptFromBackgroundUpdates'))
@ -892,8 +904,10 @@ class SourceProvider {
allowIdChange: currentApp?.allowIdChange ?? allowIdChange: currentApp?.allowIdChange ??
trackOnly || trackOnly ||
(source.appIdInferIsOptional && (source.appIdInferIsOptional &&
inferAppIdIfOptional) // Optional ID inferring may be incorrect - allow correction on first install inferAppIdIfOptional), // Optional ID inferring may be incorrect - allow correction on first install
); otherAssetUrls: apk.allAssetUrls
.where((a) => apk.apkUrls.indexWhere((p) => a.key == p.key) < 0)
.toList());
return source.endOfGetAppChanges(finalApp); return source.endOfGetAppChanges(finalApp);
} }

View File

@ -5,10 +5,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: android_intent_plus name: android_intent_plus
sha256: e92d14009f3f6ebafca6a601958aaebb793559fb03a1961fe3c5596db95af2cb sha256: "2bfdbee8d65e7c26f88b66f0a91f2863da4d3596d8a658b4162c8de5cf04b074"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.1" version: "5.0.2"
android_package_installer: android_package_installer:
dependency: "direct main" dependency: "direct main"
description: description:
@ -26,6 +26,15 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.7.1"
android_system_font:
dependency: "direct main"
description:
path: "."
ref: master
resolved-ref: "355f897e92a58a803f91d9270d389d9ec40ba550"
url: "https://github.com/re7gog/android_system_font"
source: git
version: "1.0.0"
animations: animations:
dependency: "direct main" dependency: "direct main"
description: description:
@ -38,26 +47,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: app_links name: app_links
sha256: "42dc15aecf2618ace4ffb74a2e58a50e45cd1b9f2c17c8f0cafe4c297f08c815" sha256: "1c2b9e9c56d80d17610bcbd111b37187875c5d0ded8654caa1bda14ea753d001"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.1" version: "6.0.1"
archive: archive:
dependency: transitive dependency: transitive
description: description:
name: archive name: archive
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.10" version: "3.5.1"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.5.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -70,10 +79,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: background_fetch name: background_fetch
sha256: dbffec0317ccdef6e2014cb543e147f52441e29c4fcb53dfd23558c4d92ddece sha256: "2fe367c9be0e256dadb75b8b637b0b58a2a2d2317b7c8420bb1ae8b41e23fde3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.3.4"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -126,10 +135,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: connectivity_plus name: connectivity_plus
sha256: e9feae83b1849f61bad9f6f33ee00646e3410d54ce0821e02f262f9901dad3c9 sha256: db7a4e143dc72cc3cb2044ef9b052a7ebfe729513e6a82943bc3526f784365b8
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.1" version: "6.0.3"
connectivity_plus_platform_interface: connectivity_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -138,14 +147,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
cross_file: cross_file:
dependency: transitive dependency: transitive
description: description:
@ -174,10 +175,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: cupertino_icons name: cupertino_icons
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.6" version: "1.0.8"
dbus: dbus:
dependency: transitive dependency: transitive
description: description:
@ -190,10 +191,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: device_info_plus name: device_info_plus
sha256: "50fb435ed30c6d2525cbfaaa0f46851ea6131315f213c0d921b0e407b34e3b84" sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.1" version: "10.1.0"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -214,10 +215,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: easy_localization name: easy_localization
sha256: c145aeb6584aedc7c862ab8c737c3277788f47488bfdf9bae0fe112bd0a4789c sha256: "432698c31a488dd64c56d4759f20d04844baba5e9e4f2cb1abb9676257918b17"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.5" version: "3.0.6"
easy_logger: easy_logger:
dependency: transitive dependency: transitive
description: description:
@ -226,6 +227,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.0.2" version: "0.0.2"
equations:
dependency: "direct main"
description:
name: equations
sha256: ae30e977d601e19aa1fc3409736c5eac01559d1d653a4c30141fbc4e86aa605c
url: "https://pub.dev"
source: hosted
version: "5.0.2"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -254,10 +263,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_picker name: file_picker
sha256: d1d0ac3966b36dc3e66eeefb40280c17feb87fa2099c6e22e6a1fc959327bd03 sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.0.0+1" version: "8.0.3"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@ -266,6 +275,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
flex_color_picker:
dependency: "direct main"
description:
name: flex_color_picker
sha256: "5c846437069fb7afdd7ade6bf37e628a71d2ab0787095ddcb1253bf9345d5f3a"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
flex_seed_scheme:
dependency: transitive
description:
name: flex_seed_scheme
sha256: "4cee2f1d07259f77e8b36f4ec5f35499d19e74e17c7dce5b819554914082bc01"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -275,10 +300,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_archive name: flutter_archive
sha256: "004132780d382df5171589ab793e2efc9c3eef570fe72d78b4ccfbfbe52762ae" sha256: "5ca235f304c12bf468979235f400f79846d204169d715939e39197106f5fc970"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.0.3"
flutter_fgbg: flutter_fgbg:
dependency: "direct main" dependency: "direct main"
description: description:
@ -307,10 +332,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: f9a05409385b77b06c18f200a41c7c2711ebf7415669350bb0f8474c07bd40d1 sha256: "84a3af6c7fb43c85c3528b434dacc7a7ed4551d1209d93773bf6045cec9ace68"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "17.0.0" version: "17.1.1"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
@ -323,10 +348,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_platform_interface name: flutter_local_notifications_platform_interface
sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" sha256: "340abf67df238f7f0ef58f4a26d2a83e1ab74c77ab03cd2b2d5018ac64db30b7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0+1" version: "7.1.0"
flutter_localizations: flutter_localizations:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -336,18 +361,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_markdown name: flutter_markdown
sha256: "87e11b9df25a42e2db315b8b7a51fae8e66f57a4b2f50ec4b822d0fa155e6b52" sha256: "9921f9deda326f8a885e202b1e35237eadfc1345239a0f6f0f1ff287e047547f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.22" version: "0.7.1"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
name: flutter_plugin_android_lifecycle name: flutter_plugin_android_lifecycle
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.17" version: "2.0.19"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -362,10 +387,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: fluttertoast name: fluttertoast
sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1 sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.2.4" version: "8.2.5"
fraction:
dependency: transitive
description:
name: fraction
sha256: "09e9504c9177bbd77df56e5d147abfbb3b43360e64bf61510059c14d6a82d524"
url: "https://pub.dev"
source: hosted
version: "5.0.2"
gtk: gtk:
dependency: transitive dependency: transitive
description: description:
@ -422,22 +455,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.18.1"
js:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.7.1"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
name: json_annotation name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.8.1" version: "4.9.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
@ -538,18 +563,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.3"
path_provider_android: path_provider_android:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.2.4"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
@ -594,10 +619,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_android name: permission_handler_android
sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" sha256: "8bb852cd759488893805c3161d0b2b5db55db52f773dbb014420b304055ba2c5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.0.5" version: "12.0.6"
permission_handler_apple: permission_handler_apple:
dependency: transitive dependency: transitive
description: description:
@ -634,10 +659,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: petitparser name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.2" version: "5.4.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -654,14 +679,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
url: "https://pub.dev"
source: hosted
version: "3.7.4"
provider: provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -674,34 +691,34 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: "05ec043470319bfbabe0adbc90d3a84cbff0426b9d9f3a6e2ad3e131fa5fa629" sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.0.2" version: "9.0.0"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: share_plus_platform_interface name: share_plus_platform_interface
sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496" sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.0" version: "4.0.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences name: shared_preferences
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.2.3"
shared_preferences_android: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.2.2"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
@ -750,6 +767,15 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.1" version: "0.8.1"
shizuku_apk_installer:
dependency: "direct main"
description:
path: "."
ref: master
resolved-ref: "25acc02612c2e0fcae40d312e047ac48106f8f6b"
url: "https://github.com/re7gog/shizuku_apk_installer"
source: git
version: "0.0.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -775,10 +801,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: sqflite name: sqflite
sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.3.3+1"
sqflite_common: sqflite_common:
dependency: transitive dependency: transitive
description: description:
@ -839,10 +865,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: timezone name: timezone
sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.2" version: "0.9.3"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -855,18 +881,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e" sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.5" version: "6.2.6"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.0" version: "6.3.1"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
@ -903,10 +929,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d" sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.1"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
@ -919,10 +945,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: uuid name: uuid
sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.3.3" version: "4.4.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -959,10 +985,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_android name: webview_flutter_android
sha256: f038ee2fae73b509dde1bc9d2c5a50ca92054282de17631a9a3d515883740934 sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.16.0" version: "3.16.1"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -983,18 +1009,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480" sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.3.0" version: "5.5.0"
win32_registry: win32_registry:
dependency: transitive dependency: transitive
description: description:
name: win32_registry name: win32_registry
sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a" sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "1.1.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@ -1007,10 +1033,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: xml name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.5.0" version: "6.3.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
@ -1020,5 +1046,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.3.0 <4.0.0" dart: ">=3.3.3 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.19.0"

View File

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.1.0+2257 version: 1.1.7+2264
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
@ -56,18 +56,28 @@ dependencies:
url: https://github.com/ImranR98/android_package_installer url: https://github.com/ImranR98/android_package_installer
ref: main ref: main
android_package_manager: ^0.7.0 android_package_manager: ^0.7.0
share_plus: ^8.0.2 share_plus: ^9.0.0
sqflite: ^2.2.0+3 sqflite: ^2.2.0+3
easy_localization: ^3.0.1 easy_localization: ^3.0.1
android_intent_plus: ^5.0.1 android_intent_plus: ^5.0.1
flutter_markdown: ^0.6.14 flutter_markdown: ^0.7.1
flutter_archive: ^6.0.0 flutter_archive: ^6.0.0
hsluv: ^1.1.3 hsluv: ^1.1.3
connectivity_plus: ^6.0.1 connectivity_plus: ^6.0.1
shared_storage: ^0.8.0 shared_storage: ^0.8.0
crypto: ^3.0.3 crypto: ^3.0.3
app_links: ^4.0.0 app_links: ^6.0.1
background_fetch: ^1.2.1 background_fetch: ^1.2.1
equations: ^5.0.2
flex_color_picker: ^3.4.1
android_system_font:
git:
url: https://github.com/re7gog/android_system_font
ref: master
shizuku_apk_installer:
git:
url: https://github.com/re7gog/shizuku_apk_installer
ref: master
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: