mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-30 21:13:28 +01:00 
			
		
		
		
	Compare commits
	
		
			59 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 84df499ea6 | ||
|  | 0d25b74050 | ||
|  | 0effbc3841 | ||
|  | 7478a7af22 | ||
|  | 0838a6d30b | ||
|  | 8cee268d13 | ||
|  | a3fddc5400 | ||
|  | c0a2e372e5 | ||
|  | c633963203 | ||
|  | 299f457938 | ||
|  | 37e62c922b | ||
|  | 95722ce47b | ||
|  | 8b806b3ef1 | ||
|  | 09221b3526 | ||
|  | 31b6250082 | ||
|  | 07372da91b | ||
|  | 5c36bcfb4b | ||
|  | e5012b1fcb | ||
|  | 6f951175a4 | ||
|  | be52ec372f | ||
|  | eb7126afc3 | ||
|  | 26fc63a02a | ||
|  | d33ca0948f | ||
|  | f76637a2e1 | ||
|  | b7de627c7b | ||
|  | 27fc60d437 | ||
|  | ec240f946e | ||
|  | ecd80fc371 | ||
|  | 68fa660e6d | ||
|  | 70f9e33d17 | ||
|  | 2e2dffd8e2 | ||
|  | 0b1d5bf514 | ||
|  | 2570c8e289 | ||
|  | 43a8ba4de1 | ||
|  | 3f2fb1c1ed | ||
|  | 40d303fb57 | ||
|  | 2c1687c33d | ||
|  | b688e7f160 | ||
|  | 0c80d88583 | ||
|  | b293b1e9ff | ||
|  | 61038a8969 | ||
|  | b92d1541bf | ||
|  | 13f0ccb10d | ||
|  | ed732cfad2 | ||
|  | fb206aee84 | ||
|  | 285530784d | ||
|  | 0ddb5b5e81 | ||
|  | c16cda1962 | ||
|  | 49022726d3 | ||
|  | a311894b9f | ||
|  | 29e13efd66 | ||
|  | 3131ef8c4e | ||
|  | 7b882d9bd8 | ||
|  | fb06babb96 | ||
|  | 2289e58dda | ||
|  | 049bcfbaf5 | ||
|  | 5b5f922b54 | ||
|  | 6545498c21 | ||
|  | 9717db0ca4 | 
							
								
								
									
										2
									
								
								.flutter
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								.flutter
									
									
									
									
									
								
							 Submodule .flutter updated: 300451adae...54e66469a9
									
								
							
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							| @@ -29,15 +29,23 @@ Currently supported App sources: | ||||
|   - [Huawei AppGallery](https://appgallery.huawei.com/) | ||||
|   - Jenkins Jobs | ||||
| - Open Source - App-Specific: | ||||
|   - [Mullvad](https://mullvad.net/en/) | ||||
|   - [Signal](https://signal.org/) | ||||
|   - [VLC](https://videolan.org/) | ||||
| - Other - App-Specific: | ||||
|   - [WhatsApp](https://whatsapp.com) | ||||
|   - [Telegram App](https://telegram.org) | ||||
|   - [Neutron Code](https://neutroncode.com) | ||||
| - Direct APK Link | ||||
| - "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 | ||||
|  | ||||
| [<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png" | ||||
|   | ||||
| @@ -92,20 +92,6 @@ repositories { | ||||
|     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] | ||||
| import com.android.build.OutputFile | ||||
| android.applicationVariants.all { variant -> | ||||
|   | ||||
| @@ -47,7 +47,7 @@ | ||||
|             android:value="2" /> | ||||
|         <provider | ||||
|             android:name="androidx.core.content.FileProvider" | ||||
|             android:authorities="dev.imranr.obtainium" | ||||
|             android:authorities="${applicationId}" | ||||
|             android:grantUriPermissions="true"> | ||||
|             <meta-data | ||||
|                 android:name="android.support.FILE_PROVIDER_PATHS" | ||||
|   | ||||
| @@ -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" | ||||
|     } | ||||
| } | ||||
| @@ -1,179 +1,5 @@ | ||||
| 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.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() { | ||||
|     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) | ||||
|     } | ||||
| } | ||||
| class MainActivity: FlutterActivity() | ||||
|   | ||||
| @@ -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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     }*/ | ||||
| } | ||||
| @@ -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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,3 +1,3 @@ | ||||
| org.gradle.jvmargs=-Xmx1536M | ||||
| org.gradle.jvmargs=-Xmx2048M | ||||
| android.useAndroidX=true | ||||
| android.enableJetifier=true | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(obavezno)", | ||||
|     "dropdownNoOptsError": "GREŠKA: PADAJUĆI MENI MORA IMATI NAJMANJE JEDNU OPCIJU", | ||||
|     "colour": "Boja", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Custom", | ||||
|     "useMaterialYou": "Use Material You", | ||||
|     "githubStarredRepos": "GitHub repo-i sa zvjezdicom", | ||||
|     "uname": "Korisničko ime", | ||||
|     "wrongArgNum": "Naveden je pogrešan broj argumenata", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Tamna", | ||||
|     "light": "Svijetla", | ||||
|     "followSystem": "Pratite sistem", | ||||
|     "followSystemThemeExplanation": "Following system theme is possible only by using third-party applications", | ||||
|     "useBlackTheme": "Koristite čisto crnu tamnu temu", | ||||
|     "appSortBy": "Aplikacije sortirane po", | ||||
|     "authorName": "Autor/Ime", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Nema novih ažuriranja.", | ||||
|     "xHasAnUpdate": "{} ima ažuriranje.", | ||||
|     "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", | ||||
|     "xWasUpdatedToY": "{} je ažuriran na {}.", | ||||
|     "xWasNotUpdatedToY": "Failed to update {} to {}.", | ||||
|     "errorCheckingUpdates": "Greška pri provjeri ažuriranja", | ||||
|     "errorCheckingUpdatesNotifDescription": "Obavijest koja se prikazuje kada provjera sigurnosnog ažuriranja ne uspije", | ||||
|     "appsRemoved": "Aplikacije su uklonjene", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Podržite fiksne APK URL-ove", | ||||
|     "selectX": "Izaberite {}", | ||||
|     "parallelDownloads": "Dozvoli paralelna preuzimanja", | ||||
|     "installMethod": "Način instalacije", | ||||
|     "normal": "normalno", | ||||
|     "root": "korijen", | ||||
|     "useShizuku": "Use Shizuku or Sui to install", | ||||
|     "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", | ||||
|     "systemFontError": "Greška pri učitavanju sistemskog fonta: {}", | ||||
|     "useVersionCodeAsOSVersion": "Koristite kod verzije aplikacije kao verziju koju je otkrio OS", | ||||
|     "requestHeader": "Zaglavlje zahtjeva", | ||||
|     "useLatestAssetDateAsReleaseDate": "Koristite najnovije otpremanje materijala kao datum izdavanja", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "The APK could not be parsed (incompatible or partial download)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", | ||||
|     "appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", | ||||
|     "wiki": "Help/Wiki", | ||||
|     "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Želite li ukloniti aplikaciju?", | ||||
|         "other": "Želite li ukloniti aplikacije?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} i još 1 aplikacija je ažurirana.", | ||||
|         "other": "{} i još {} aplikacija je ažurirano." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesFailed": { | ||||
|         "one": "Failed to update {} and 1 more app.", | ||||
|         "other": "Failed to update {} and {} more apps." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "one": "{} i još jedna aplikacija je vjerovatno ažurirana.", | ||||
|         "other": "{} i još {} aplikacija su vjerovatno ažurirane." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Požadované)", | ||||
|     "dropdownNoOptsError": "ERROR: DROPDOWN MUSÍ MÍT AŽ JEDNU MOŽNOST", | ||||
|     "colour": "Barva", | ||||
|     "standard": "Standardní", | ||||
|     "custom": "Vlastní", | ||||
|     "useMaterialYou": "Použijte materiál, který jste", | ||||
|     "githubStarredRepos": "GitHub označená hvězdičkou", | ||||
|     "uname": "Uživatelské jméno", | ||||
|     "wrongArgNum": "Nesprávný počet zadaných argumentů", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Tmavé", | ||||
|     "light": "Světlé", | ||||
|     "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", | ||||
|     "appSortBy": "Seřadit podle", | ||||
|     "authorName": "Autor/Jméno", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Žádné nové aktualizace.", | ||||
|     "xHasAnUpdate": "{} má aktualizaci.", | ||||
|     "appsUpdated": "Aplikace aktualizovány", | ||||
|     "appsNotUpdated": "Nepodařilo se aktualizovat aplikace", | ||||
|     "appsUpdatedNotifDescription": "Upozornit, že byly provedeny aktualizace jedné nebo více aplikací na pozadí", | ||||
|     "xWasUpdatedToY": "{} byla aktualizována na {}", | ||||
|     "xWasNotUpdatedToY": "Nepodařilo se aktualizovat {} na {}.", | ||||
|     "errorCheckingUpdates": "Chyba kontroly aktualizací", | ||||
|     "errorCheckingUpdatesNotifDescription": "Zobrazit oznámení při neúspěšné kontrole aktualizací na pozadí", | ||||
|     "appsRemoved": "Odstraněné aplikace", | ||||
| @@ -282,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", | ||||
|     "selectX": "Vybrat {}", | ||||
|     "parallelDownloads": "Povolit souběžné stahování", | ||||
|     "installMethod": "Metoda instalace", | ||||
|     "normal": "Normální", | ||||
|     "root": "Správce", | ||||
|     "useShizuku": "K instalaci použijte Shizuku nebo Sui", | ||||
|     "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", | ||||
|     "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", | ||||
|     "requestHeader": "Hlavička požadavku", | ||||
|     "useLatestAssetDateAsReleaseDate": "Použít poslední nahrané dílo jako datum vydání", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "APK nelze analyzovat (nekompatibilní nebo částečné stažení)", | ||||
|     "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.", | ||||
|     "wiki": "Nápověda/Wiki", | ||||
|     "crowdsourcedConfigsLabel": "Konfigurace aplikací s využitím crowdsourcingu (použití na vlastní nebezpečí)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Odstranit Apku?", | ||||
|         "other": "Odstranit Apky?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} a 1 další aplikace mají aktualizace.", | ||||
|         "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": { | ||||
|         "one": "{} a 1 další aplikace možno aktualizovat", | ||||
|         "other": "{} a {} další aplikace mohou být aktualizovány." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(wird benötigt)", | ||||
|     "dropdownNoOptsError": "FEHLER: DROPDOWN MUSS MINDESTENS EINE OPTION HABEN", | ||||
|     "colour": "Farbe", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Benutzerdefiniert", | ||||
|     "useMaterialYou": "Verwende Material You", | ||||
|     "githubStarredRepos": "GitHub Starred Repos", | ||||
|     "uname": "Benutzername", | ||||
|     "wrongArgNum": "Falsche Anzahl von Argumenten (Parametern) übermittelt", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Dunkel", | ||||
|     "light": "Hell", | ||||
|     "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", | ||||
|     "appSortBy": "App sortieren nach", | ||||
|     "authorName": "Autor/Name", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Keine neuen Aktualisierungen.", | ||||
|     "xHasAnUpdate": "{} hat eine Aktualisierung.", | ||||
|     "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", | ||||
|     "xWasUpdatedToY": "{} wurde auf {} aktualisiert.", | ||||
|     "xWasNotUpdatedToY": "Die Aktualisierung von {} auf {} ist fehlgeschlagen.", | ||||
|     "errorCheckingUpdates": "Fehler beim Prüfen auf Aktualisierungen", | ||||
|     "errorCheckingUpdatesNotifDescription": "Eine Benachrichtigung, die angezeigt wird, wenn die Prüfung der Hintergrundaktualisierung fehlschlägt", | ||||
|     "appsRemoved": "Apps entfernt", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "neuere Version anhand der ersten dreißig Zahlen der Checksumme der APK URL erraten, wenn anderweitig nicht unterstützt", | ||||
|     "selectX": "Wähle {}", | ||||
|     "parallelDownloads": "Erlaube parallele Downloads", | ||||
|     "installMethod": "Installationsmethode", | ||||
|     "normal": "Normal", | ||||
|     "root": "Root", | ||||
|     "useShizuku": "Verwenden Sie Shizuku oder Sui zur Installation", | ||||
|     "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", | ||||
|     "systemFontError": "Fehler beim Laden der Systemschriftart: {}", | ||||
|     "useVersionCodeAsOSVersion": "Verwende die Appversion als erkannte Version vom Betriebssystem", | ||||
|     "requestHeader": "Request Header", | ||||
|     "useLatestAssetDateAsReleaseDate": "Den letzten Asset-Upload als Veröffentlichungsdatum verwenden", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "Die APK konnte nicht geparst werden (inkompatibler oder teilweiser Download)", | ||||
|     "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.", | ||||
|     "wiki": "Hilfe/Wiki", | ||||
|     "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (Verwendung auf eigene Gefahr)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "App entfernen?", | ||||
|         "other": "Apps entfernen?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} und 1 weitere Anwendung 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": { | ||||
|         "one": "{} und 1 weitere Anwendung wurden möglicherweise aktualisiert.", | ||||
|         "other": "{} und {} weitere Anwendungen wurden möglicherweise aktualisiert." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Required)", | ||||
|     "dropdownNoOptsError": "ERROR: DROPDOWN MUST HAVE AT LEAST ONE OPT", | ||||
|     "colour": "Colour", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Custom", | ||||
|     "useMaterialYou": "Use Material You", | ||||
|     "githubStarredRepos": "GitHub Starred Repos", | ||||
|     "uname": "Username", | ||||
|     "wrongArgNum": "Wrong number of arguments provided", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Dark", | ||||
|     "light": "Light", | ||||
|     "followSystem": "Follow System", | ||||
|     "followSystemThemeExplanation": "Following system theme is possible only by using third-party applications", | ||||
|     "useBlackTheme": "Use pure black dark theme", | ||||
|     "appSortBy": "App Sort By", | ||||
|     "authorName": "Author/Name", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "No new updates.", | ||||
|     "xHasAnUpdate": "{} has an update.", | ||||
|     "appsUpdated": "Apps Updated", | ||||
|     "appsNotUpdated": "Failed to update applications", | ||||
|     "appsUpdatedNotifDescription": "Notifies the user that updates to one or more Apps were applied in the background", | ||||
|     "xWasUpdatedToY": "{} was updated to {}.", | ||||
|     "xWasNotUpdatedToY": "Failed to update {} to {}.", | ||||
|     "errorCheckingUpdates": "Error Checking for Updates", | ||||
|     "errorCheckingUpdatesNotifDescription": "A notification that shows when background update checking fails", | ||||
|     "appsRemoved": "Apps Removed", | ||||
| @@ -253,7 +259,7 @@ | ||||
|     "bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi", | ||||
|     "autoSelectHighestVersionCode": "Auto-select highest versionCode APK", | ||||
|     "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", | ||||
|     "pickExportDir": "Pick Export Directory", | ||||
|     "autoExportOnChanges": "Auto-export on changes", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Support fixed APK URLs", | ||||
|     "selectX": "Select {}", | ||||
|     "parallelDownloads": "Allow parallel downloads", | ||||
|     "installMethod": "Installation method", | ||||
|     "normal": "Normal", | ||||
|     "root": "Root", | ||||
|     "shizukuBinderNotFound": "Сompatible Shizuku service wasn't found", | ||||
|     "useShizuku": "Use Shizuku or Sui to install", | ||||
|     "shizukuBinderNotFound": "Shizuku service 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": "Use the system font", | ||||
|     "systemFontError": "Error loading the system font: {}", | ||||
|     "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", | ||||
|     "requestHeader": "Request header", | ||||
|     "useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "The APK could not be parsed (incompatible or partial download)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", | ||||
|     "appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", | ||||
|     "wiki": "Help/Wiki", | ||||
|     "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Remove App?", | ||||
|         "other": "Remove Apps?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} and 1 more app was updated.", | ||||
|         "other": "{} and {} more apps were updated." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesFailed": { | ||||
|         "one": "Failed to update {} and 1 more app.", | ||||
|         "other": "Failed to update {} and {} more apps." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "one": "{} and 1 more app may have been updated.", | ||||
|         "other": "{} and {} more apps may have been updated." | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| { | ||||
|     "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", | ||||
|     "urlMatchesNoSource": "El URL no coincide con ninguna fuente conocida", | ||||
|     "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", | ||||
|     "placeholder": "Espacio reservado", | ||||
|     "someErrors": "Han ocurrido algunos errores", | ||||
| @@ -22,14 +22,17 @@ | ||||
|     "requiredInBrackets": "(Requerido)", | ||||
|     "dropdownNoOptsError": "ERROR: EL DESPLEGABLE DEBE TENER AL MENOS UNA OPCIÓN", | ||||
|     "colour": "Color", | ||||
|     "standard": "Estándar", | ||||
|     "custom": "A medida", | ||||
|     "useMaterialYou": "Use 'Material You'", | ||||
|     "githubStarredRepos": "Repositorios favoritos en GitHub", | ||||
|     "uname": "Nombre de usuario", | ||||
|     "wrongArgNum": "Número de argumentos provistos inválido", | ||||
|     "xIsTrackOnly": "{} es de 'sólo seguimiento'", | ||||
|     "source": "Origen", | ||||
|     "app": "Aplicación", | ||||
|     "appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son de 'solo seguimiento'.", | ||||
|     "youPickedTrackOnly": "Debe seleccionar la opción de 'solo seguimiento'.", | ||||
|     "appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para 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.", | ||||
|     "cancelled": "Cancelado", | ||||
|     "appAlreadyAdded": "Aplicación añadida anteriormente", | ||||
| @@ -42,14 +45,14 @@ | ||||
|     "search": "Buscar", | ||||
|     "additionalOptsFor": "Opciones adicionales para {}", | ||||
|     "supportedSources": "Fuentes admitidas", | ||||
|     "trackOnlyInBrackets": "(Solo seguimiento)", | ||||
|     "trackOnlyInBrackets": "(Solo para seguimiento)", | ||||
|     "searchableInBrackets": "(permite búsqueda)", | ||||
|     "appsString": "Aplicaciones", | ||||
|     "noApps": "Sin Aplicaciones", | ||||
|     "noAppsForFilter": "Sin aplicaciones para filtrar", | ||||
|     "byX": "por: {}", | ||||
|     "percentProgress": "Progreso: {} %", | ||||
|     "pleaseWait": "Espere un momento", | ||||
|     "pleaseWait": "Espere...", | ||||
|     "updateAvailable": "Actualización disponible", | ||||
|     "notInstalled": "No instalado", | ||||
|     "pseudoVersion": "pseudoversión", | ||||
| @@ -60,7 +63,7 @@ | ||||
|     "removeSelectedApps": "Eliminar aplicaciones seleccionadas", | ||||
|     "updateX": "Actualizar {}", | ||||
|     "installX": "Instalar {}", | ||||
|     "markXTrackOnlyAsUpdated": "Marcar {}\n(Solo seguimiento)\ncomo actualizada", | ||||
|     "markXTrackOnlyAsUpdated": "Marcar {}\n(solo para seguimiento)\ncomo actualizada", | ||||
|     "changeX": "Cambiar {}", | ||||
|     "installUpdateApps": "Instalar/actualizar aplicaciones", | ||||
|     "installUpdateSelectedApps": "Instalar/actualizar aplicaciones seleccionadas", | ||||
| @@ -97,7 +100,7 @@ | ||||
|     "appURLList": "Lista de URL de aplicaciones", | ||||
|     "line": "Línea", | ||||
|     "searchX": "Buscar {}", | ||||
|     "noResults": "No se encontró ningún resultado", | ||||
|     "noResults": "No se ha encontrado ningún resultado", | ||||
|     "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.", | ||||
|     "importErrors": "Errores de Importación", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Oscuro", | ||||
|     "light": "Claro", | ||||
|     "followSystem": "Seguir al sistema", | ||||
|     "followSystemThemeExplanation": "Seguir el tema del sistema sólo es posible utilizando aplicaciones de terceros", | ||||
|     "useBlackTheme": "Negro puro en tema oscuro", | ||||
|     "appSortBy": "Ordenar aplicaciones por", | ||||
|     "authorName": "Autor/nombre", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "No hay nuevas actualizaciones.", | ||||
|     "xHasAnUpdate": "{} tiene una actualización.", | ||||
|     "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", | ||||
|     "xWasUpdatedToY": "{} ha sido actualizada a {}.", | ||||
|     "xWasNotUpdatedToY": "Error al actualizar {} a {}.", | ||||
|     "errorCheckingUpdates": "Error al buscar actualizaciones", | ||||
|     "errorCheckingUpdatesNotifDescription": "Una notificación que muestra cuándo la comprobación de actualizaciones en segundo plano falla", | ||||
|     "appsRemoved": "Aplicaciones eliminadas", | ||||
| @@ -170,9 +176,9 @@ | ||||
|     "fdroid": "Repositorio oficial F-Droid", | ||||
|     "appIdOrName": "ID o Nombre 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", | ||||
|     "fdroidThirdPartyRepo": "Repositorio de tercera parte F-Droid", | ||||
|     "fdroidThirdPartyRepo": "Repositorio de terceros F-Droid", | ||||
|     "steamMobile": "Steam para móviles", | ||||
|     "steamChat": "Chat de Steam", | ||||
|     "install": "Instalar", | ||||
| @@ -185,9 +191,9 @@ | ||||
|     "downloadingX": "Descargando {}", | ||||
|     "downloadX": "Descargar {}", | ||||
|     "downloadedX": "Descargado {}", | ||||
|     "releaseAsset": "Liberar activos", | ||||
|     "releaseAsset": "Recurso publicado", | ||||
|     "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", | ||||
|     "categorize": "Catogorizar", | ||||
|     "categories": "Categorías", | ||||
| @@ -199,7 +205,7 @@ | ||||
|     "addCategory": "Añadir categoría", | ||||
|     "label": "Nombre", | ||||
|     "language": "Idioma", | ||||
|     "copiedToClipboard": "Se copió en el portapapeles", | ||||
|     "copiedToClipboard": "Copiado en el portapapeles", | ||||
|     "storagePermissionDenied": "Permiso de almacenamiento rechazado", | ||||
|     "selectedCategorizeWarning": "Esto reemplazará cualquier ajuste de categoría para las aplicaciones seleccionadas.", | ||||
|     "filterAPKsByRegEx": "Filtrar por APK", | ||||
| @@ -216,16 +222,16 @@ | ||||
|     "standardVersionDetection": "Por versión", | ||||
|     "groupByCategory": "Agrupar por categoría", | ||||
|     "autoApkFilterByArch": "Filtrar APK por arquitectura del procesador (si es posible)", | ||||
|     "overrideSource": "Anular fuente", | ||||
|     "overrideSource": "Forzar desde la fuente", | ||||
|     "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", | ||||
|     "moveNonInstalledAppsToBottom": "Mover Apps no instaladas al final", | ||||
|     "moveNonInstalledAppsToBottom": "Mover apps no instaladas al final", | ||||
|     "gitlabPATLabel": "Token de acceso personal a GitLab", | ||||
|     "about": "Acerca", | ||||
|     "requiresCredentialsInSettings": "{}: Esto requiere credenciales adicionales (en ajustes)", | ||||
|     "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", | ||||
|     "pickHighestVersionCode": "Auto selección de versión superior del paquete APK", | ||||
|     "checkUpdateOnDetailPage": "Comprobar actualizaciones al abrir detalles de la app", | ||||
| @@ -280,30 +286,32 @@ | ||||
|     "checkingForUpdatesNotifChannel": "Buscando actualizaciones", | ||||
|     "onlyCheckInstalledOrTrackOnlyApps": "Comprobar actualizaciones solo para apps instaladas o en seguimiento", | ||||
|     "supportFixedAPKURL": "Soporte para URLs fijas de APK", | ||||
|     "selectX": "Selecciona {}", | ||||
|     "selectX": "Elija {}", | ||||
|     "parallelDownloads": "Permitir descargas paralelas", | ||||
|     "installMethod": "Método de instalación", | ||||
|     "normal": "Normal", | ||||
|     "root": "Raíz", | ||||
|     "useShizuku": "Use Shizuku o Sui para instalar", | ||||
|     "shizukuBinderNotFound": "Shizuku no funciona", | ||||
|     "useSystemFont": "Usar la fuente de impresión del sistema", | ||||
|     "systemFontError": "Error al cargar la fuente de impresión del sistema: {}", | ||||
|     "shizukuOld": "Versión antigua de Shizuku (<11) - actualícela", | ||||
|     "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", | ||||
|     "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", | ||||
|     "partialAPKHash": "Hash de APK parcial", | ||||
|     "APKLinkHash": "Hash de enlace APK", | ||||
|     "directAPKLink": "Enlace APK directo", | ||||
|     "pseudoVersionInUse": "Se está utilizando una pseudoversión", | ||||
|     "pseudoVersionInUse": "Se está usando una pseudoversión", | ||||
|     "installed": "Instalado", | ||||
|     "latest": "Versión más reciente", | ||||
|     "invertRegEx": "Invertir expresión regular", | ||||
|     "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)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Compartir nuevas aplicaciones con AppVerifier (si está disponible)", | ||||
|     "appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.", | ||||
|     "wiki": "Ayuda/Wiki", | ||||
|     "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "¿Eliminar aplicación?", | ||||
|         "other": "¿Eliminar aplicaciones?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} y 1 aplicación 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": { | ||||
|         "one": "{} y 1 aplicación más podría haber sido actualizada.", | ||||
|         "other": "{} y {} aplicaciones más podrían haber sido actualizadas." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(ضروری)", | ||||
|     "dropdownNoOptsError": "خطا: کشویی باید حداقل یک گزینه داشته باشد", | ||||
|     "colour": "رنگ", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Custom", | ||||
|     "useMaterialYou": "Use Material You", | ||||
|     "githubStarredRepos": "مخازن ستاره دار گیتهاب", | ||||
|     "uname": "نام کاربری", | ||||
|     "wrongArgNum": "تعداد آرگومان های ارائه شده اشتباه است", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "تاریک", | ||||
|     "light": "روشن", | ||||
|     "followSystem": "هماهنگ با سیستم", | ||||
|     "followSystemThemeExplanation": "Following system theme is possible only by using third-party applications", | ||||
|     "useBlackTheme": "استفاده از تم تیره سیاه خالص", | ||||
|     "appSortBy": "مرتب سازی برنامه بر اساس", | ||||
|     "authorName": "سازنده/اسم", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "به روز رسانی جدیدی وجود ندارد.", | ||||
|     "xHasAnUpdate": "{} یک به روز رسانی دارد.", | ||||
|     "appsUpdated": "برنامه ها به روز شدند", | ||||
|     "appsNotUpdated": "Failed to update applications", | ||||
|     "appsUpdatedNotifDescription": "به کاربر اطلاع می دهد که به روز رسانی یک یا چند برنامه در پس زمینه اعمال شده است", | ||||
|     "xWasUpdatedToY": "{} به {} به روز شد.", | ||||
|     "xWasNotUpdatedToY": "Failed to update {} to {}.", | ||||
|     "errorCheckingUpdates": "خطا در بررسی بهروزرسانیها", | ||||
|     "errorCheckingUpdatesNotifDescription": "اعلانی که وقتی بررسی بهروزرسانی پسزمینه ناموفق است نشان میدهد", | ||||
|     "appsRemoved": "برنامه ها حذف شدند", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "پشتیبانی از URL های APK ثابت", | ||||
|     "selectX": "انتخاب کنید {}", | ||||
|     "parallelDownloads": "اجازه دانلود موازی", | ||||
|     "installMethod": "روش نصب", | ||||
|     "normal": "طبیعی", | ||||
|     "root": "ریشه", | ||||
|     "useShizuku": "Use Shizuku or Sui to install", | ||||
|     "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": "استفاده از فونت سیستم", | ||||
|     "systemFontError": "خطا در بارگیری فونت سیستم: {}", | ||||
|     "useVersionCodeAsOSVersion": "استفاده کد نسخه برنامه به جای نسخه شناسایی شده توسط سیستم عامل استفاده کنید", | ||||
|     "requestHeader": "درخواست سطر بالایی", | ||||
|     "useLatestAssetDateAsReleaseDate": "استفاده از آخرین بارگذاری دارایی به عنوان تاریخ انتشار", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "The APK could not be parsed (incompatible or partial download)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", | ||||
|     "appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", | ||||
|     "wiki": "Help/Wiki", | ||||
|     "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "برنامه حذف شود؟", | ||||
|         "other": "برنامه ها حذف شوند؟" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} و 1 برنامه دیگر به روز شدند.", | ||||
|         "other": "{} و {} برنامه دیگر به روز شدند." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesFailed": { | ||||
|         "one": "Failed to update {} and 1 more app.", | ||||
|         "other": "Failed to update {} and {} more apps." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.", | ||||
|         "other": "ممکن است {} و {} برنامه های دیگر به روز شده باشند." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Requis)", | ||||
|     "dropdownNoOptsError": "ERREUR : LE DÉROULEMENT DOIT AVOIR AU MOINS UNE OPT", | ||||
|     "colour": "Couleur", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Sur mesure", | ||||
|     "useMaterialYou": "Utiliser le matériel que vous", | ||||
|     "githubStarredRepos": "Dépôts étoilés GitHub", | ||||
|     "uname": "Nom d'utilisateur", | ||||
|     "wrongArgNum": "Mauvais nombre d'arguments fournis", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Sombre", | ||||
|     "light": "Clair", | ||||
|     "followSystem": "Suivre le système", | ||||
|     "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", | ||||
|     "authorName": "Auteur/Nom", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Aucune nouvelle mise à jour.", | ||||
|     "xHasAnUpdate": "{} a une mise à 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", | ||||
|     "xWasUpdatedToY": "{} a été mis à jour pour {}.", | ||||
|     "xWasNotUpdatedToY": "Échec de la mise à jour de {} vers {}.", | ||||
|     "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", | ||||
|     "appsRemoved": "Applications supprimées", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Prise en charge des URL APK fixes", | ||||
|     "selectX": "Sélectionner {}", | ||||
|     "parallelDownloads": "Autoriser les téléchargements parallèles", | ||||
|     "installMethod": "Méthode d'installation", | ||||
|     "normal": "Normale", | ||||
|     "root": "Racine", | ||||
|     "useShizuku": "Utiliser Shizuku ou Sui pour l'installation", | ||||
|     "shizukuBinderNotFound": "Service Shizuku compatible non trouvé", | ||||
|     "shizukuOld": "Ancienne version de Shizuku (<11) - la mettre à jour", | ||||
|     "shizukuOldAndroidWithADB": "Shizuku fonctionne sur Android < 8.1 avec ADB - mettre à jour Android ou utiliser Sui à la place", | ||||
|     "shizukuPretendToBeGooglePlay": "Définir Google Play comme source d'installation (si Shizuku est utilisé)", | ||||
|     "useSystemFont": "Utiliser la police du système", | ||||
|     "systemFontError": "Erreur de chargement de 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", | ||||
|     "requestHeader": "En-tête de demande", | ||||
|     "useLatestAssetDateAsReleaseDate": "Utiliser le dernier élément téléversé comme date de sortie", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "L'APK n'a pas pu être analysé (téléchargement incompatible ou partiel)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)", | ||||
|     "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": { | ||||
|         "one": "Supprimer l'application ?", | ||||
|         "other": "Supprimer les applications ?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} et 1 autre application 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": { | ||||
|         "une": "{} et 1 application supplémentaire ont peut-être été mises à jour.", | ||||
|         "other": "{} et {} autres applications peuvent avoir été mises à jour." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Kötelező)", | ||||
|     "dropdownNoOptsError": "HIBA: A LEDOBÁST LEGALÁBB EGY OPCIÓHOZ KELL RENDELNI", | ||||
|     "colour": "Szín", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Custom", | ||||
|     "useMaterialYou": "Használja az Ön által használt anyagot", | ||||
|     "githubStarredRepos": "GitHub Csillagos Repo-k", | ||||
|     "uname": "Felh.név", | ||||
|     "wrongArgNum": "Rossz számú argumentumot adott meg", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Sötét", | ||||
|     "light": "Világos", | ||||
|     "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", | ||||
|     "appSortBy": "App rendezés...", | ||||
|     "authorName": "Szerző/Név", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Nincsenek új frissítések.", | ||||
|     "xHasAnUpdate": "A(z) {} frissítést kapott.", | ||||
|     "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", | ||||
|     "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", | ||||
|     "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", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Támogatja a rögzített APK URL-eket", | ||||
|     "selectX": "Kiválaszt {}", | ||||
|     "parallelDownloads": "Párhuzamos letöltéseket enged", | ||||
|     "installMethod": "Telepítési mód", | ||||
|     "normal": "Normál", | ||||
|     "root": "Root", | ||||
|     "useShizuku": "Használja Shizuku vagy Sui telepítéséhez", | ||||
|     "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", | ||||
|     "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", | ||||
|     "requestHeader": "Kérelem fejléc", | ||||
|     "useLatestAssetDateAsReleaseDate": "Használja a legújabb tartalomfeltöltést megjelenési dátumként", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "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ő)", | ||||
|     "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": { | ||||
|         "one": "Eltávolítja az alkalmazást?", | ||||
|         "other": "Eltávolítja az alkalmazásokat?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "A(z) {} és 1 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": { | ||||
|         "one": "{} és 1 további alkalmazás is frissült.", | ||||
|         "other": "{} és {} további alkalmazás is frissült." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(richiesto)", | ||||
|     "dropdownNoOptsError": "ERRORE: LA TENDINA DEVE AVERE ALMENO UN'OPZIONE", | ||||
|     "colour": "Colore", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Personalizzato", | ||||
|     "useMaterialYou": "Utilizzate il materiale che avete a disposizione", | ||||
|     "githubStarredRepos": "repository stellati da GitHub", | ||||
|     "uname": "Nome utente", | ||||
|     "wrongArgNum": "Numero di argomenti forniti errato", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Scuro", | ||||
|     "light": "Chiaro", | ||||
|     "followSystem": "Segui il sistema", | ||||
|     "followSystemThemeExplanation": "È possibile seguire il tema di sistema solo utilizzando applicazioni di terze parti.", | ||||
|     "useBlackTheme": "Usa il tema nero puro", | ||||
|     "appSortBy": "App ordinate per", | ||||
|     "authorName": "Autore/Nome", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Nessun nuovo aggiornamento.", | ||||
|     "xHasAnUpdate": "Aggiornamento disponibile per {}", | ||||
|     "appsUpdated": "App aggiornate", | ||||
|     "appsNotUpdated": "Impossibile aggiornare le applicazioni", | ||||
|     "appsUpdatedNotifDescription": "Notifica all'utente che una o più app sono state aggiornate in secondo piano", | ||||
|     "xWasUpdatedToY": "{} è stato aggiornato alla {}.", | ||||
|     "xWasNotUpdatedToY": "Impossibile aggiornare {} a {}.", | ||||
|     "errorCheckingUpdates": "Controllo degli errori per gli aggiornamenti", | ||||
|     "errorCheckingUpdatesNotifDescription": "Una notifica che mostra quando il controllo degli aggiornamenti in secondo piano fallisce", | ||||
|     "appsRemoved": "App rimosse", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Supporta URL fissi di APK", | ||||
|     "selectX": "Seleziona {}", | ||||
|     "parallelDownloads": "Permetti download paralleli", | ||||
|     "installMethod": "Metodo d'installazione", | ||||
|     "normal": "Normale", | ||||
|     "root": "Root", | ||||
|     "useShizuku": "Utilizzare Shizuku o Sui per installare", | ||||
|     "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", | ||||
|     "systemFontError": "Errore durante il caricamento dei caratteri di sistema: {}", | ||||
|     "useVersionCodeAsOSVersion": "Usa il codice versione dell'app come versione rilevata dal sistema operativo", | ||||
|     "requestHeader": "Intestazione della richiesta", | ||||
|     "useLatestAssetDateAsReleaseDate": "Usa l'ultimo caricamento della risorsa come data di rilascio", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "Non è stato possibile analizzare l'APK (download incompatibile o parziale).", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Condividere le nuove applicazioni con AppVerifier (se disponibile)", | ||||
|     "appVerifierInstructionToast": "Condividete con AppVerifier, quindi tornate qui quando siete pronti.", | ||||
|     "wiki": "Aiuto/Wiki", | ||||
|     "crowdsourcedConfigsLabel": "Configurazioni di app in crowdsourcing (uso a proprio rischio)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Rimuovere l'app?", | ||||
|         "other": "Rimuovere le app?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} e un'altra 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": { | ||||
|         "one": "{} e un'altra app potrebbero essere state aggiornate.", | ||||
|         "other": "{} e altre {} app potrebbero essere state aggiornate." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(必須)", | ||||
|     "dropdownNoOptsError": "エラー: ドロップダウンには、少なくとも1つのオプションが必要です", | ||||
|     "colour": "カラー", | ||||
|     "standard": "スタンダード", | ||||
|     "custom": "カスタム", | ||||
|     "useMaterialYou": "Material Youを使用する", | ||||
|     "githubStarredRepos": "Githubでスターしたリポジトリ", | ||||
|     "uname": "ユーザー名", | ||||
|     "wrongArgNum": "提供する引数の数が間違っています", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "ダーク", | ||||
|     "light": "ライト", | ||||
|     "followSystem": "システムに従う", | ||||
|     "followSystemThemeExplanation": "以下のシステムテーマは、サードパーティのアプリケーションを使用することによってのみ可能です。", | ||||
|     "useBlackTheme": "ピュアブラックダークテーマを使用する", | ||||
|     "appSortBy": "アプリの並び方", | ||||
|     "authorName": "作者名/アプリ名", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "新しいアップデートはありません", | ||||
|     "xHasAnUpdate": "{} のアップデートが利用可能です。", | ||||
|     "appsUpdated": "アプリをアップデートしました", | ||||
|     "appsNotUpdated": "アプリケーションの更新に失敗", | ||||
|     "appsUpdatedNotifDescription": "1つまたは複数のAppのアップデートがバックグラウンドで適用されたことをユーザーに通知する", | ||||
|     "xWasUpdatedToY": "{} が {} にアップデートされました", | ||||
|     "xWasNotUpdatedToY": "への更新に失敗しました。", | ||||
|     "errorCheckingUpdates": "アップデート確認中のエラー", | ||||
|     "errorCheckingUpdatesNotifDescription": "バックグラウンドでのアップデート確認に失敗した際に表示される通知", | ||||
|     "appsRemoved": "削除されたアプリ", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "固定されたAPKのURLをサポートする", | ||||
|     "selectX": "{} 選択", | ||||
|     "parallelDownloads": "並行ダウンロードを許可する", | ||||
|     "installMethod": "インストール方法", | ||||
|     "normal": "通常", | ||||
|     "root": "Root", | ||||
|     "useShizuku": "ShizukuまたはSuiを使用してインストールする", | ||||
|     "shizukuBinderNotFound": "Shizukuが起動していません", | ||||
|     "shizukuOld": "古いShizukuのバージョン (<11) - アップデートしてください", | ||||
|     "shizukuOldAndroidWithADB": "ShizukuがAndroid 8.1未満でADBを使用して動作しています - Androidをアップデートするか、代わりにSuiを使用してください", | ||||
|     "shizukuPretendToBeGooglePlay": "Google Playをインストール元として設定する(Shizukuを使用する場合)", | ||||
|     "useSystemFont": "システムフォントを使用する", | ||||
|     "systemFontError": "システムフォントの読み込みエラー: {}", | ||||
|     "useVersionCodeAsOSVersion": "アプリのバージョンコードをOSで検出されたバージョンとして使用する", | ||||
|     "requestHeader": "リクエストヘッダー", | ||||
|     "useLatestAssetDateAsReleaseDate": "最新のアセットアップロードをリリース日として使用する", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "APK を解析できませんでした(互換性がないか、部分的にダウンロードされています)。", | ||||
|     "beforeNewInstallsShareToAppVerifier": "AppVerifierで新しいアプリを共有する(利用可能な場合)", | ||||
|     "appVerifierInstructionToast": "AppVerifierに共有し、準備ができたらここに戻ってください。", | ||||
|     "wiki": "ヘルプ/ウィキ", | ||||
|     "crowdsourcedConfigsLabel": "クラウドソーシングによるアプリの設定(利用は自己責任で)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "アプリを削除しますか?", | ||||
|         "other": "アプリを削除しますか?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} とさらに {} 個のアプリがアップデートされました。", | ||||
|         "other": "{} とさらに {} 個のアプリがアップデートされました。" | ||||
|     }, | ||||
|     "xAndNMoreUpdatesFailed": { | ||||
|         "one": "更新に失敗しました。", | ||||
|         "other": "アプリのアップデートに失敗しました。" | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。", | ||||
|         "other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。" | ||||
|   | ||||
| @@ -1,131 +1,135 @@ | ||||
| { | ||||
|     "invalidURLForSource": "Geen valide {} app URL", | ||||
|     "noReleaseFound": "Kan geen geschikte release vinden", | ||||
|     "noVersionFound": "Kan de versie niet bepalen", | ||||
|     "invalidURLForSource": "Ongeldige app-URL voor {}", | ||||
|     "noReleaseFound": "Geen geschikte release gevonden", | ||||
|     "noVersionFound": "Geen versie kunnen bepalen", | ||||
|     "urlMatchesNoSource": "URL komt niet overeen met bekende bron", | ||||
|     "cantInstallOlderVersion": "Kan geen oudere versie van de app installeren", | ||||
|     "appIdMismatch": "Gedownloade pakket-ID komt niet overeen met de bestaande app-ID", | ||||
|     "functionNotImplemented": "Deze class heeft deze functie niet geïmplementeerd.", | ||||
|     "placeholder": "Plaatshouder", | ||||
|     "appIdMismatch": "Gedownload pakket-ID komt niet overeen met de bestaande app-ID", | ||||
|     "functionNotImplemented": "Deze klasse heeft deze functie niet geïmplementeerd.", | ||||
|     "placeholder": "Dummy", | ||||
|     "someErrors": "Er zijn enkele fouten opgetreden", | ||||
|     "unexpectedError": "Onverwachte fout", | ||||
|     "ok": "Ok", | ||||
|     "ok": "Oké", | ||||
|     "and": "en", | ||||
|     "githubPATLabel": "GitHub Personal Access Token\n(Verhoogt limiet aantal verzoeken)", | ||||
|     "includePrereleases": "Bevat prereleases", | ||||
|     "includePrereleases": "Inclusief pre-releases", | ||||
|     "fallbackToOlderReleases": "Terugvallen op oudere releases", | ||||
|     "filterReleaseTitlesByRegEx": "Filter release-titels met reguliere expressies.", | ||||
|     "filterReleaseTitlesByRegEx": "Release-titels filteren met reguliere expressies.", | ||||
|     "invalidRegEx": "Ongeldige reguliere expressie", | ||||
|     "noDescription": "Geen omschrijving", | ||||
|     "cancel": "Annuleer", | ||||
|     "continue": "Ga verder", | ||||
|     "cancel": "Annuleren", | ||||
|     "continue": "Doorgaan", | ||||
|     "requiredInBrackets": "(Verplicht)", | ||||
|     "dropdownNoOptsError": "FOUTMELDING: DROPDOWN MOET TENMINSTE ÉÉN OPT HEBBEN", | ||||
|     "dropdownNoOptsError": "FOUTMELDING: UITKLAPMENU MOET TENMINSTE EEN OPT HEBBEN", | ||||
|     "colour": "Kleur", | ||||
|     "standard": "Standaard", | ||||
|     "custom": "Aangepast", | ||||
|     "useMaterialYou": "Material You gebruiken", | ||||
|     "githubStarredRepos": "GitHub-repo's met ster", | ||||
|     "uname": "Gebruikersnaam", | ||||
|     "wrongArgNum": "Onjuist aantal argumenten verstrekt.", | ||||
|     "xIsTrackOnly": "{} is alleen tracken", | ||||
|     "wrongArgNum": "Incorrect aantal argumenten.", | ||||
|     "xIsTrackOnly": "{} is 'Alleen volgen'", | ||||
|     "source": "Bron", | ||||
|     "app": "App", | ||||
|     "appsFromSourceAreTrackOnly": "Apps van deze bron zijn 'Track-Only'.", | ||||
|     "youPickedTrackOnly": "Je hebt de 'Track-Only' optie geselecteerd.", | ||||
|     "appsFromSourceAreTrackOnly": "Apps van deze bron zijn 'Alleen volgen'.", | ||||
|     "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.", | ||||
|     "cancelled": "Geannuleerd", | ||||
|     "appAlreadyAdded": "App al toegevoegd", | ||||
|     "alreadyUpToDateQuestion": "Is de app al up-to-date?", | ||||
|     "appAlreadyAdded": "App reeds toegevoegd", | ||||
|     "alreadyUpToDateQuestion": "App al bijgewerkt?", | ||||
|     "addApp": "App toevoegen", | ||||
|     "appSourceURL": "App bron URL", | ||||
|     "appSourceURL": "App-bron URL", | ||||
|     "error": "Foutmelding", | ||||
|     "add": "Toevoegen", | ||||
|     "searchSomeSourcesLabel": "Zoeken (Alleen sommige bronnen)", | ||||
|     "searchSomeSourcesLabel": "Zoeken (sommige bronnen)", | ||||
|     "search": "Zoeken", | ||||
|     "additionalOptsFor": "Aanvullende opties voor {}", | ||||
|     "supportedSources": "Ondersteunde bronnen", | ||||
|     "trackOnlyInBrackets": "(Alleen track)", | ||||
|     "trackOnlyInBrackets": "(Alleen volgen)", | ||||
|     "searchableInBrackets": "(Doorzoekbaar)", | ||||
|     "appsString": "Apps", | ||||
|     "noApps": "Geen Apps", | ||||
|     "noAppsForFilter": "Geen Apps voor filter", | ||||
|     "byX": "Door {}", | ||||
|     "percentProgress": "Vooruitgang: {}%", | ||||
|     "percentProgress": "Voortgang: {}%", | ||||
|     "pleaseWait": "Even geduld", | ||||
|     "updateAvailable": "Update beschikbaar", | ||||
|     "notInstalled": "Niet geinstalleerd", | ||||
|     "pseudoVersion": "pseudo-versie", | ||||
|     "selectAll": "Selecteer alles", | ||||
|     "deselectX": "Deselecteer {}", | ||||
|     "xWillBeRemovedButRemainInstalled": "{} zal worden verwijderd uit Obtainium, maar blijft geïnstalleerd op het apparaat.", | ||||
|     "removeSelectedAppsQuestion": "Geselecteerde apps verwijderen??", | ||||
|     "selectAll": "Alles selecteren", | ||||
|     "deselectX": "Selectie opheffen {}", | ||||
|     "xWillBeRemovedButRemainInstalled": "{} zal worden gewist uit Obtainium, maar blijft geïnstalleerd op het apparaat.", | ||||
|     "removeSelectedAppsQuestion": "Geselecteerde apps verwijderen?", | ||||
|     "removeSelectedApps": "Geselecteerde apps verwijderen", | ||||
|     "updateX": "Update {}", | ||||
|     "installX": "Installeer {}", | ||||
|     "markXTrackOnlyAsUpdated": "Markeer {}\n(Track-Only)\nals up-to-date", | ||||
|     "changeX": "Verander {}", | ||||
|     "installUpdateApps": "Installeer/Update apps", | ||||
|     "installUpdateSelectedApps": "Installeer/Update geselecteerde apps", | ||||
|     "markXSelectedAppsAsUpdated": "{} geselecteerde apps markeren als up-to-date?", | ||||
|     "updateX": "{} bijwerken", | ||||
|     "installX": "{} installeren", | ||||
|     "markXTrackOnlyAsUpdated": "{}\n(Alleen volgen)\nmarkeren als bijgewerkt", | ||||
|     "changeX": "{} wijzigen", | ||||
|     "installUpdateApps": "Apps installeren/bijwerken", | ||||
|     "installUpdateSelectedApps": "Geselecteerde apps installeren/bijwerken", | ||||
|     "markXSelectedAppsAsUpdated": "{} geselecteerde apps markeren als bijgewerkt?", | ||||
|     "no": "Nee", | ||||
|     "yes": "Ja", | ||||
|     "markSelectedAppsUpdated": "Markeer geselecteerde aps als up-to-date", | ||||
|     "pinToTop": "Vastzetten aan de bovenkant", | ||||
|     "unpinFromTop": "Losmaken van de bovenkant", | ||||
|     "resetInstallStatusForSelectedAppsQuestion": "Installatiestatus resetten 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.", | ||||
|     "customLinkMessage": "Deze links werken op apparaten waarop Obtainium is geïnstalleerd", | ||||
|     "markSelectedAppsUpdated": "Geselecteerde apps markeren als bijgewerkt", | ||||
|     "pinToTop": "Bovenaan plaatsen", | ||||
|     "unpinFromTop": "Bovenaan wegnemen", | ||||
|     "resetInstallStatusForSelectedAppsQuestion": "Installatiestatus herstellen voor geselecteerde apps?", | ||||
|     "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 koppelingen werken op apparaten waarop Obtainium is geïnstalleerd", | ||||
|     "shareAppConfigLinks": "App-configuratie delen als HTML-link", | ||||
|     "shareSelectedAppURLs": "Deel geselecteerde app URL's", | ||||
|     "resetInstallStatus": "Reset installatiestatus", | ||||
|     "shareSelectedAppURLs": "Geselecteerde app-URL's delen", | ||||
|     "resetInstallStatus": "Installatiestatus herstellen", | ||||
|     "more": "Meer", | ||||
|     "removeOutdatedFilter": "Verwijder out-of-date app filter", | ||||
|     "showOutdatedOnly": "Toon alleen out-of-date apps", | ||||
|     "filter": "Filter", | ||||
|     "filterApps": "Filter apps", | ||||
|     "appName": "App naam", | ||||
|     "removeOutdatedFilter": "Verouderde apps-filter verwijderen", | ||||
|     "showOutdatedOnly": "Alleen verouderde apps weergeven", | ||||
|     "filter": "Filteren", | ||||
|     "filterApps": "Apps filteren", | ||||
|     "appName": "App-naam", | ||||
|     "author": "Auteur", | ||||
|     "upToDateApps": "Up-to-date apps", | ||||
|     "upToDateApps": "Bijgewerkte apps", | ||||
|     "nonInstalledApps": "Niet-geïnstalleerde apps", | ||||
|     "importExport": "Importeren/Exporteren", | ||||
|     "importExport": "Importeren/exporteren", | ||||
|     "settings": "Instellingen", | ||||
|     "exportedTo": "Geëxporteerd naar {}", | ||||
|     "obtainiumExport": "Obtainium export", | ||||
|     "invalidInput": "Ongeldige invoer", | ||||
|     "importedX": "Geïmporteerd {}", | ||||
|     "importedX": "{} geïmporteerd", | ||||
|     "obtainiumImport": "Obtainium import", | ||||
|     "importFromURLList": "Importeer van URL-lijsten", | ||||
|     "importFromURLList": "Importeren van URL-lijsten", | ||||
|     "searchQuery": "Zoekopdracht", | ||||
|     "appURLList": "App URL-lijst", | ||||
|     "line": "Lijn", | ||||
|     "searchX": "Zoek {}", | ||||
|     "line": "Regel", | ||||
|     "searchX": "{} zoeken", | ||||
|     "noResults": "Geen resultaten gevonden", | ||||
|     "importX": "Importeer {}", | ||||
|     "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.", | ||||
|     "importErrors": "Import foutmeldingen", | ||||
|     "importX": "{} importeren", | ||||
|     "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": "Fouten bij het importeren", | ||||
|     "importedXOfYApps": "{} van {} apps geïmporteerd.", | ||||
|     "followingURLsHadErrors": "De volgende URL's bevatten fouten:", | ||||
|     "selectURL": "Selecteer URL", | ||||
|     "selectURLs": "Selecteer URL's", | ||||
|     "pick": "Kies", | ||||
|     "selectURL": "URL selecteren", | ||||
|     "selectURLs": "URL's selecteren", | ||||
|     "pick": "Kiezen", | ||||
|     "theme": "Thema", | ||||
|     "dark": "Donker", | ||||
|     "light": "Licht", | ||||
|     "followSystem": "Volg systeem", | ||||
|     "useBlackTheme": "Gebruik zwart thema", | ||||
|     "appSortBy": "App sorteren op", | ||||
|     "followSystem": "Systeem volgen", | ||||
|     "followSystemThemeExplanation": "Het volgen van het systeemthema is alleen mogelijk met applicaties van derden", | ||||
|     "useBlackTheme": "Zwart thema gebruiken", | ||||
|     "appSortBy": "Sortering", | ||||
|     "authorName": "Auteur/Naam", | ||||
|     "nameAuthor": "Naam/Auteur", | ||||
|     "asAdded": "Zoals toegevoegd", | ||||
|     "appSortOrder": "App sorteervolgorde", | ||||
|     "asAdded": "Datum toegevoegd", | ||||
|     "appSortOrder": "Volgorde", | ||||
|     "ascending": "Oplopend", | ||||
|     "descending": "Aflopend", | ||||
|     "bgUpdateCheckInterval": "Frequentie voor achtergrondupdatecontrole", | ||||
|     "bgUpdateCheckInterval": "Frequentie voor achtergrond-updatecontrole", | ||||
|     "neverManualOnly": "Nooit - Alleen handmatig", | ||||
|     "appearance": "Weergave", | ||||
|     "showWebInAppView": "Toon de bronwebpagina in app-weergave", | ||||
|     "pinUpdates": "Updates bovenaan in de apps-weergave vastpinnen", | ||||
|     "showWebInAppView": "Bron-webpagina weergeven in app-weergave", | ||||
|     "pinUpdates": "Updates bovenaan plaatsen in de apps-weergave", | ||||
|     "updates": "Updates", | ||||
|     "sourceSpecific": "Bron-specifiek", | ||||
|     "appSource": "App bron", | ||||
|     "appSource": "App-bron", | ||||
|     "noLogs": "Geen logs", | ||||
|     "appLogs": "App logs", | ||||
|     "close": "Sluiten", | ||||
| @@ -133,30 +137,32 @@ | ||||
|     "appNotFound": "App niet gevonden", | ||||
|     "obtainiumExportHyphenatedLowercase": "obtainium-export", | ||||
|     "pickAnAPK": "Kies een APK", | ||||
|     "appHasMoreThanOnePackage": "{} heeft meer dan één package:", | ||||
|     "deviceSupportsXArch": "Jouw apparaat support de {} CPU-architectuur.", | ||||
|     "deviceSupportsFollowingArchs": "Je apparaat ondersteunt de volgende CPU-architecturen:", | ||||
|     "appHasMoreThanOnePackage": "{} biedt verschillende pakketten:", | ||||
|     "deviceSupportsXArch": "Dit apparaat ondersteunt de {} CPU-architectuur.", | ||||
|     "deviceSupportsFollowingArchs": "Dit apparaat ondersteunt de volgende CPU-architecturen:", | ||||
|     "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", | ||||
|     "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.", | ||||
|     "xHasAnUpdate": "{} heeft een update.", | ||||
|     "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.", | ||||
|     "xWasUpdatedToY": "{} is bijgewerkt naar {}.", | ||||
|     "xWasNotUpdatedToY": "Het bijwerken van {} naar {} is mislukt.", | ||||
|     "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", | ||||
|     "appsRemovedNotifDescription": "Stelt de gebruiker op de hoogte dat één of meer apps zijn verwijderd vanwege fouten tijdens het laden ervan", | ||||
|     "xWasRemovedDueToErrorY": "{} is verwijderd vanwege deze foutmelding: {}", | ||||
|     "completeAppInstallation": "Complete app installatie", | ||||
|     "appsRemovedNotifDescription": "Stelt de gebruiker op de hoogte dat een of meer apps zijn verwijderd vanwege fouten tijdens het laden", | ||||
|     "xWasRemovedDueToErrorY": "{} is verwijderd vanwege de fout: {}", | ||||
|     "completeAppInstallation": "App-installatie voltooien", | ||||
|     "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", | ||||
|     "checkingForUpdates": "Controleren op updates", | ||||
|     "checkingForUpdatesNotifDescription": "Tijdelijke melding die verschijnt tijdens het controleren op updates", | ||||
|     "pleaseAllowInstallPerm": "Sta Obtainium toe om apps te installeren", | ||||
|     "trackOnly": "Alleen track", | ||||
|     "pleaseAllowInstallPerm": "Toestaan dat Obtainium apps installeert", | ||||
|     "trackOnly": "'Alleen volgen'", | ||||
|     "errorWithHttpStatusCode": "Foutmelding {}", | ||||
|     "versionCorrectionDisabled": "Versiecorrectie uitgeschakeld (de plug-in lijkt niet te werken)", | ||||
|     "unknown": "Onbekend", | ||||
| @@ -166,25 +172,25 @@ | ||||
|     "installedVersionX": "Geïnstalleerde versie: {}", | ||||
|     "lastUpdateCheckX": "Laatste updatecontrole: {}", | ||||
|     "remove": "Verwijderen", | ||||
|     "yesMarkUpdated": "Ja, markeer als bijgewerkt", | ||||
|     "fdroid": "F-Droid-ambtenaar", | ||||
|     "appIdOrName": "App ID of naam", | ||||
|     "yesMarkUpdated": "Ja, markeren als bijgewerkt", | ||||
|     "fdroid": "F-Droid (Officieel)", | ||||
|     "appIdOrName": "App-ID of naam", | ||||
|     "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", | ||||
|     "fdroidThirdPartyRepo": "F-Droid Repository van derden", | ||||
|     "steamMobile": "Stoommobiel", | ||||
|     "steamChat": "Steamchat", | ||||
|     "fdroidThirdPartyRepo": "F-Droid Repository voor derden", | ||||
|     "steamMobile": "Steam Mobile", | ||||
|     "steamChat": "Steam Chat", | ||||
|     "install": "Installeren", | ||||
|     "markInstalled": "Als geïnstalleerd markere", | ||||
|     "update": "Update", | ||||
|     "markUpdated": "Markeren als bijgewerkt", | ||||
|     "markInstalled": "Als geïnstalleerd markeren", | ||||
|     "update": "Bijwerken", | ||||
|     "markUpdated": "Als bijgewerkt markeren", | ||||
|     "additionalOptions": "Aanvullende opties", | ||||
|     "disableVersionDetection": "Versieherkenning uitschakelen", | ||||
|     "noVersionDetectionExplanation": "Deze optie moet alleen worden gebruikt voor apps waar versieherkenning niet correct werkt.", | ||||
|     "downloadingX": "Downloaden {}", | ||||
|     "downloadingX": "{} downloaden", | ||||
|     "downloadX": "Downloaden", | ||||
|     "downloadedX": "Gedownload {}", | ||||
|     "downloadedX": "{} gedownload", | ||||
|     "releaseAsset": "Release Activa", | ||||
|     "downloadNotifDescription": "Stelt de gebruiker op de hoogte van de voortgang bij het downloaden van een app", | ||||
|     "noAPKFound": "Geen APK gevonden", | ||||
| @@ -197,100 +203,100 @@ | ||||
|     "deleteCategoriesQuestion": "Categorieën verwijderen?", | ||||
|     "categoryDeleteWarning": "Alle apps in verwijderde categorieën worden teruggezet naar 'ongecategoriseerd'.", | ||||
|     "addCategory": "Categorie toevoegen", | ||||
|     "label": "Etiket", | ||||
|     "label": "Label", | ||||
|     "language": "Taal", | ||||
|     "copiedToClipboard": "Gekopieerd naar klembord", | ||||
|     "storagePermissionDenied": "Toegang tot opslag geweigerd", | ||||
|     "selectedCategorizeWarning": "Dit zal eventuele bestaande categorie-instellingen voor de geselecteerde apps vervangen.", | ||||
|     "filterAPKsByRegEx": "Filter APK's op reguliere expressie", | ||||
|     "removeFromObtainium": "Verwijder van Obtainium", | ||||
|     "uninstallFromDevice": "Verwijder van apparaat", | ||||
|     "filterAPKsByRegEx": "APK's flteren met reguliere expressie", | ||||
|     "removeFromObtainium": "Uit Obtainium verwijderen", | ||||
|     "uninstallFromDevice": "Van apparaat verwijderen", | ||||
|     "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.", | ||||
|     "changes": "Veranderingen", | ||||
|     "changes": "Aanpassingen", | ||||
|     "releaseDate": "Releasedatum", | ||||
|     "importFromURLsInFile": "Importeren vanaf URL's in een bestand (zoals OPML)", | ||||
|     "versionDetectionExplanation": "Versiereeks afstemmen met versie gedetecteerd door besturingssysteem", | ||||
|     "versionDetection": "Versieherkenning", | ||||
|     "standardVersionDetection": "Standaard versieherkenning", | ||||
|     "groupByCategory": "Groepeer op categorie", | ||||
|     "autoApkFilterByArch": "Poging om APK's te filteren op CPU-architectuur indien mogelijk", | ||||
|     "groupByCategory": "Groeperen op categorie", | ||||
|     "autoApkFilterByArch": "Probeer APK's te filteren op CPU-architectuur, indien mogelijk", | ||||
|     "overrideSource": "Bron overschrijven", | ||||
|     "dontShowAgain": "Laat dit niet meer zien", | ||||
|     "dontShowTrackOnlyWarnings": "Geen waarschuwingen voor 'Track-Only' weergeven", | ||||
|     "dontShowAPKOriginWarnings": "APK-herkomstwaarschuwingen niet weergeven", | ||||
|     "moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave", | ||||
|     "dontShowTrackOnlyWarnings": "Geen waarschuwingen weergeven voor 'Alleen volgen'", | ||||
|     "dontShowAPKOriginWarnings": "Geen waarschuwingen weergeven voor APK-herkomst", | ||||
|     "moveNonInstalledAppsToBottom": "Niet-geïnstalleerde apps onderaan de apps-lijst plaatsen", | ||||
|     "gitlabPATLabel": "GitLab persoonlijk toegangskenmerk", | ||||
|     "about": "Over", | ||||
|     "requiresCredentialsInSettings": "{}: Dit vereist aanvullende referenties (in Instellingen)", | ||||
|     "checkOnStart": "Controleren op updates bij opstarten", | ||||
|     "requiresCredentialsInSettings": "{} vereist aanvullende referenties (in Instellingen)", | ||||
|     "checkOnStart": "Bij opstarten op updates controleren", | ||||
|     "tryInferAppIdFromCode": "Probeer de app-ID af te leiden uit de broncode", | ||||
|     "removeOnExternalUninstall": "Automatisch extern verwijderde apps verwijderen", | ||||
|     "pickHighestVersionCode": "Automatisch de APK met de hoogste versiecode selecteren", | ||||
|     "removeOnExternalUninstall": "Extern verwijderde apps automatisch verwijderen", | ||||
|     "pickHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren", | ||||
|     "checkUpdateOnDetailPage": "Controleren op updates bij het openen van een app-detailpagina", | ||||
|     "disablePageTransitions": "Schakel overgangsanimaties tussen pagina's uit", | ||||
|     "reversePageTransitions": "Omgekeerde overgangsanimaties tussen pagina's", | ||||
|     "minStarCount": "Minimale Github Stars", | ||||
|     "addInfoBelow": "Voeg deze informatie hieronder toe.", | ||||
|     "addInfoInSettings": "Voeg deze informatie toe in de instellingen.", | ||||
|     "disablePageTransitions": "Overgangsanimaties tussen pagina's uitschakelen", | ||||
|     "reversePageTransitions": "Overgangsanimaties tussen pagina's herstellen", | ||||
|     "minStarCount": "Minimum Github Stars", | ||||
|     "addInfoBelow": "Deze informatie hieronder toevoegen.", | ||||
|     "addInfoInSettings": "Deze informatie toevoegen in de instellingen.", | ||||
|     "githubSourceNote": "Beperkingen van GitHub kunnen worden vermeden door het gebruik van een API-sleutel.", | ||||
|     "sortByLastLinkSegment": "Sorteren op alleen het laatste segment van de link", | ||||
|     "filterReleaseNotesByRegEx": "Filter release-opmerkingen met een reguliere expressie.", | ||||
|     "customLinkFilterRegex": "Aangepaste APK-linkfilter met een reguliere expressie (Standaard '.apk$').", | ||||
|     "appsPossiblyUpdated": "Poging tot app-updates", | ||||
|     "sortByLastLinkSegment": "Alleen sorteren op het laatste segment van de link", | ||||
|     "filterReleaseNotesByRegEx": "Release-opmerkingen fiteren met een reguliere expressie.", | ||||
|     "customLinkFilterRegex": "Aangepaste APK-links filteren met een reguliere expressie (Standaard '.apk$').", | ||||
|     "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", | ||||
|     "xWasPossiblyUpdatedToY": "{} mogelijk bijgewerkt naar {}.", | ||||
|     "enableBackgroundUpdates": "Achtergrondupdates inschakelen", | ||||
|     "backgroundUpdateReqsExplanation": "Achtergrondupdates zijn mogelijk niet voor alle apps mogelijk.", | ||||
|     "xWasPossiblyUpdatedToY": "{} kan bijgewerkt zijn naar {}.", | ||||
|     "enableBackgroundUpdates": "Achtergrond-updates inschakelen", | ||||
|     "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.", | ||||
|     "verifyLatestTag": "Verifieer de 'Laatste'-tag", | ||||
|     "intermediateLinkRegex": "Filter voor een 'Intermediaire' link om te bezoeken", | ||||
|     "verifyLatestTag": "Het label 'Laatste' verifiëren", | ||||
|     "intermediateLinkRegex": "Filteren op een 'Intermediaire' link om te bezoeken", | ||||
|     "filterByLinkText": "Links filteren op linktekst", | ||||
|     "intermediateLinkNotFound": "Tussenliggende link niet gevonden", | ||||
|     "intermediateLinkNotFound": "Intermediaire link niet gevonden", | ||||
|     "intermediateLink": "Intermediaire link", | ||||
|     "exemptFromBackgroundUpdates": "Vrijgesteld van achtergrondupdates (indien ingeschakeld)", | ||||
|     "bgUpdatesOnWiFiOnly": "Achtergrondupdates uitschakelen wanneer niet verbonden met WiFi", | ||||
|     "autoSelectHighestVersionCode": "Automatisch de APK met de hoogste versiecode selecteren", | ||||
|     "exemptFromBackgroundUpdates": "Vrijgesteld van achtergrond-updates (indien ingeschakeld)", | ||||
|     "bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met WiFi", | ||||
|     "autoSelectHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren", | ||||
|     "versionExtractionRegEx": "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", | ||||
|     "autoExportOnChanges": "Automatisch exporteren bij wijzigingen", | ||||
|     "autoExportOnChanges": "Bij wijzigingen automatisch exporteren", | ||||
|     "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", | ||||
|     "dontSortReleasesList": "Volgorde van releases behouden vanuit de API", | ||||
|     "reverseSort": "Sortering omkeren", | ||||
|     "reverseSort": "Omgekeerde sortering", | ||||
|     "takeFirstLink": "Neem de eerste link", | ||||
|     "skipSort": "Sorteren overslaan", | ||||
|     "debugMenu": "Debug menu", | ||||
|     "skipSort": "Sortering overslaan", | ||||
|     "debugMenu": "Debug-menu", | ||||
|     "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", | ||||
|     "installing": "Installeren", | ||||
|     "skipUpdateNotifications": "Updatemeldingen overslaan", | ||||
|     "updatesAvailableNotifChannel": "Updates beschikbaar", | ||||
|     "appsUpdatedNotifChannel": "Apps bijgewerkt", | ||||
|     "appsPossiblyUpdatedNotifChannel": "Poging tot app-updates", | ||||
|     "appsPossiblyUpdatedNotifChannel": "Pogingen tot app-updates", | ||||
|     "errorCheckingUpdatesNotifChannel": "Foutcontrole bij het zoeken naar updates", | ||||
|     "appsRemovedNotifChannel": "Apps verwijderd", | ||||
|     "downloadingXNotifChannel": "{} downloaden", | ||||
|     "completeAppInstallationNotifChannel": "Voltooien van de app-installatie", | ||||
|     "completeAppInstallationNotifChannel": "App-installatie voltooien", | ||||
|     "checkingForUpdatesNotifChannel": "Controleren op updates", | ||||
|     "onlyCheckInstalledOrTrackOnlyApps": "Alleen geïnstalleerde en Track-Only apps controleren op updates", | ||||
|     "supportFixedAPKURL": "Ondersteuning vaste APK URL's", | ||||
|     "selectX": "Selecteer {}", | ||||
|     "onlyCheckInstalledOrTrackOnlyApps": "Alleen geïnstalleerde apps en 'Alleen volgen' controleren op updates", | ||||
|     "supportFixedAPKURL": "Vaste APK-URL's ondersteunen", | ||||
|     "selectX": "{} selecteren", | ||||
|     "parallelDownloads": "Parallelle downloads toestaan", | ||||
|     "installMethod": "Installatiemethode", | ||||
|     "normal": "Normaal", | ||||
|     "root": "Wortel", | ||||
|     "shizukuBinderNotFound": "Shizuku draait niet", | ||||
|     "useSystemFont": "Gebruik het systeemlettertype", | ||||
|     "systemFontError": "Fout bij het laden van het systeemlettertype: {}", | ||||
|     "useVersionCodeAsOSVersion": "Gebruik app versieCode als door OS gedetecteerde versie", | ||||
|     "useShizuku": "Shizuku of Sui gebruiken om te installeren", | ||||
|     "shizukuBinderNotFound": "Shizuku is niet actief", | ||||
|     "shizukuOld": "Verouderde Shizuku-versie (<11) - bijwerken", | ||||
|     "shizukuOldAndroidWithADB": "Shizuku draait op Android < 8.1 met ADB - update Android of gebruik in plaats daarvan Sui", | ||||
|     "shizukuPretendToBeGooglePlay": "Google Play instellen als installatiebron (bij Shizuku)", | ||||
|     "useSystemFont": "Systeemlettertype gebruiken", | ||||
|     "useVersionCodeAsOSVersion": "App versiecode gebruiken als door OS gedetecteerde versie", | ||||
|     "requestHeader": "Verzoekkoptekst", | ||||
|     "useLatestAssetDateAsReleaseDate": "Gebruik laatste upload als releasedatum", | ||||
|     "useLatestAssetDateAsReleaseDate": "Laatste upload als releasedatum gebruiken", | ||||
|     "defaultPseudoVersioningMethod": "Standaard pseudo-versiebeheermethode", | ||||
|     "partialAPKHash": "Gedeeltelijke APK-hash", | ||||
|     "APKLinkHash": "APK-link-hash", | ||||
| @@ -303,22 +309,24 @@ | ||||
|     "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)", | ||||
|     "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": { | ||||
|         "one": "App verwijderen?", | ||||
|         "other": "Apps verwijderen?" | ||||
|     }, | ||||
|     "tooManyRequestsTryAgainInMinutes": { | ||||
|         "one": "Te veel verzoeken (aantal beperkt) - probeer het opnieuw in {} minuut", | ||||
|         "other": "Te veel verzoeken (aantal beperkt) - probeer het opnieuw in {} minuten" | ||||
|         "one": "Te veel verzoeken (aantal beperkt) - opnieuw proberen over {} minuut", | ||||
|         "other": "Te veel verzoeken (aantal beperkt) - opnieuw proberen over {} minuten" | ||||
|     }, | ||||
|     "bgUpdateGotErrorRetryInMinutes": { | ||||
|         "one": "Achtergrondupdatecontrole heeft een {}, zal een hercontrole plannen over {} minuut", | ||||
|         "other": "Achtergrondupdatecontrole heeft een {}, zal een hercontrole plannen over {} minuten" | ||||
|         "one": "Achtergrond-updatecontrole heeft een {}, zal een nieuwe controle plannen over {} minuut", | ||||
|         "other": "Achtergrond-updatecontrole heeft een {}, zal een nieuwe controle plannen over {} minuten" | ||||
|     }, | ||||
|     "bgCheckFoundUpdatesWillNotifyIfNeeded": { | ||||
|         "one": "Achtergrondupdatecontrole 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" | ||||
|         "one": "Achtergrond-updatecontrole heeft {} update 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": { | ||||
|         "one": "{} app", | ||||
| @@ -346,15 +354,19 @@ | ||||
|     }, | ||||
|     "xAndNMoreUpdatesAvailable": { | ||||
|         "one": "{} en nog 1 app hebben updates.", | ||||
|         "other": "{} en {} meer apps hebben updates." | ||||
|         "other": "{} en nog {} apps hebben updates." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesInstalled": { | ||||
|         "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": { | ||||
|         "one": "{} en nog 1 app zijn mogelijk bijgewerkt.", | ||||
|         "other": "{} en {} meer apps zijn mogelijk bijgwerkt." | ||||
|         "other": "{} en nog {} apps zijn mogelijk bijgwerkt." | ||||
|     }, | ||||
|     "apk": { | ||||
|         "one": "{} APK", | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Wymagane)", | ||||
|     "dropdownNoOptsError": "BŁĄD: LISTA ROZWIJANA MUSI MIEĆ CO NAJMNIEJ JEDNĄ OPCJĘ", | ||||
|     "colour": "Kolor", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Niestandardowe", | ||||
|     "useMaterialYou": "Używaj materiałów", | ||||
|     "githubStarredRepos": "Repozytoria GitHub oznaczone gwiazdką", | ||||
|     "uname": "Nazwa użytkownika", | ||||
|     "wrongArgNum": "Nieprawidłowa liczba podanych argumentów", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Ciemny", | ||||
|     "light": "Jasny", | ||||
|     "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", | ||||
|     "appSortBy": "Sortuj aplikacje według", | ||||
|     "authorName": "Autor/Nazwa", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Brak nowych aktualizacji.", | ||||
|     "xHasAnUpdate": "{} ma aktualizację.", | ||||
|     "appsUpdated": "Zaktualizowano aplikacje", | ||||
|     "appsNotUpdated": "Nie udało się zaktualizować aplikacji", | ||||
|     "appsUpdatedNotifDescription": "Informuje, gdy co najmniej jedna aplikacja została zaktualizowana w tle", | ||||
|     "xWasUpdatedToY": "{} zaktualizowano do {}.", | ||||
|     "xWasNotUpdatedToY": "Nie udało się zaktualizować {} do {}.", | ||||
|     "errorCheckingUpdates": "Błąd sprawdzania aktualizacji", | ||||
|     "errorCheckingUpdatesNotifDescription": "Jest wyświetlane, gdy sprawdzanie aktualizacji w tle nie powiedzie się", | ||||
|     "appsRemoved": "Usunięte aplikacje", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Obsługuj stałe adresy URL APK", | ||||
|     "selectX": "Wybierz {}", | ||||
|     "parallelDownloads": "Zezwól na pobieranie równoległe", | ||||
|     "installMethod": "Metoda instalacji", | ||||
|     "normal": "Normalna", | ||||
|     "root": "Źródło", | ||||
|     "useShizuku": "Użyj Shizuku lub Sui, aby zainstalować", | ||||
|     "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", | ||||
|     "systemFontError": "Błąd podczas ładowania czcionki systemowej: {}", | ||||
|     "useVersionCodeAsOSVersion": "Użyj kodu wersji aplikacji jako wersji wykrytej przez system operacyjny", | ||||
|     "requestHeader": "Nagłówek żądania", | ||||
|     "useLatestAssetDateAsReleaseDate": "Użyj najnowszego przesłanego zasobu jako daty wydania", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "Nie można przeanalizować pliku APK (niekompatybilny lub częściowo pobrany).", | ||||
|     "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.", | ||||
|     "wiki": "Pomoc/Wiki", | ||||
|     "crowdsourcedConfigsLabel": "Konfiguracje aplikacji pochodzące z crowdsourcingu (korzystanie na własne ryzyko)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Usunąć aplikację?", | ||||
|         "few": "Usunąć aplikacje?", | ||||
| @@ -376,6 +384,10 @@ | ||||
|         "many": "{} i {} innych apek zostało zaktualizowanych.", | ||||
|         "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": { | ||||
|         "one": "{} i 1 inna apka mogły zostać zaktualizowane.", | ||||
|         "few": "{} i {} inne apki mogły zostać zaktualizowane.", | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Necessário)", | ||||
|     "dropdownNoOptsError": "ERRO: O DROPDOWN DEVE TER PELO MENOS UMA OPÇÃO", | ||||
|     "colour": "Cor", | ||||
|     "standard": "Padrão", | ||||
|     "custom": "Personalizado", | ||||
|     "useMaterialYou": "Utilizar o material que", | ||||
|     "githubStarredRepos": "repositórios favoritos no GitHub", | ||||
|     "uname": "Nome de usuário", | ||||
|     "wrongArgNum": "Número de argumentos errado", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Escuro", | ||||
|     "light": "Claro", | ||||
|     "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", | ||||
|     "appSortBy": "Classificar aplicativo por", | ||||
|     "authorName": "Autor/Nome", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Sem novas atualizações.", | ||||
|     "xHasAnUpdate": "{} tem uma atualização.", | ||||
|     "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 ", | ||||
|     "xWasUpdatedToY": "{} foi atualizado para {}.", | ||||
|     "xWasNotUpdatedToY": "Falha ao atualizar {} para {}.", | ||||
|     "errorCheckingUpdates": "Erro ao procurar por atualizações", | ||||
|     "errorCheckingUpdatesNotifDescription": "Uma notificação que mostra quando a checagem por atualizações em segundo-plano falha", | ||||
|     "appsRemoved": "Aplicativos removidos", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Suporte a APK com URLs fixas", | ||||
|     "selectX": "Selecionar {}", | ||||
|     "parallelDownloads": "Permitir downloads paralelos", | ||||
|     "installMethod": "Método de instalação", | ||||
|     "normal": "Normal", | ||||
|     "root": "Root", | ||||
|     "useShizuku": "Utilizar Shizuku ou Sui para instalar", | ||||
|     "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", | ||||
|     "systemFontError": "Erro ao carregar a fonte do sistema: {}", | ||||
|     "useVersionCodeAsOSVersion": "Usar versionCode do aplicativo como versão detectada pelo sistema operacional", | ||||
|     "requestHeader": "Requisitar cabeçalho", | ||||
|     "useLatestAssetDateAsReleaseDate": "Use o último upload de recursos como data de lançamento", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "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)", | ||||
|     "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": { | ||||
|         "one": "Remover aplicativo?", | ||||
|         "other": "Remover aplicativos?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} e um outro aplicativo foram atualizado.", | ||||
|         "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": { | ||||
|         "one": "{} e um outro aplicativo podem ter sido atualizados.", | ||||
|         "other": "{} e {} outros aplicativos podem ter sido atualizados." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(обязательно)", | ||||
|     "dropdownNoOptsError": "Ошибка: в выпадающем списке должна быть выбрана хотя бы одна настройка", | ||||
|     "colour": "Цвет", | ||||
|     "standard": "Стандартный", | ||||
|     "custom": "Индивидуальный", | ||||
|     "useMaterialYou": "Использовать Material You", | ||||
|     "githubStarredRepos": "Избранные репозитории GitHub", | ||||
|     "uname": "Имя пользователя", | ||||
|     "wrongArgNum": "Неправильное количество предоставленных аргументов", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Тёмная", | ||||
|     "light": "Светлая", | ||||
|     "followSystem": "Системная", | ||||
|     "followSystemThemeExplanation": "Следование системной теме возможно только при использовании сторонних приложений", | ||||
|     "useBlackTheme": "Использовать чёрную тему", | ||||
|     "appSortBy": "Сортировка приложений", | ||||
|     "authorName": "Автор/Название", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Нет новых обновлений", | ||||
|     "xHasAnUpdate": "{} есть обновление", | ||||
|     "appsUpdated": "Приложения обновлены", | ||||
|     "appsNotUpdated": "Не удалось обновить приложения", | ||||
|     "appsUpdatedNotifDescription": "Уведомляет об обновлении одного или нескольких приложений в фоновом режиме", | ||||
|     "xWasUpdatedToY": "{} была обновлена до версии {}", | ||||
|     "xWasNotUpdatedToY": "Не удалось обновить {} до версии {}", | ||||
|     "errorCheckingUpdates": "Ошибка при проверке обновлений", | ||||
|     "errorCheckingUpdatesNotifDescription": "Уведомление о завершении проверки обновлений в фоновом режиме с ошибкой", | ||||
|     "appsRemoved": "Приложение удалено", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Поддержка фиксированных URL-адресов APK", | ||||
|     "selectX": "Выбрать {}", | ||||
|     "parallelDownloads": "Разрешить параллельные загрузки", | ||||
|     "installMethod": "Метод установки", | ||||
|     "normal": "Нормальный", | ||||
|     "root": "Суперпользователь", | ||||
|     "shizukuBinderNotFound": "Совместимый сервис Shizuku не найден", | ||||
|     "useShizuku": "Использовать Shizuku или Sui для установки", | ||||
|     "shizukuBinderNotFound": "Совместимый сервис Shizuku не найден, возможно он не запущен", | ||||
|     "shizukuOld": "Устаревшая версия Shizuku (<11), обновите", | ||||
|     "shizukuOldAndroidWithADB": "Shizuku работает на Android < 8.1 с ADB, обновите Android или используйте Sui", | ||||
|     "shizukuPretendToBeGooglePlay": "Указать Google Play как источник установки (если используется Shizuku)", | ||||
|     "useSystemFont": "Использовать системный шрифт", | ||||
|     "systemFontError": "Ошибка загрузки системного шрифта: {}", | ||||
|     "useVersionCodeAsOSVersion": "Использовать код версии приложения как версию, обнаруженную ОС", | ||||
|     "requestHeader": "Заголовок запроса", | ||||
|     "useLatestAssetDateAsReleaseDate": "Использовать последнюю загрузку ресурса в качестве даты выпуска", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "APK не удалось разобрать (несовместимая или неполная загрузка)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Поделитесь новыми приложениями с AppVerifier (если доступно)", | ||||
|     "appVerifierInstructionToast": "Поделитесь с AppVerifier, а затем вернитесь сюда, когда будете готовы.", | ||||
|     "wiki": "Помощь/Вики", | ||||
|     "crowdsourcedConfigsLabel": "Конфигурации приложений на основе краудсорсинга (используйте на свой страх и риск)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Удалить приложение?", | ||||
|         "other": "Удалить приложения?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} и ещё 1 приложение были обновлены", | ||||
|         "other": "{} и ещё {} приложений были обновлены" | ||||
|     }, | ||||
|     "xAndNMoreUpdatesFailed": { | ||||
|         "one": "Не удалось обновить {} и ещё 1 приложение", | ||||
|         "other": "Не удалось обновить {} и ещё {} приложений" | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "one": "{} и ещё 1 приложение могли быть обновлены", | ||||
|         "other": "{} и ещё {} приложений могли быть обновлены" | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Kräver)", | ||||
|     "dropdownNoOptsError": "FEL: DROPDOWN MÅSTE HA MINST ETT OPT", | ||||
|     "colour": "Färg", | ||||
|     "standard": "Standard", | ||||
|     "custom": "Anpassad", | ||||
|     "useMaterialYou": "Använd material Du", | ||||
|     "githubStarredRepos": "GitHub Stjärnmärkta Förråd", | ||||
|     "uname": "Användarnamn", | ||||
|     "wrongArgNum": "Fel antal argument har angetts", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Mörkt", | ||||
|     "light": "Ljust", | ||||
|     "followSystem": "Följ System", | ||||
|     "followSystemThemeExplanation": "Följande systemtema är endast möjligt med hjälp av tredjepartsapplikationer", | ||||
|     "useBlackTheme": "Använd svart tema", | ||||
|     "appSortBy": "Sortera Appar via", | ||||
|     "authorName": "Utvecklare/Namn", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Inga nya uppdateringar.", | ||||
|     "xHasAnUpdate": "{} har en uppdatering.", | ||||
|     "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", | ||||
|     "xWasUpdatedToY": "{} uppdaterades till {}.", | ||||
|     "xWasNotUpdatedToY": "Det gick inte att uppdatera {} till {}.", | ||||
|     "errorCheckingUpdates": "Fel vid uppdateringskoll", | ||||
|     "errorCheckingUpdatesNotifDescription": "En aviserings som visar när bakgrundsuppdateringarkollar misslyckas", | ||||
|     "appsRemoved": "Appar borttagna", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Stöd fasta APK-webbadresser", | ||||
|     "selectX": "Välj {}", | ||||
|     "parallelDownloads": "Tillåt parallella nedladdningar", | ||||
|     "installMethod": "Installationsmetod", | ||||
|     "normal": "Vanligt", | ||||
|     "root": "Rot", | ||||
|     "useShizuku": "Använd Shizuku eller Sui för att installera", | ||||
|     "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", | ||||
|     "systemFontError": "Fel vid laddning av systemteckensnittet: {}", | ||||
|     "useVersionCodeAsOSVersion": "Använd appversionskoden som OS-upptäckt version", | ||||
|     "requestHeader": "Rubrik för begäran", | ||||
|     "useLatestAssetDateAsReleaseDate": "Använd senaste tillgångsuppladdning som releasedatum", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "APK kunde inte analyseras (inkompatibel eller partiell nedladdning)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Dela nya appar med AppVerifier (om tillgängligt)", | ||||
|     "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": { | ||||
|         "one": "Ta Bort App?", | ||||
|         "other": "Ta Bort Appar?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} och 1 till app 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": { | ||||
|         "one": "{} och 1 till app kan ha uppdaterats.", | ||||
|         "other": "{} och {} appar till kan ha uppdaterats." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Gerekli)", | ||||
|     "dropdownNoOptsError": "HATA: DİPLOMADA EN AZ BİR SEÇENEK OLMALI", | ||||
|     "colour": "Renk", | ||||
|     "standard": "Standart", | ||||
|     "custom": "Özel", | ||||
|     "useMaterialYou": "Sizin Malzemenizi Kullanın", | ||||
|     "githubStarredRepos": "GitHub'a Yıldızlı Depolar", | ||||
|     "uname": "Kullanıcı Adı", | ||||
|     "wrongArgNum": "Hatalı argüman sayısı sağlandı", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Koyu", | ||||
|     "light": "Aydınlık", | ||||
|     "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", | ||||
|     "appSortBy": "Uygulama Sıralama Ölçütü", | ||||
|     "authorName": "Yazar/Ad", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Yeni güncelleme yok.", | ||||
|     "xHasAnUpdate": "{} güncelleme alıyor.", | ||||
|     "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", | ||||
|     "xWasUpdatedToY": "{} şu sürüme güncellendi: {}.", | ||||
|     "xWasNotUpdatedToY": "{} öğesi {} olarak güncellenemedi.", | ||||
|     "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", | ||||
|     "appsRemoved": "Uygulamalar Kaldırıldı", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Sabit APK URL'lerini destekleyin", | ||||
|     "selectX": "Seçme {}", | ||||
|     "parallelDownloads": "Paralel indirmelere izin ver", | ||||
|     "installMethod": "Kurulum yöntemi", | ||||
|     "normal": "Normal", | ||||
|     "root": "Kök", | ||||
|     "useShizuku": "Yüklemek için Shizuku veya Sui'yi kullanın", | ||||
|     "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", | ||||
|     "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", | ||||
|     "requestHeader": "Başlık talep et", | ||||
|     "useLatestAssetDateAsReleaseDate": "Yayın tarihi olarak en son öğe yüklemesini kullan", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "APK ayrıştırılamadı (uyumsuz veya kısmi indirme)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Yeni Uygulamaları AppVerifier ile paylaşın (varsa)", | ||||
|     "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": { | ||||
|         "one": "Uygulamayı Kaldır?", | ||||
|         "other": "Uygulamaları Kaldır?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} ve 1 diğer 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": { | ||||
|         "one": "{} ve 1 diğer uygulama muhtemelen güncellendi.", | ||||
|         "other": "{} ve {} daha fazla uygulama muhtemelen güncellendi." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Обов'язково)", | ||||
|     "dropdownNoOptsError": "ПОМИЛКА: В ВИПАДАЮЧОМУ СПИСКУ МАЄ БУТИ ХОЧА Б ОДИН ЕЛЕМЕНТ", | ||||
|     "colour": "Колір", | ||||
|     "standard": "Стандартний", | ||||
|     "custom": "Нестандартний", | ||||
|     "useMaterialYou": "Використовуйте матеріал, який ви", | ||||
|     "githubStarredRepos": "Відзначені репозиторії GitHub", | ||||
|     "uname": "Ім'я користувача", | ||||
|     "wrongArgNum": "Надано неправильну кількість аргументів", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Темна", | ||||
|     "light": "Світла", | ||||
|     "followSystem": "Дотримуватися системи", | ||||
|     "followSystemThemeExplanation": "Зміна теми системи можлива лише за допомогою сторонніх додатків", | ||||
|     "useBlackTheme": "Використовувати чорну тему (Amoled)", | ||||
|     "appSortBy": "Сортувати застосунки за", | ||||
|     "authorName": "Автор/Назва", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Немає нових оновлень.", | ||||
|     "xHasAnUpdate": "{} має оновлення.", | ||||
|     "appsUpdated": "Застосунки оновлено", | ||||
|     "appsNotUpdated": "Не вдалося оновити програми", | ||||
|     "appsUpdatedNotifDescription": "Повідомляє користувача, що оновлення одного чи декількох застосунків було застосовано в фоновому режимі", | ||||
|     "xWasUpdatedToY": "{} було оновлено до {}.", | ||||
|     "xWasNotUpdatedToY": "Не вдалося оновити {} на {}.", | ||||
|     "errorCheckingUpdates": "Помилка перевірки оновлень", | ||||
|     "errorCheckingUpdatesNotifDescription": "Повідомлення, яке з'являється, коли перевірка оновлень в фоновому режимі завершується невдачею", | ||||
|     "appsRemoved": "Застосунки видалено", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Підтримка фіксованих посилань на APK", | ||||
|     "selectX": "Вибрати {}", | ||||
|     "parallelDownloads": "Дозволити паралельні завантаження", | ||||
|     "installMethod": "Метод встановлення", | ||||
|     "normal": "Звичайний", | ||||
|     "root": "Root", | ||||
|     "useShizuku": "Використовуйте Shizuku або Sui для встановлення", | ||||
|     "shizukuBinderNotFound": "Сумісний сервіс Shizuku не було знайдено", | ||||
|     "shizukuOld": "Стара версія Shizuku (<11) - оновіть її", | ||||
|     "shizukuOldAndroidWithADB": "Shizuku працює на Android < 8.1 з ADB - оновіть Android або використовуйте Sui замість нього", | ||||
|     "shizukuPretendToBeGooglePlay": "Виберіть Google Play як джерело встановлення (якщо використовується Shizuku)", | ||||
|     "useSystemFont": "Використовувати системний шрифт", | ||||
|     "systemFontError": "Помилка завантаження системного шрифту: {}", | ||||
|     "useVersionCodeAsOSVersion": "Використовувати код версії застосунку як версію, визначену операційною системою", | ||||
|     "requestHeader": "Заголовок запиту", | ||||
|     "useLatestAssetDateAsReleaseDate": "Використовувати останню дату завантаження ресурсу як дату випуску", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "badDownload": "APK не вдалося розпарсити (несумісний або часткове завантаження)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "Діліться новими додатками з AppVerifier (якщо доступно)", | ||||
|     "appVerifierInstructionToast": "Надішліть на AppVerifier, а потім поверніться сюди, коли будете готові.", | ||||
|     "wiki": "Довідка/Вікі", | ||||
|     "crowdsourcedConfigsLabel": "Краудсорсингові конфігурації додатків (використовуйте на свій страх і ризик)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Видалити застосунок?", | ||||
|         "other": "Видалити застосунки?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} та ще 1 застосунок було оновлено.", | ||||
|         "other": "{} та ще {} застосунків було оновлено." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesFailed": { | ||||
|         "one": "Не вдалося оновити {} та ще 1 програму.", | ||||
|         "other": "Не вдалося оновити {} і {} та інші програми." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "one": "{} та ще 1 застосунок можливо було оновлено.", | ||||
|         "other": "{} та ще {} застосунків можливо було оновлено." | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(Yêu cầu)", | ||||
|     "dropdownNoOptsError": "LỖI: TẢI XUỐNG PHẢI CÓ ÍT NHẤT MỘT LỰA CHỌN", | ||||
|     "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", | ||||
|     "uname": "Tên người dùng", | ||||
|     "wrongArgNum": "Số lượng đối số được cung cấp sai", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "Tối", | ||||
|     "light": "Sáng", | ||||
|     "followSystem": "Theo hệ thống", | ||||
|     "followSystemThemeExplanation": "Following system theme is possible only by using third-party applications", | ||||
|     "useBlackTheme": "Nền đen", | ||||
|     "appSortBy": "Sắp xếp ứng dụng", | ||||
|     "authorName": "Tác giả", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "Không có bản cập nhật mới.", | ||||
|     "xHasAnUpdate": "{} có bản 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", | ||||
|     "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", | ||||
|     "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ỏ", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "Hỗ trợ URL APK cố định", | ||||
|     "selectX": "Lựa chọn {}", | ||||
|     "parallelDownloads": "Cho phép tải đa luồng", | ||||
|     "installMethod": "Phương thức cài đặt", | ||||
|     "normal": "Mặc định", | ||||
|     "root": "Root", | ||||
|     "useShizuku": "Use Shizuku or Sui to install", | ||||
|     "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", | ||||
|     "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", | ||||
|     "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", | ||||
| @@ -304,6 +310,8 @@ | ||||
|     "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": "Chia sẻ ứng dụng mới với AppVerifier (nếu có)", | ||||
|     "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": { | ||||
|         "one": "Gỡ ứng dụng?", | ||||
|         "other": "Gỡ ứng dụng?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "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." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesFailed": { | ||||
|         "one": "Failed to update {} and 1 more app.", | ||||
|         "other": "Failed to update {} and {} more apps." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "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." | ||||
|   | ||||
| @@ -13,8 +13,8 @@ | ||||
|     "and": "和", | ||||
|     "githubPATLabel": "GitHub 个人访问令牌(提升 API 请求限额)", | ||||
|     "includePrereleases": "包含预发行版", | ||||
|     "fallbackToOlderReleases": "将旧发行版作为备选", | ||||
|     "filterReleaseTitlesByRegEx": "筛选发行标题(正则表达式)", | ||||
|     "fallbackToOlderReleases": "将过往的发行版作为备选", | ||||
|     "filterReleaseTitlesByRegEx": "筛选发行标题的正则表达式", | ||||
|     "invalidRegEx": "无效的正则表达式", | ||||
|     "noDescription": "无描述", | ||||
|     "cancel": "取消", | ||||
| @@ -22,6 +22,9 @@ | ||||
|     "requiredInBrackets": "(必填)", | ||||
|     "dropdownNoOptsError": "错误:下拉菜单必须包含至少一个选项", | ||||
|     "colour": "配色", | ||||
|     "standard": "标准", | ||||
|     "custom": "定制", | ||||
|     "useMaterialYou": "使用 Material You 配色", | ||||
|     "githubStarredRepos": "已星标的 GitHub 仓库", | ||||
|     "uname": "用户名", | ||||
|     "wrongArgNum": "参数数量错误", | ||||
| @@ -72,8 +75,8 @@ | ||||
|     "unpinFromTop": "取消置顶", | ||||
|     "resetInstallStatusForSelectedAppsQuestion": "是否重置选中应用的安装状态?", | ||||
|     "installStatusOfXWillBeResetExplanation": "选中应用的安装状态将会被重置。\n\n当更新安装失败或其他问题导致 Obtainium 中的应用版本显示错误时,可以尝试通过此方法解决。", | ||||
|     "customLinkMessage": "这些链接适用于安装了 Gettingium 的设备", | ||||
|     "shareAppConfigLinks": "将应用程序配置共享为 HTML 链接", | ||||
|     "customLinkMessage": "分享链接仅适用于已安装 Obtainium 的设备", | ||||
|     "shareAppConfigLinks": "通过链接分享应用配置", | ||||
|     "shareSelectedAppURLs": "分享选中应用的 URL", | ||||
|     "resetInstallStatus": "重置安装状态", | ||||
|     "more": "更多", | ||||
| @@ -110,6 +113,7 @@ | ||||
|     "dark": "深色", | ||||
|     "light": "浅色", | ||||
|     "followSystem": "跟随系统", | ||||
|     "followSystemThemeExplanation": "跟随系统主题仅在使用第三方应用时有效", | ||||
|     "useBlackTheme": "使用纯黑深色主题", | ||||
|     "appSortBy": "排序依据", | ||||
|     "authorName": "作者 / 应用名称", | ||||
| @@ -131,7 +135,7 @@ | ||||
|     "close": "关闭", | ||||
|     "share": "分享", | ||||
|     "appNotFound": "未找到应用", | ||||
|     "obtainiumExportHyphenatedLowercase": "获取出口", | ||||
|     "obtainiumExportHyphenatedLowercase": "obtainium-export", | ||||
|     "pickAnAPK": "选择一个 APK 文件", | ||||
|     "appHasMoreThanOnePackage": "“{}”有多个架构可用:", | ||||
|     "deviceSupportsXArch": "您的设备支持 {} 架构。", | ||||
| @@ -143,8 +147,10 @@ | ||||
|     "noNewUpdates": "全部应用已是最新。", | ||||
|     "xHasAnUpdate": "“{}”可以更新了。", | ||||
|     "appsUpdated": "应用已更新", | ||||
|     "appsNotUpdated": "更新应用程序失败", | ||||
|     "appsUpdatedNotifDescription": "当应用在后台安装更新时发送通知", | ||||
|     "xWasUpdatedToY": "“{}”已更新至 {}。", | ||||
|     "xWasNotUpdatedToY": "未能将 {} 更新为 {}。", | ||||
|     "errorCheckingUpdates": "检查更新出错", | ||||
|     "errorCheckingUpdatesNotifDescription": "当后台检查更新失败时显示的通知", | ||||
|     "appsRemoved": "应用已删除", | ||||
| @@ -173,8 +179,8 @@ | ||||
|     "appWithIdOrNameNotFound": "未找到符合此 ID 或名称的应用", | ||||
|     "reposHaveMultipleApps": "存储库中可能包含多个应用", | ||||
|     "fdroidThirdPartyRepo": "F-Droid 第三方存储库", | ||||
|     "steamMobile": "蒸汽手机", | ||||
|     "steamChat": "蒸汽聊天", | ||||
|     "steamMobile": "Steam Mobile", | ||||
|     "steamChat": "Steam Chat", | ||||
|     "install": "安装", | ||||
|     "markInstalled": "标记为已安装", | ||||
|     "update": "更新", | ||||
| @@ -185,7 +191,7 @@ | ||||
|     "downloadingX": "正在下载“{}”", | ||||
|     "downloadX": "下载 {}", | ||||
|     "downloadedX": "下载 {}", | ||||
|     "releaseAsset": "释放资产", | ||||
|     "releaseAsset": "APK 文件", | ||||
|     "downloadNotifDescription": "提示应用的下载进度", | ||||
|     "noAPKFound": "未找到 APK 文件", | ||||
|     "noVersionDetection": "禁用版本检测", | ||||
| @@ -202,7 +208,7 @@ | ||||
|     "copiedToClipboard": "已复制至剪贴板", | ||||
|     "storagePermissionDenied": "已拒绝授予存储权限", | ||||
|     "selectedCategorizeWarning": "这将覆盖选中应用当前的类别设置。", | ||||
|     "filterAPKsByRegEx": "筛选 APK 文件(正则表达式)", | ||||
|     "filterAPKsByRegEx": "筛选 APK 文件的正则表达式", | ||||
|     "removeFromObtainium": "从 Obtainium 中删除", | ||||
|     "uninstallFromDevice": "从设备中卸载", | ||||
|     "onlyWorksWithNonVersionDetectApps": "仅适用于禁用版本检测的应用。", | ||||
| @@ -236,7 +242,7 @@ | ||||
|     "addInfoInSettings": "在“设置”中添加此凭据。", | ||||
|     "githubSourceNote": "使用访问令牌可避免触发 GitHub 的 API 请求限制。", | ||||
|     "sortByLastLinkSegment": "仅根据链接的末尾部分进行筛选", | ||||
|     "filterReleaseNotesByRegEx": "筛选发行说明(正则表达式)", | ||||
|     "filterReleaseNotesByRegEx": "筛选发行说明的正则表达式", | ||||
|     "customLinkFilterRegex": "筛选自定义来源的 APK 文件链接\n(正则表达式,默认匹配模式为“.apk$”)", | ||||
|     "appsPossiblyUpdated": "已尝试更新应用", | ||||
|     "appsPossiblyUpdatedNotifDescription": "当应用已尝试在后台更新时发送通知", | ||||
| @@ -245,20 +251,20 @@ | ||||
|     "backgroundUpdateReqsExplanation": "后台更新未必适用于所有的应用。", | ||||
|     "backgroundUpdateLimitsExplanation": "只有在启动 Obtainium 时才能确认安装是否成功。", | ||||
|     "verifyLatestTag": "验证“Latest”标签", | ||||
|     "intermediateLinkRegex": "筛选中转链接(正则表达式)", | ||||
|     "intermediateLinkRegex": "筛选中转链接的正则表达式", | ||||
|     "filterByLinkText": "根据链接文本进行筛选", | ||||
|     "intermediateLinkNotFound": "未找到中转链接", | ||||
|     "intermediateLink": "中转链接", | ||||
|     "exemptFromBackgroundUpdates": "禁用后台更新(如果已经全局启用)", | ||||
|     "bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新", | ||||
|     "autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件", | ||||
|     "versionExtractionRegEx": "版本号提取规则(正则表达式)", | ||||
|     "matchGroupToUse": "引用的捕获组", | ||||
|     "versionExtractionRegEx": "提取版本号的正则表达式", | ||||
|     "matchGroupToUse": "从上述匹配结果中引用的捕获组", | ||||
|     "highlightTouchTargets": "突出展示不明显的触摸区域", | ||||
|     "pickExportDir": "选择导出文件夹", | ||||
|     "autoExportOnChanges": "数据变更时自动导出", | ||||
|     "includeSettings": "同时导出应用设置", | ||||
|     "filterVersionsByRegEx": "筛选版本号(正则表达式)", | ||||
|     "filterVersionsByRegEx": "筛选版本号的正则表达式", | ||||
|     "trySelectingSuggestedVersionCode": "尝试选择推荐版本的 APK 文件", | ||||
|     "dontSortReleasesList": "保持来自 API 的发行顺序", | ||||
|     "reverseSort": "反转排序", | ||||
| @@ -282,12 +288,12 @@ | ||||
|     "supportFixedAPKURL": "支持固定的 APK 文件链接", | ||||
|     "selectX": "选择{}", | ||||
|     "parallelDownloads": "启用并行下载", | ||||
|     "installMethod": "安装方式", | ||||
|     "normal": "常规", | ||||
|     "root": "root", | ||||
|     "useShizuku": "使用 Shizuku 或 Sui 安装", | ||||
|     "shizukuBinderNotFound": "未发现兼容的 Shizuku 服务", | ||||
|     "shizukuOld": "Shizuku 版本过低(<11)- 请更新", | ||||
|     "shizukuOldAndroidWithADB": "正在低版本 Android(<8.1)系统中以 ADB 模式运行 Shizuku - 请更新 Android 版本或使用 Sui 代替", | ||||
|     "shizukuPretendToBeGooglePlay": "使用 Shizuku 时,将安装来源伪装为“Google Play”", | ||||
|     "useSystemFont": "使用系统字体", | ||||
|     "systemFontError": "加载系统字体出错:{}", | ||||
|     "useVersionCodeAsOSVersion": "使用内部版本号代替应用定义的版本号", | ||||
|     "requestHeader": "请求标头", | ||||
|     "useLatestAssetDateAsReleaseDate": "使用最近文件上传时间作为发行日期", | ||||
| @@ -302,8 +308,10 @@ | ||||
|     "note": "备注", | ||||
|     "selfHostedNote": "可以通过“{}”下拉菜单来指向任意来源的自托管/自定义实例。", | ||||
|     "badDownload": "无法解析 APK 文件(不兼容或文件不完整)", | ||||
|     "beforeNewInstallsShareToAppVerifier": "与 AppVerifier 共享新应用程序(如有)", | ||||
|     "appVerifierInstructionToast": "分享到 AppVerifier,准备就绪后返回此处。", | ||||
|     "beforeNewInstallsShareToAppVerifier": "通过 AppVerifier 校验新应用(如果可用)", | ||||
|     "appVerifierInstructionToast": "分享至 AppVerifier,完成后返回此处。", | ||||
|     "wiki": "帮助/维基", | ||||
|     "crowdsourcedConfigsLabel": "众包应用程序配置(使用风险自负)", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "是否删除应用?", | ||||
|         "other": "是否删除应用?" | ||||
| @@ -352,6 +360,10 @@ | ||||
|         "one": "{} 和另外 1 个应用已更新。", | ||||
|         "other": "“{}”和另外 {} 个应用已更新。" | ||||
|     }, | ||||
|     "xAndNMoreUpdatesFailed": { | ||||
|         "one": "更新 {} 和另外 1 个应用程序失败。", | ||||
|         "other": "未能更新 {} 和 {} 更多应用程序。" | ||||
|     }, | ||||
|     "xAndNMoreUpdatesPossiblyInstalled": { | ||||
|         "one": "{} 和另外 1 个应用已尝试更新。", | ||||
|         "other": "“{}”和另外 {} 个应用已尝试更新。" | ||||
|   | ||||
| @@ -273,10 +273,11 @@ class GitHub extends AppSource { | ||||
|  | ||||
|       List<MapEntry<String, String>> getReleaseAssetUrls(dynamic release) => | ||||
|           (release['assets'] as List<dynamic>?)?.map((e) { | ||||
|             return (e['name'] != null) && | ||||
|                     ((e['url'] ?? e['browser_download_url']) != null) | ||||
|                 ? MapEntry(e['name'] as String, | ||||
|                     (e['url'] ?? e['browser_download_url']) as String) | ||||
|             var url = !e['name'].toString().toLowerCase().endsWith('.apk') | ||||
|                 ? (e['browser_download_url'] ?? e['url']) | ||||
|                 : (e['url'] ?? e['browser_download_url']); | ||||
|             return (e['name'] != null) && (url != null) | ||||
|                 ? MapEntry(e['name'] as String, url as String) | ||||
|                 : const MapEntry('', ''); | ||||
|           }).toList() ?? | ||||
|           []; | ||||
|   | ||||
| @@ -243,19 +243,28 @@ class HTML extends AppSource { | ||||
|     if ((additionalSettings['customLinkFilterRegex'] as String?)?.isNotEmpty == | ||||
|         true) { | ||||
|       var reg = RegExp(additionalSettings['customLinkFilterRegex']); | ||||
|       links = allLinks | ||||
|           .where((element) => reg.hasMatch( | ||||
|               filterLinkByText ? element.value : Uri.decodeFull(element.key))) | ||||
|           .toList(); | ||||
|       links = allLinks.where((element) { | ||||
|         var link = element.key; | ||||
|         try { | ||||
|           link = Uri.decodeFull(element.key); | ||||
|         } catch (e) { | ||||
|           // Some links may not have valid encoding | ||||
|         } | ||||
|         return reg.hasMatch(filterLinkByText ? element.value : link); | ||||
|       }).toList(); | ||||
|     } else { | ||||
|       links = allLinks | ||||
|           .where((element) => Uri.parse(filterLinkByText | ||||
|                   ? element.value | ||||
|                   : Uri.decodeFull(element.key)) | ||||
|       links = allLinks.where((element) { | ||||
|         var link = element.key; | ||||
|         try { | ||||
|           link = Uri.decodeFull(element.key); | ||||
|         } catch (e) { | ||||
|           // Some links may not have valid encoding | ||||
|         } | ||||
|         return Uri.parse(filterLinkByText ? element.value : link) | ||||
|             .path | ||||
|             .toLowerCase() | ||||
|               .endsWith('.apk')) | ||||
|           .toList(); | ||||
|             .endsWith('.apk'); | ||||
|       }).toList(); | ||||
|     } | ||||
|     if (!skipSort) { | ||||
|       links.sort((a, b) => additionalSettings['sortByLastLinkSegment'] == true | ||||
| @@ -310,13 +319,19 @@ class HTML extends AppSource { | ||||
|       links = [MapEntry(currentUrl, currentUrl)]; | ||||
|     } | ||||
|     var rel = links.last.key; | ||||
|     var relDecoded = rel; | ||||
|     try { | ||||
|       relDecoded = Uri.decodeFull(rel); | ||||
|     } catch (e) { | ||||
|       // Some links may not have valid encoding | ||||
|     } | ||||
|     String? version; | ||||
|     version = extractVersion( | ||||
|         additionalSettings['versionExtractionRegEx'] as String?, | ||||
|         additionalSettings['matchGroupToUse'] as String?, | ||||
|         additionalSettings['versionExtractWholePage'] == true | ||||
|             ? versionExtractionWholePageString | ||||
|             : Uri.decodeFull(rel)); | ||||
|             : relDecoded); | ||||
|     version ??= | ||||
|         additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash' | ||||
|             ? rel.hashCode.toString() | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import 'package:obtainium/providers/source_provider.dart'; | ||||
| class HuaweiAppGallery extends AppSource { | ||||
|   HuaweiAppGallery() { | ||||
|     name = 'Huawei AppGallery'; | ||||
|     hosts = ['appgallery.huawei.com']; | ||||
|     hosts = ['appgallery.huawei.com', 'appgallery.cloud.huawei.com']; | ||||
|     versionDetectionDisallowed = true; | ||||
|     showReleaseDateAsVersionToggle = true; | ||||
|   } | ||||
| @@ -14,7 +14,7 @@ class HuaweiAppGallery extends AppSource { | ||||
|   @override | ||||
|   String sourceSpecificStandardizeURL(String url) { | ||||
|     RegExp standardUrlRegEx = RegExp( | ||||
|         '^https?://(www\\.)?${getSourceRegex(hosts)}/app/[^/]+', | ||||
|         '^https?://(www\\.)?${getSourceRegex(hosts)}(/#)?/(app|appdl)/[^/]+', | ||||
|         caseSensitive: false); | ||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url); | ||||
|     if (match == null) { | ||||
| @@ -24,7 +24,7 @@ class HuaweiAppGallery extends AppSource { | ||||
|   } | ||||
|  | ||||
|   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( | ||||
|       String dlUrl, Map<String, dynamic> additionalSettings) async { | ||||
| @@ -84,7 +84,7 @@ class HuaweiAppGallery extends AppSource { | ||||
|     } | ||||
|     var relDate = relDateStrAdj == 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) { | ||||
|       throw NoVersionError(); | ||||
|     } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; | ||||
| import 'package:obtainium/pages/home.dart'; | ||||
| import 'package:obtainium/providers/apps_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/settings_provider.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
| @@ -118,8 +119,6 @@ void main() async { | ||||
|   BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask); | ||||
| } | ||||
|  | ||||
| var defaultThemeColour = Colors.deepPurple; | ||||
|  | ||||
| class Obtainium extends StatefulWidget { | ||||
|   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 | ||||
|       ColorScheme lightColorScheme; | ||||
|       ColorScheme darkColorScheme; | ||||
|       if (lightDynamic != null && | ||||
|           darkDynamic != null && | ||||
|           settingsProvider.colour == ColourSettings.materialYou) { | ||||
|       if (lightDynamic != null && darkDynamic != null && settingsProvider.useMaterialYou) { | ||||
|         lightColorScheme = lightDynamic.harmonized(); | ||||
|         darkColorScheme = darkDynamic.harmonized(); | ||||
|       } else { | ||||
|         lightColorScheme = ColorScheme.fromSeed(seedColor: defaultThemeColour); | ||||
|         lightColorScheme = ColorScheme.fromSeed(seedColor: settingsProvider.themeColor); | ||||
|         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 | ||||
| @@ -231,6 +228,8 @@ class _ObtainiumState extends State<Obtainium> { | ||||
|             .harmonized(); | ||||
|       } | ||||
|  | ||||
|       if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont(); | ||||
|  | ||||
|       return MaterialApp( | ||||
|           title: 'Obtainium', | ||||
|           localizationsDelegates: context.localizationDelegates, | ||||
|   | ||||
| @@ -133,7 +133,7 @@ class _AppPageState extends State<AppPage> { | ||||
|                         child: Text( | ||||
|                           app?.app.releaseDate == null | ||||
|                               ? tr('changes') | ||||
|                               : app!.app.releaseDate.toString(), | ||||
|                               : app!.app.releaseDate!.toLocal().toString(), | ||||
|                           textAlign: TextAlign.center, | ||||
|                           style: | ||||
|                               Theme.of(context).textTheme.labelSmall!.copyWith( | ||||
| @@ -175,9 +175,8 @@ class _AppPageState extends State<AppPage> { | ||||
|                 tr('downloadX', args: [tr('releaseAsset').toLowerCase()]), | ||||
|                 textAlign: TextAlign.center, | ||||
|                 style: Theme.of(context).textTheme.labelSmall!.copyWith( | ||||
|                       decoration: | ||||
|                           changeLogFn != null ? TextDecoration.underline : null, | ||||
|                       fontStyle: changeLogFn != null ? FontStyle.italic : null, | ||||
|                       decoration: TextDecoration.underline, | ||||
|                       fontStyle: FontStyle.italic, | ||||
|                     ), | ||||
|               ), | ||||
|             ), | ||||
|   | ||||
| @@ -437,7 +437,7 @@ class AppsPageState extends State<AppsPage> { | ||||
|               ? tr('changes') | ||||
|               : '' | ||||
|           : DateFormat('yyyy-MM-dd') | ||||
|               .format(listedApps[appIndex].app.releaseDate!); | ||||
|               .format(listedApps[appIndex].app.releaseDate!.toLocal()); | ||||
|     } | ||||
|  | ||||
|     getSingleAppHorizTile(int index) { | ||||
| @@ -882,11 +882,10 @@ class AppsPageState extends State<AppsPage> { | ||||
|                           onPressed: selectedAppIds.isEmpty | ||||
|                               ? null | ||||
|                               : () { | ||||
|                                   String urls = | ||||
|                                       '<p>${tr('customLinkMessage')}:</p>\n\n<ul>\n'; | ||||
|                                   String urls = ''; | ||||
|                                   for (var a in selectedApps) { | ||||
|                                     urls += | ||||
|                                         '    <li><a href="obtainium://app/${Uri.encodeComponent(jsonEncode({ | ||||
|                                         'https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/${Uri.encodeComponent(jsonEncode({ | ||||
|                                           'id': a.id, | ||||
|                                           'url': a.url, | ||||
|                                           'author': a.author, | ||||
| @@ -895,10 +894,8 @@ class AppsPageState extends State<AppsPage> { | ||||
|                                               a.preferredApkIndex, | ||||
|                                           'additionalSettings': | ||||
|                                               jsonEncode(a.additionalSettings) | ||||
|                                         }))}">${a.name}</a></li>\n'; | ||||
|                                         }))}\n\n'; | ||||
|                                   } | ||||
|                                   urls += | ||||
|                                       '</ul>\n\n<p><a href="$obtainiumUrl">${tr('about')}</a></p>'; | ||||
|                                   Share.share(urls, | ||||
|                                       subject: | ||||
|                                           'Obtainium - ${tr('appsString')}'); | ||||
|   | ||||
| @@ -119,7 +119,7 @@ class _HomePageState extends State<HomePage> { | ||||
|     } | ||||
|  | ||||
|     // Check initial link if app was in cold state (terminated) | ||||
|     final appLink = await _appLinks.getInitialAppLink(); | ||||
|     final appLink = await _appLinks.getInitialLink(); | ||||
|     if (appLink != null) { | ||||
|       await interpretLink(appLink); | ||||
|     } | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| import 'package:device_info_plus/device_info_plus.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:obtainium/components/custom_app_bar.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:provider/provider.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'; | ||||
|  | ||||
| class SettingsPage extends StatefulWidget { | ||||
| @@ -22,78 +25,184 @@ class SettingsPage extends StatefulWidget { | ||||
| } | ||||
|  | ||||
| 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 | ||||
|   Widget build(BuildContext context) { | ||||
|     SettingsProvider settingsProvider = context.watch<SettingsProvider>(); | ||||
|     SourceProvider sourceProvider = SourceProvider(); | ||||
|     if (settingsProvider.prefs == null) { | ||||
|       settingsProvider.initializeSettings(); | ||||
|     if (settingsProvider.prefs == null) 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( | ||||
|         decoration: InputDecoration(labelText: tr('installMethod')), | ||||
|         value: settingsProvider.installMethod, | ||||
|         items: [ | ||||
|           DropdownMenuItem( | ||||
|             value: InstallMethodSettings.normal, | ||||
|             child: Text(tr('normal')), | ||||
|           ), | ||||
|           const DropdownMenuItem( | ||||
|             value: InstallMethodSettings.shizuku, | ||||
|             child: Text('Shizuku'), | ||||
|           ), | ||||
|           DropdownMenuItem( | ||||
|             value: InstallMethodSettings.root, | ||||
|             child: Text(tr('root')), | ||||
|           ) | ||||
|         ], | ||||
|         onChanged: (value) { | ||||
|           if (value != null) { | ||||
|             settingsProvider.installMethod = value; | ||||
|           } | ||||
|     var colorPicker = ListTile( | ||||
|         dense: true, | ||||
|         contentPadding: EdgeInsets.zero, | ||||
|         title: Text(tr('selectX', args: [tr('colour')])), | ||||
|         subtitle: Text( | ||||
|             "${ColorTools.nameThatColor(settingsProvider.themeColor)} " | ||||
|             "(${ColorTools.materialNameAndCode(settingsProvider.themeColor, colorSwatchNameMap: colorsNameMap)})"), | ||||
|         trailing: ColorIndicator( | ||||
|             width: 40, | ||||
|             height: 40, | ||||
|             borderRadius: 20, | ||||
|             color: settingsProvider.themeColor, | ||||
|             onSelectFocus: false, | ||||
|             onSelect: () async { | ||||
|               final Color colorBeforeDialog = settingsProvider.themeColor; | ||||
|               if (!(await colorPickerDialog())) { | ||||
|                 setState(() { | ||||
|                   settingsProvider.themeColor = colorBeforeDialog; | ||||
|                 }); | ||||
|               } | ||||
|             })); | ||||
|  | ||||
|     var themeDropdown = DropdownButtonFormField( | ||||
|         decoration: InputDecoration(labelText: tr('theme')), | ||||
|         value: settingsProvider.theme, | ||||
|         items: [ | ||||
|           DropdownMenuItem( | ||||
|             value: ThemeSettings.dark, | ||||
|             child: Text(tr('dark')), | ||||
|           ), | ||||
|           DropdownMenuItem( | ||||
|             value: ThemeSettings.light, | ||||
|             child: Text(tr('light')), | ||||
|           ), | ||||
|           DropdownMenuItem( | ||||
|             value: ThemeSettings.system, | ||||
|             child: Text(tr('followSystem')), | ||||
|           ) | ||||
|         ], | ||||
|     var useMaterialThemeSwitch = FutureBuilder( | ||||
|         builder: (ctx, val) { | ||||
|           return ((val.data?.version.sdkInt ?? 0) >= 31) | ||||
|               ? Row( | ||||
|                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                   children: [ | ||||
|                     Flexible(child: Text(tr('useMaterialYou'))), | ||||
|                     Switch( | ||||
|                         value: settingsProvider.useMaterialYou, | ||||
|                         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'), | ||||
|           ) | ||||
|                           settingsProvider.useMaterialYou = value; | ||||
|                         }) | ||||
|                   ], | ||||
|         onChanged: (value) { | ||||
|           if (value != null) { | ||||
|             settingsProvider.colour = value; | ||||
|           } | ||||
|         }); | ||||
|                 ) | ||||
|               : const SizedBox.shrink(); | ||||
|         }, | ||||
|         future: DeviceInfoPlugin().androidInfo); | ||||
|  | ||||
|     var sortDropdown = DropdownButtonFormField( | ||||
|         isExpanded: true, | ||||
| @@ -165,30 +274,29 @@ class _SettingsPageState extends State<SettingsPage> { | ||||
|           } | ||||
|         }); | ||||
|  | ||||
|     var intervalDropdown = DropdownButtonFormField( | ||||
|         decoration: InputDecoration(labelText: tr('bgUpdateCheckInterval')), | ||||
|         value: settingsProvider.updateInterval, | ||||
|         items: updateIntervals.map((e) { | ||||
|           int displayNum = (e < 60 | ||||
|                   ? e | ||||
|                   : e < 1440 | ||||
|                       ? e / 60 | ||||
|                       : e / 1440) | ||||
|               .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; | ||||
|           } | ||||
|     var intervalSlider = Slider( | ||||
|       value: settingsProvider.updateIntervalSliderVal, | ||||
|       max: updateIntervalNodes.length.toDouble(), | ||||
|       divisions: updateIntervalNodes.length * 20, | ||||
|       label: updateIntervalLabel, | ||||
|       onChanged: (double value) { | ||||
|         setState(() { | ||||
|           settingsProvider.updateIntervalSliderVal = value; | ||||
|           processIntervalSliderValue(value); | ||||
|         }); | ||||
|       }, | ||||
|       onChangeStart: (double value) { | ||||
|         setState(() { | ||||
|           showIntervalLabel = false; | ||||
|         }); | ||||
|       }, | ||||
|       onChangeEnd: (double value) { | ||||
|         setState(() { | ||||
|           showIntervalLabel = true; | ||||
|           settingsProvider.updateInterval = updateInterval; | ||||
|         }); | ||||
|       }, | ||||
|     ); | ||||
|  | ||||
|     var sourceSpecificFields = sourceProvider.sources.map((e) { | ||||
|       if (e.sourceConfigSettingFormItems.isNotEmpty) { | ||||
| @@ -239,15 +347,26 @@ class _SettingsPageState extends State<SettingsPage> { | ||||
|                                   fontWeight: FontWeight.bold, | ||||
|                                   color: Theme.of(context).colorScheme.primary), | ||||
|                             ), | ||||
|                             intervalDropdown, | ||||
|                             //intervalDropdown, | ||||
|                             height16, | ||||
|                             if (showIntervalLabel) | ||||
|                               SizedBox( | ||||
|                                   child: Text( | ||||
|                                       "${tr('bgUpdateCheckInterval')}: $updateIntervalLabel")) | ||||
|                             else | ||||
|                               const SizedBox(height: 16), | ||||
|                             intervalSlider, | ||||
|                             FutureBuilder( | ||||
|                                 builder: (ctx, val) { | ||||
|                                   return (val.data?.version.sdkInt ?? 0) >= 30 | ||||
|                                   return (settingsProvider.updateInterval > | ||||
|                                               0) && | ||||
|                                           (((val.data?.version.sdkInt ?? 0) >= | ||||
|                                                   30) || | ||||
|                                               settingsProvider.useShizuku) | ||||
|                                       ? Column( | ||||
|                                           crossAxisAlignment: | ||||
|                                               CrossAxisAlignment.start, | ||||
|                                           children: [ | ||||
|                                             height16, | ||||
|                                             Row( | ||||
|                                               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, | ||||
|                             Text( | ||||
|                               tr('sourceSpecific'), | ||||
| @@ -432,21 +592,49 @@ class _SettingsPageState extends State<SettingsPage> { | ||||
|                                   fontWeight: FontWeight.bold, | ||||
|                                   color: Theme.of(context).colorScheme.primary), | ||||
|                             ), | ||||
|                             themeDropdown, | ||||
|                             DropdownButtonFormField( | ||||
|                                 decoration: | ||||
|                                     InputDecoration(labelText: tr('theme')), | ||||
|                                 value: settingsProvider.theme, | ||||
|                                 items: [ | ||||
|                                   DropdownMenuItem( | ||||
|                                     value: ThemeSettings.system, | ||||
|                                     child: Text(tr('followSystem')), | ||||
|                                   ), | ||||
|                                   DropdownMenuItem( | ||||
|                                     value: ThemeSettings.light, | ||||
|                                     child: Text(tr('light')), | ||||
|                                   ), | ||||
|                                   DropdownMenuItem( | ||||
|                                     value: ThemeSettings.dark, | ||||
|                                     child: Text(tr('dark')), | ||||
|                                   ) | ||||
|                                 ], | ||||
|                                 onChanged: (value) { | ||||
|                                   if (value != null) { | ||||
|                                     settingsProvider.theme = value; | ||||
|                                   } | ||||
|                                 }), | ||||
|                             height8, | ||||
|                             if (settingsProvider.theme == ThemeSettings.system) | ||||
|                               followSystemThemeExplanation, | ||||
|                             height16, | ||||
|                             if (settingsProvider.theme != ThemeSettings.light) | ||||
|                               Row( | ||||
|                               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                                   mainAxisAlignment: | ||||
|                                       MainAxisAlignment.spaceBetween, | ||||
|                                   children: [ | ||||
|                                     Flexible(child: Text(tr('useBlackTheme'))), | ||||
|                                     Switch( | ||||
|                                         value: settingsProvider.useBlackTheme, | ||||
|                                         onChanged: (value) { | ||||
|                                       settingsProvider.useBlackTheme = value; | ||||
|                                           settingsProvider.useBlackTheme = | ||||
|                                               value; | ||||
|                                         }) | ||||
|                               ], | ||||
|                             ), | ||||
|                             colourDropdown, | ||||
|                             height16, | ||||
|                                   ]), | ||||
|                             height8, | ||||
|                             useMaterialThemeSwitch, | ||||
|                             if (!settingsProvider.useMaterialYou) colorPicker, | ||||
|                             Row( | ||||
|                               mainAxisAlignment: MainAxisAlignment.start, | ||||
|                               crossAxisAlignment: CrossAxisAlignment.start, | ||||
| @@ -460,34 +648,46 @@ class _SettingsPageState extends State<SettingsPage> { | ||||
|                             ), | ||||
|                             height16, | ||||
|                             localeDropdown, | ||||
|                             FutureBuilder( | ||||
|                                 builder: (ctx, val) { | ||||
|                                   return (val.data?.version.sdkInt ?? 0) >= 34 | ||||
|                                       ? Column( | ||||
|                                           crossAxisAlignment: | ||||
|                                               CrossAxisAlignment.start, | ||||
|                                           children: [ | ||||
|                                               height16, | ||||
|                                               Row( | ||||
|                               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                                                   mainAxisAlignment: | ||||
|                                                       MainAxisAlignment | ||||
|                                                           .spaceBetween, | ||||
|                                                   children: [ | ||||
|                                 Flexible(child: Text(tr('useSystemFont'))), | ||||
|                                                     Flexible( | ||||
|                                                         child: Text(tr( | ||||
|                                                             'useSystemFont'))), | ||||
|                                                     Switch( | ||||
|                                     value: settingsProvider.useSystemFont, | ||||
|                                     onChanged: (useSystemFont) { | ||||
|                                                         value: settingsProvider | ||||
|                                                             .useSystemFont, | ||||
|                                                         onChanged: | ||||
|                                                             (useSystemFont) { | ||||
|                                                           if (useSystemFont) { | ||||
|                                         NativeFeatures.loadSystemFont() | ||||
|                                             .then((fontLoadRes) { | ||||
|                                           if (fontLoadRes == 'ok') { | ||||
|                                             settingsProvider.useSystemFont = | ||||
|                                                             NativeFeatures | ||||
|                                                                     .loadSystemFont() | ||||
|                                                                 .then((val) { | ||||
|                                                               settingsProvider | ||||
|                                                                       .useSystemFont = | ||||
|                                                                   true; | ||||
|                                           } else { | ||||
|                                             showError( | ||||
|                                                 ObtainiumError(tr( | ||||
|                                                     'systemFontError', | ||||
|                                                     args: [fontLoadRes])), | ||||
|                                                 context); | ||||
|                                           } | ||||
|                                                             }); | ||||
|                                                           } else { | ||||
|                                         settingsProvider.useSystemFont = false; | ||||
|                                                             settingsProvider | ||||
|                                                                     .useSystemFont = | ||||
|                                                                 false; | ||||
|                                                           } | ||||
|                                                         }) | ||||
|                               ], | ||||
|                             ), | ||||
|                                                   ]) | ||||
|                                             ]) | ||||
|                                       : const SizedBox.shrink(); | ||||
|                                 }, | ||||
|                                 future: DeviceInfoPlugin().androidInfo), | ||||
|                             height16, | ||||
|                             Row( | ||||
|                               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
| @@ -640,17 +840,31 @@ class _SettingsPageState extends State<SettingsPage> { | ||||
|                 Row( | ||||
|                   mainAxisAlignment: MainAxisAlignment.spaceAround, | ||||
|                   children: [ | ||||
|                     TextButton.icon( | ||||
|                     IconButton( | ||||
|                       onPressed: () { | ||||
|                         launchUrlString(settingsProvider.sourceUrl, | ||||
|                             mode: LaunchMode.externalApplication); | ||||
|                       }, | ||||
|                       icon: const Icon(Icons.code), | ||||
|                       label: Text( | ||||
|                         tr('appSource'), | ||||
|                       tooltip: tr('appSource'), | ||||
|                     ), | ||||
|                     IconButton( | ||||
|                       onPressed: () { | ||||
|                         launchUrlString('${settingsProvider.sourceUrl}/wiki', | ||||
|                             mode: LaunchMode.externalApplication); | ||||
|                       }, | ||||
|                       icon: const Icon(Icons.help_outline_rounded), | ||||
|                       tooltip: tr('wiki'), | ||||
|                     ), | ||||
|                     TextButton.icon( | ||||
|                     IconButton( | ||||
|                       onPressed: () { | ||||
|                         launchUrlString('https://apps.obtainium.imranr.dev/', | ||||
|                             mode: LaunchMode.externalApplication); | ||||
|                       }, | ||||
|                       icon: const Icon(Icons.apps_rounded), | ||||
|                       tooltip: tr('crowdsourcedConfigsLabel'), | ||||
|                     ), | ||||
|                     IconButton( | ||||
|                         onPressed: () { | ||||
|                           context.read<LogsProvider>().get().then((logs) { | ||||
|                             if (logs.isEmpty) { | ||||
| @@ -666,7 +880,7 @@ class _SettingsPageState extends State<SettingsPage> { | ||||
|                           }); | ||||
|                         }, | ||||
|                         icon: const Icon(Icons.bug_report_outlined), | ||||
|                         label: Text(tr('appLogs'))), | ||||
|                         tooltip: tr('appLogs')) | ||||
|                   ], | ||||
|                 ), | ||||
|                 const SizedBox( | ||||
|   | ||||
| @@ -34,7 +34,7 @@ import 'package:android_intent_plus/android_intent.dart'; | ||||
| import 'package:flutter_archive/flutter_archive.dart'; | ||||
| import 'package:share_plus/share_plus.dart'; | ||||
| 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(); | ||||
|  | ||||
| @@ -142,19 +142,20 @@ List<MapEntry<String, int>> moveStrToEndMapEntryWithCount( | ||||
|   return arr; | ||||
| } | ||||
|  | ||||
| Future<File> downloadFileWithRetry( | ||||
|     String url, String fileNameNoExt, Function? onProgress, String destDir, | ||||
| Future<File> downloadFileWithRetry(String url, String fileName, | ||||
|     bool fileNameHasExt, Function? onProgress, String destDir, | ||||
|     {bool useExisting = true, | ||||
|     Map<String, String>? headers, | ||||
|     int retries = 3}) async { | ||||
|   try { | ||||
|     return await downloadFile(url, fileNameNoExt, onProgress, destDir, | ||||
|     return await downloadFile( | ||||
|         url, fileName, fileNameHasExt, onProgress, destDir, | ||||
|         useExisting: useExisting, headers: headers); | ||||
|   } catch (e) { | ||||
|     if (retries > 0 && e is ClientException) { | ||||
|       await Future.delayed(const Duration(seconds: 5)); | ||||
|       return await downloadFileWithRetry( | ||||
|           url, fileNameNoExt, onProgress, destDir, | ||||
|           url, fileName, fileNameHasExt, onProgress, destDir, | ||||
|           useExisting: useExisting, headers: headers, retries: (retries - 1)); | ||||
|     } else { | ||||
|       rethrow; | ||||
| @@ -201,8 +202,8 @@ Future<String> checkPartialDownloadHash(String url, int bytesToGrab, | ||||
|   return hashListOfLists(bytes); | ||||
| } | ||||
|  | ||||
| Future<File> downloadFile( | ||||
|     String url, String fileNameNoExt, Function? onProgress, String destDir, | ||||
| Future<File> downloadFile(String url, String fileName, bool fileNameHasExt, | ||||
|     Function? onProgress, String destDir, | ||||
|     {bool useExisting = true, Map<String, String>? headers}) async { | ||||
|   // Send the initial request but cancel it as soon as you have the headers | ||||
|   var reqHeaders = headers ?? {}; | ||||
| @@ -222,7 +223,12 @@ Future<File> downloadFile( | ||||
|   if (url.toLowerCase().endsWith('.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; | ||||
|   if (resHeaders['accept-ranges']?.isNotEmpty == true) { | ||||
| @@ -435,8 +441,8 @@ class AppsProvider with ChangeNotifier { | ||||
|       var headers = await source.getRequestHeaders(app.additionalSettings, | ||||
|           forAPKDownload: true); | ||||
|       var downloadedFile = await downloadFileWithRetry( | ||||
|           downloadUrl, fileNameNoExt, | ||||
|           headers: headers, (double? progress) { | ||||
|           downloadUrl, fileNameNoExt, false, headers: headers, | ||||
|           (double? progress) { | ||||
|         int? prog = progress?.ceil(); | ||||
|         if (apps[app.id] != null) { | ||||
|           apps[app.id]!.downloadProgress = progress; | ||||
| @@ -507,9 +513,6 @@ class AppsProvider with ChangeNotifier { | ||||
|       .isNotEmpty; | ||||
|  | ||||
|   Future<bool> canInstallSilently(App app) async { | ||||
|     if (app.id == obtainiumId) { | ||||
|       return false; | ||||
|     } | ||||
|     if (!settingsProvider.enableBackgroundUpdates) { | ||||
|       return false; | ||||
|     } | ||||
| @@ -517,8 +520,7 @@ class AppsProvider with ChangeNotifier { | ||||
|       return false; | ||||
|     } | ||||
|     if (app.apkUrls.length > 1) { | ||||
|       // Manual API selection means silent install is not possible | ||||
|       return false; | ||||
|       return false; // Manual API selection means silent install is not possible | ||||
|     } | ||||
|  | ||||
|     var osInfo = await DeviceInfoPlugin().androidInfo; | ||||
| @@ -529,20 +531,30 @@ class AppsProvider with ChangeNotifier { | ||||
|               ?.installingPackageName | ||||
|           : (await pm.getInstallerPackageName(packageName: app.id)); | ||||
|     } catch (e) { | ||||
|       // Probably not installed - ignore | ||||
|     } | ||||
|     if (installerPackageName != obtainiumId) { | ||||
|       // If we did not install the app (or it isn't installed), silent install is not possible | ||||
|       return false; | ||||
|       return false; // App probably not installed | ||||
|     } | ||||
|  | ||||
|     int? targetSDK = | ||||
|         (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 | ||||
|     return osInfo.version.sdkInt >= 31 && | ||||
|         targetSDK != null && | ||||
|         targetSDK >= // https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int) | ||||
|             (osInfo.version.sdkInt - 3); | ||||
|     if (settingsProvider.useShizuku) { | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     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 { | ||||
| @@ -566,7 +578,8 @@ class AppsProvider with ChangeNotifier { | ||||
|  | ||||
|   Future<bool> installXApkDir( | ||||
|       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 | ||||
|     // 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 | ||||
| @@ -581,7 +594,8 @@ class AppsProvider with ChangeNotifier { | ||||
|             somethingInstalled = somethingInstalled || | ||||
|                 await installApk( | ||||
|                     DownloadedApk(dir.appId, file), firstTimeWithContext, | ||||
|                     needsBGWorkaround: needsBGWorkaround); | ||||
|                     needsBGWorkaround: needsBGWorkaround, | ||||
|                     shizukuPretendToBeGooglePlay: shizukuPretendToBeGooglePlay); | ||||
|           } catch (e) { | ||||
|             logs.add( | ||||
|                 'Could not install APK from XAPK \'${file.path}\': ${e.toString()}'); | ||||
| @@ -604,7 +618,8 @@ class AppsProvider with ChangeNotifier { | ||||
|  | ||||
|   Future<bool> installApk( | ||||
|       DownloadedApk file, BuildContext? firstTimeWithContext, | ||||
|       {bool needsBGWorkaround = false}) async { | ||||
|       {bool needsBGWorkaround = false, | ||||
|       bool shizukuPretendToBeGooglePlay = false}) async { | ||||
|     if (firstTimeWithContext != null && | ||||
|         settingsProvider.beforeNewInstallsShareToAppVerifier && | ||||
|         (await getInstalledInfo('dev.soupslurpr.appverifier')) != null) { | ||||
| @@ -632,8 +647,7 @@ class AppsProvider with ChangeNotifier { | ||||
|         !(await canDowngradeApps())) { | ||||
|       throw DowngradeError(); | ||||
|     } | ||||
|     if (needsBGWorkaround && | ||||
|         settingsProvider.installMethod == InstallMethodSettings.normal) { | ||||
|     if (needsBGWorkaround) { | ||||
|       // 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 | ||||
|       // So we update the app's installed version first as we will never get to the later code | ||||
| @@ -645,20 +659,12 @@ class AppsProvider with ChangeNotifier { | ||||
|           attemptToCorrectInstallStatus: false); | ||||
|     } | ||||
|     int? code; | ||||
|     switch (settingsProvider.installMethod) { | ||||
|       case InstallMethodSettings.normal: | ||||
|         code = await AndroidPackageInstaller.installApk( | ||||
|             apkFilePath: file.file.path); | ||||
|       case InstallMethodSettings.shizuku: | ||||
|         code = (await NativeFeatures.installWithShizuku( | ||||
|                 apkFileUri: file.file.uri.toString())) | ||||
|             ? 0 | ||||
|             : 1; | ||||
|       case InstallMethodSettings.root: | ||||
|     if (!settingsProvider.useShizuku) { | ||||
|       code = | ||||
|             (await NativeFeatures.installWithRoot(apkFilePath: file.file.path)) | ||||
|                 ? 0 | ||||
|                 : 1; | ||||
|           await AndroidPackageInstaller.installApk(apkFilePath: file.file.path); | ||||
|     } else { | ||||
|       code = await ShizukuApkInstaller.installAPK(file.file.uri.toString(), | ||||
|           shizukuPretendToBeGooglePlay ? "com.android.vending" : ""); | ||||
|     } | ||||
|     bool installed = false; | ||||
|     if (code != null && code != 0 && code != 3) { | ||||
| @@ -716,8 +722,8 @@ class AppsProvider with ChangeNotifier { | ||||
|     List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis; | ||||
|  | ||||
|     if (urlsToSelectFrom.length > 1 && context != null) { | ||||
|       // ignore: use_build_context_synchronously | ||||
|       appFileUrl = await showDialog( | ||||
|           // ignore: use_build_context_synchronously | ||||
|           context: context, | ||||
|           builder: (BuildContext ctx) { | ||||
|             return AppFilePicker( | ||||
| @@ -737,10 +743,9 @@ class AppsProvider with ChangeNotifier { | ||||
|     if (appFileUrl != null && | ||||
|         getHost(appFileUrl.value) != getHost(app.url) && | ||||
|         context != null) { | ||||
|       // ignore: use_build_context_synchronously | ||||
|       if (!(settingsProvider.hideAPKOriginWarning) && | ||||
|           // ignore: use_build_context_synchronously | ||||
|           await showDialog( | ||||
|                   // ignore: use_build_context_synchronously | ||||
|                   context: context, | ||||
|                   builder: (BuildContext ctx) { | ||||
|                     return APKOriginWarningDialog( | ||||
| @@ -828,25 +833,23 @@ class AppsProvider with ChangeNotifier { | ||||
|         } | ||||
|         id = downloadedFile?.appId ?? downloadedDir!.appId; | ||||
|         bool willBeSilent = await canInstallSilently(apps[id]!.app); | ||||
|         switch (settingsProvider.installMethod) { | ||||
|           case InstallMethodSettings.normal: | ||||
|             if (!(await settingsProvider.getInstallPermission( | ||||
|                 enforce: false))) { | ||||
|         if (!settingsProvider.useShizuku) { | ||||
|           if (!(await settingsProvider.getInstallPermission(enforce: false))) { | ||||
|             throw ObtainiumError(tr('cancelled')); | ||||
|           } | ||||
|           case InstallMethodSettings.shizuku: | ||||
|             int code = await NativeFeatures.checkPermissionShizuku(); | ||||
|             if (code == -1) { | ||||
|         } else { | ||||
|           switch ((await ShizukuApkInstaller.checkPermission())!) { | ||||
|             case 'binder_not_found': | ||||
|               throw ObtainiumError(tr('shizukuBinderNotFound')); | ||||
|             } else if (code == 0) { | ||||
|               throw ObtainiumError(tr('cancelled')); | ||||
|             } | ||||
|           case InstallMethodSettings.root: | ||||
|             if (!(await NativeFeatures.checkPermissionRoot())) { | ||||
|             case 'old_shizuku': | ||||
|               throw ObtainiumError(tr('shizukuOld')); | ||||
|             case 'old_android_with_adb': | ||||
|               throw ObtainiumError(tr('shizukuOldAndroidWithADB')); | ||||
|             case 'denied': | ||||
|               throw ObtainiumError(tr('cancelled')); | ||||
|           } | ||||
|         } | ||||
|         if (!willBeSilent && context != null) { | ||||
|         if (!willBeSilent && context != null && !settingsProvider.useShizuku) { | ||||
|           // ignore: use_build_context_synchronously | ||||
|           await waitForUserToReturnToForeground(context); | ||||
|         } | ||||
| @@ -857,27 +860,47 @@ class AppsProvider with ChangeNotifier { | ||||
|             bool sayInstalled = true; | ||||
|             var contextIfNewInstall = | ||||
|                 apps[id]?.installedInfo == null ? context : null; | ||||
|             bool needBGWorkaround = | ||||
|                 willBeSilent && context == null && !settingsProvider.useShizuku; | ||||
|             if (downloadedFile != null) { | ||||
|               if (willBeSilent && context == null) { | ||||
|               if (needBGWorkaround) { | ||||
|                 // ignore: use_build_context_synchronously | ||||
|                 installApk(downloadedFile, contextIfNewInstall, | ||||
|                     needsBGWorkaround: true); | ||||
|               } else { | ||||
|                 sayInstalled = | ||||
|                     await installApk(downloadedFile, contextIfNewInstall); | ||||
|                 // ignore: use_build_context_synchronously | ||||
|                 sayInstalled = await installApk( | ||||
|                     downloadedFile, contextIfNewInstall, | ||||
|                     shizukuPretendToBeGooglePlay: | ||||
|                         apps[id]!.app.additionalSettings[ | ||||
|                                 'shizukuPretendToBeGooglePlay'] == | ||||
|                             true); | ||||
|               } | ||||
|             } else { | ||||
|               if (willBeSilent && context == null) { | ||||
|               if (needBGWorkaround) { | ||||
|                 // ignore: use_build_context_synchronously | ||||
|                 installXApkDir(downloadedDir!, contextIfNewInstall, | ||||
|                     needsBGWorkaround: true); | ||||
|               } else { | ||||
|                 sayInstalled = | ||||
|                     await installXApkDir(downloadedDir!, contextIfNewInstall); | ||||
|                 // ignore: use_build_context_synchronously | ||||
|                 sayInstalled = await installXApkDir( | ||||
|                     downloadedDir!, contextIfNewInstall, | ||||
|                     shizukuPretendToBeGooglePlay: | ||||
|                         apps[id]!.app.additionalSettings[ | ||||
|                                 'shizukuPretendToBeGooglePlay'] == | ||||
|                             true); | ||||
|               } | ||||
|             } | ||||
|             if (willBeSilent && context == null) { | ||||
|               if (!settingsProvider.useShizuku) { | ||||
|                 notificationsProvider?.notify(SilentUpdateAttemptNotification( | ||||
|                     [apps[id]!.app], | ||||
|                     id: id.hashCode)); | ||||
|               } else { | ||||
|                 notificationsProvider?.notify(SilentUpdateNotification( | ||||
|                     [apps[id]!.app], sayInstalled, | ||||
|                     id: id.hashCode)); | ||||
|               } | ||||
|             } | ||||
|             if (sayInstalled) { | ||||
|               installedIds.add(id); | ||||
| @@ -952,15 +975,8 @@ class AppsProvider with ChangeNotifier { | ||||
|         if (!downloadsAccessible && exportDir != null) { | ||||
|           downloadPath = exportDir.path; | ||||
|         } | ||||
|         await downloadFile( | ||||
|             fileUrl.value, | ||||
|             fileUrl.key | ||||
|                 .split('.') | ||||
|                 .reversed | ||||
|                 .toList() | ||||
|                 .sublist(1) | ||||
|                 .reversed | ||||
|                 .join('.'), (double? progress) { | ||||
|         await downloadFile(fileUrl.value, fileUrl.key, true, | ||||
|             (double? progress) { | ||||
|           notificationsProvider | ||||
|               .notify(DownloadNotification(fileUrl.key, progress?.ceil() ?? 0)); | ||||
|         }, downloadPath, | ||||
| @@ -1710,7 +1726,7 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async { | ||||
|   int maxRetryWaitSeconds = 5; | ||||
|  | ||||
|   var netResult = await (Connectivity().checkConnectivity()); | ||||
|   if (netResult == ConnectivityResult.none) { | ||||
|   if (netResult.contains(ConnectivityResult.none)) { | ||||
|     logs.add('BG update task: No network.'); | ||||
|     return; | ||||
|   } | ||||
| @@ -1747,8 +1763,8 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async { | ||||
|  | ||||
|   var networkRestricted = false; | ||||
|   if (appsProvider.settingsProvider.bgUpdatesOnWiFiOnly) { | ||||
|     networkRestricted = (netResult != ConnectivityResult.wifi) && | ||||
|         (netResult != ConnectivityResult.ethernet); | ||||
|     networkRestricted = !netResult.contains(ConnectivityResult.wifi) && | ||||
|         !netResult.contains(ConnectivityResult.ethernet); | ||||
|   } | ||||
|  | ||||
|   if (toCheck.isNotEmpty) { | ||||
| @@ -1792,8 +1808,8 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async { | ||||
|     var networkRestricted = false; | ||||
|     if (appsProvider.settingsProvider.bgUpdatesOnWiFiOnly) { | ||||
|       var netResult = await (Connectivity().checkConnectivity()); | ||||
|       networkRestricted = (netResult != ConnectivityResult.wifi) && | ||||
|           (netResult != ConnectivityResult.ethernet); | ||||
|       networkRestricted = !netResult.contains(ConnectivityResult.wifi) && | ||||
|           !netResult.contains(ConnectivityResult.ethernet); | ||||
|     } | ||||
|  | ||||
|     try { | ||||
|   | ||||
| @@ -1,75 +1,22 @@ | ||||
| import 'dart:async'; | ||||
| import 'dart:io'; | ||||
| import 'package:android_system_font/android_system_font.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
|  | ||||
| class NativeFeatures { | ||||
|   static const MethodChannel _channel = MethodChannel('native'); | ||||
|   static bool _systemFontLoaded = false; | ||||
|   static bool _callbacksApplied = false; | ||||
|   static int _resPermShizuku = -2;  // not set | ||||
|  | ||||
|   static Future<ByteData> _readFileBytes(String path) async { | ||||
|     var file = File(path); | ||||
|     var bytes = await file.readAsBytes(); | ||||
|     var bytes = await File(path).readAsBytes(); | ||||
|     return ByteData.view(bytes.buffer); | ||||
|   } | ||||
|  | ||||
|   static Future _handleCalls(MethodCall call) async { | ||||
|     if (call.method == 'resPermShizuku') { | ||||
|       _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 | ||||
|   static Future loadSystemFont() async { | ||||
|     if (_systemFontLoaded) return; | ||||
|     var fontLoader = FontLoader('SystemFont'); | ||||
|     fontLoader.addFont(_readFileBytes(getFontRes)); | ||||
|     await fontLoader.load(); | ||||
|     var fontFilePath = await AndroidSystemFont().getFilePath(); | ||||
|     fontLoader.addFont(_readFileBytes(fontFilePath!)); | ||||
|     fontLoader.load(); | ||||
|     _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}); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -41,20 +41,26 @@ class UpdateNotification extends ObtainiumNotification { | ||||
| } | ||||
|  | ||||
| class SilentUpdateNotification extends ObtainiumNotification { | ||||
|   SilentUpdateNotification(List<App> updates, {int? id}) | ||||
|   SilentUpdateNotification(List<App> updates, bool succeeded, {int? id}) | ||||
|       : super( | ||||
|             id ?? 3, | ||||
|             tr('appsUpdated'), | ||||
|             succeeded | ||||
|                 ? tr('appsUpdated') | ||||
|                 : tr('appsNotUpdated'), | ||||
|             '', | ||||
|             'APPS_UPDATED', | ||||
|             tr('appsUpdatedNotifChannel'), | ||||
|             tr('appsUpdatedNotifDescription'), | ||||
|             Importance.defaultImportance) { | ||||
|     message = updates.length == 1 | ||||
|         ? tr('xWasUpdatedToY', | ||||
|         ? tr(succeeded | ||||
|             ? 'xWasUpdatedToY' | ||||
|             : 'xWasNotUpdatedToY', | ||||
|                 args: [updates[0].finalName, updates[0].latestVersion]) | ||||
|         : plural('xAndNMoreUpdatesInstalled', updates.length - 1, | ||||
|             args: [updates[0].finalName, (updates.length - 1).toString()]); | ||||
|         : plural(succeeded | ||||
|             ? 'xAndNMoreUpdatesInstalled' | ||||
|             : "xAndNMoreUpdatesFailed", | ||||
|                 updates.length - 1, args: [updates[0].finalName, (updates.length - 1).toString()]); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -17,41 +17,14 @@ import 'package:shared_storage/shared_storage.dart' as saf; | ||||
| String obtainiumTempId = 'imranr98_obtainium_${GitHub().hosts[0]}'; | ||||
| String obtainiumId = 'dev.imranr.obtainium'; | ||||
| String obtainiumUrl = 'https://github.com/ImranR98/Obtainium'; | ||||
|  | ||||
| enum InstallMethodSettings { normal, shizuku, root } | ||||
| Color obtainiumThemeColor = const Color(0xFF6438B5); | ||||
|  | ||||
| enum ThemeSettings { system, light, dark } | ||||
|  | ||||
| enum ColourSettings { basic, materialYou } | ||||
|  | ||||
| enum SortColumnSettings { added, nameAuthor, authorName, releaseDate } | ||||
|  | ||||
| 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 { | ||||
|   SharedPreferences? prefs; | ||||
|   String? defaultAppDir; | ||||
| @@ -75,13 +48,12 @@ class SettingsProvider with ChangeNotifier { | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   InstallMethodSettings get installMethod { | ||||
|     return InstallMethodSettings.values[ | ||||
|         prefs?.getInt('installMethod') ?? InstallMethodSettings.normal.index]; | ||||
|   bool get useShizuku{ | ||||
|     return prefs?.getBool('useShizuku') ?? false; | ||||
|   } | ||||
|  | ||||
|   set installMethod(InstallMethodSettings t) { | ||||
|     prefs?.setInt('installMethod', t.index); | ||||
|   set useShizuku(bool useShizuku) { | ||||
|     prefs?.setBool('useShizuku', useShizuku); | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
| @@ -95,13 +67,23 @@ class SettingsProvider with ChangeNotifier { | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   ColourSettings get colour { | ||||
|     return ColourSettings | ||||
|         .values[prefs?.getInt('colour') ?? ColourSettings.basic.index]; | ||||
|   Color get themeColor { | ||||
|     int? colorCode = prefs?.getInt('themeColor'); | ||||
|     return (colorCode != null) ? | ||||
|         Color(colorCode) : obtainiumThemeColor; | ||||
|   } | ||||
|  | ||||
|   set colour(ColourSettings t) { | ||||
|     prefs?.setInt('colour', t.index); | ||||
|   set themeColor(Color themeColor) { | ||||
|     prefs?.setInt('themeColor', themeColor.value); | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   bool get useMaterialYou { | ||||
|     return prefs?.getBool('useMaterialYou') ?? false; | ||||
|   } | ||||
|  | ||||
|   set useMaterialYou(bool useMaterialYou) { | ||||
|     prefs?.setBool('useMaterialYou', useMaterialYou); | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
| @@ -115,21 +97,20 @@ class SettingsProvider with ChangeNotifier { | ||||
|   } | ||||
|  | ||||
|   int get updateInterval { | ||||
|     var min = 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; | ||||
|     return prefs?.getInt('updateInterval') ?? 360; | ||||
|   } | ||||
|  | ||||
|   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(); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -521,6 +521,11 @@ abstract class AppSource { | ||||
|           label: tr('autoApkFilterByArch'), defaultValue: true) | ||||
|     ], | ||||
|     [GeneratedFormTextField('appName', label: tr('appName'), required: false)], | ||||
|     [ | ||||
|       GeneratedFormSwitch('shizukuPretendToBeGooglePlay', | ||||
|           label: tr('shizukuPretendToBeGooglePlay'), | ||||
|           defaultValue: false) | ||||
|     ], | ||||
|     [ | ||||
|       GeneratedFormSwitch('exemptFromBackgroundUpdates', | ||||
|           label: tr('exemptFromBackgroundUpdates')) | ||||
|   | ||||
							
								
								
									
										156
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -26,6 +26,15 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     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: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -38,18 +47,18 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: app_links | ||||
|       sha256: "42dc15aecf2618ace4ffb74a2e58a50e45cd1b9f2c17c8f0cafe4c297f08c815" | ||||
|       sha256: "1c2b9e9c56d80d17610bcbd111b37187875c5d0ded8654caa1bda14ea753d001" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.0.1" | ||||
|     version: "6.0.1" | ||||
|   archive: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: archive | ||||
|       sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" | ||||
|       sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.4.10" | ||||
|     version: "3.5.1" | ||||
|   args: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -70,10 +79,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: background_fetch | ||||
|       sha256: dbffec0317ccdef6e2014cb543e147f52441e29c4fcb53dfd23558c4d92ddece | ||||
|       sha256: "2fe367c9be0e256dadb75b8b637b0b58a2a2d2317b7c8420bb1ae8b41e23fde3" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.3.2" | ||||
|     version: "1.3.4" | ||||
|   boolean_selector: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -126,10 +135,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: connectivity_plus | ||||
|       sha256: ebe15d94de9dd7c31dc2ac54e42780acdf3384b1497c69290c9f3c5b0279fc57 | ||||
|       sha256: db7a4e143dc72cc3cb2044ef9b052a7ebfe729513e6a82943bc3526f784365b8 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.0.2" | ||||
|     version: "6.0.3" | ||||
|   connectivity_plus_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -138,14 +147,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.0.0" | ||||
|   convert: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: convert | ||||
|       sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.1.1" | ||||
|   cross_file: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -174,10 +175,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: cupertino_icons | ||||
|       sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d | ||||
|       sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.0.6" | ||||
|     version: "1.0.8" | ||||
|   dbus: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -214,10 +215,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: easy_localization | ||||
|       sha256: c145aeb6584aedc7c862ab8c737c3277788f47488bfdf9bae0fe112bd0a4789c | ||||
|       sha256: "432698c31a488dd64c56d4759f20d04844baba5e9e4f2cb1abb9676257918b17" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.0.5" | ||||
|     version: "3.0.6" | ||||
|   easy_logger: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -226,6 +227,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     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: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -254,10 +263,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: file_picker | ||||
|       sha256: d1d0ac3966b36dc3e66eeefb40280c17feb87fa2099c6e22e6a1fc959327bd03 | ||||
|       sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "8.0.0+1" | ||||
|     version: "8.0.3" | ||||
|   fixnum: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -266,6 +275,22 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     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: | ||||
|     dependency: "direct main" | ||||
|     description: flutter | ||||
| @@ -307,10 +332,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: flutter_local_notifications | ||||
|       sha256: a701df4866f9a38bb8e4450a54c143bbeeb0ce2381e7df5a36e1006f3b43bb28 | ||||
|       sha256: "84a3af6c7fb43c85c3528b434dacc7a7ed4551d1209d93773bf6045cec9ace68" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "17.0.1" | ||||
|     version: "17.1.1" | ||||
|   flutter_local_notifications_linux: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -323,10 +348,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: flutter_local_notifications_platform_interface | ||||
|       sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" | ||||
|       sha256: "340abf67df238f7f0ef58f4a26d2a83e1ab74c77ab03cd2b2d5018ac64db30b7" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "7.0.0+1" | ||||
|     version: "7.1.0" | ||||
|   flutter_localizations: | ||||
|     dependency: transitive | ||||
|     description: flutter | ||||
| @@ -336,10 +361,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: flutter_markdown | ||||
|       sha256: "04c4722cc36ec5af38acc38ece70d22d3c2123c61305d555750a091517bbe504" | ||||
|       sha256: "9921f9deda326f8a885e202b1e35237eadfc1345239a0f6f0f1ff287e047547f" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.6.23" | ||||
|     version: "0.7.1" | ||||
|   flutter_plugin_android_lifecycle: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -366,6 +391,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "8.2.5" | ||||
|   fraction: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: fraction | ||||
|       sha256: "09e9504c9177bbd77df56e5d147abfbb3b43360e64bf61510059c14d6a82d524" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "5.0.2" | ||||
|   gtk: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -422,22 +455,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.18.1" | ||||
|   js: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: js | ||||
|       sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.7.1" | ||||
|   json_annotation: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: json_annotation | ||||
|       sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 | ||||
|       sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.8.1" | ||||
|     version: "4.9.0" | ||||
|   leak_tracker: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -594,10 +619,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: permission_handler_android | ||||
|       sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" | ||||
|       sha256: "8bb852cd759488893805c3161d0b2b5db55db52f773dbb014420b304055ba2c5" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "12.0.5" | ||||
|     version: "12.0.6" | ||||
|   permission_handler_apple: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -634,10 +659,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: petitparser | ||||
|       sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 | ||||
|       sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.0.2" | ||||
|     version: "5.4.0" | ||||
|   platform: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -654,14 +679,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.1.8" | ||||
|   pointycastle: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: pointycastle | ||||
|       sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.8.0" | ||||
|   provider: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -674,18 +691,18 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: share_plus | ||||
|       sha256: fb5319f3aab4c5dda5ebb92dca978179ba21f8c783ee4380910ef4c1c6824f51 | ||||
|       sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "8.0.3" | ||||
|     version: "9.0.0" | ||||
|   share_plus_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: share_plus_platform_interface | ||||
|       sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496" | ||||
|       sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.4.0" | ||||
|     version: "4.0.0" | ||||
|   shared_preferences: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -750,6 +767,15 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     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: | ||||
|     dependency: transitive | ||||
|     description: flutter | ||||
| @@ -775,10 +801,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: sqflite | ||||
|       sha256: "5ce2e1a15e822c3b4bfb5400455775e421da7098eed8adc8f26298ada7c9308c" | ||||
|       sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.3" | ||||
|     version: "2.3.3+1" | ||||
|   sqflite_common: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -839,10 +865,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: timezone | ||||
|       sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" | ||||
|       sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.9.2" | ||||
|     version: "0.9.3" | ||||
|   typed_data: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -959,10 +985,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: webview_flutter_android | ||||
|       sha256: f038ee2fae73b509dde1bc9d2c5a50ca92054282de17631a9a3d515883740934 | ||||
|       sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.16.0" | ||||
|     version: "3.16.1" | ||||
|   webview_flutter_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -983,10 +1009,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: win32 | ||||
|       sha256: "0a989dc7ca2bb51eac91e8fd00851297cfffd641aa7538b165c62637ca0eaa4a" | ||||
|       sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "5.4.0" | ||||
|     version: "5.5.0" | ||||
|   win32_registry: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1007,10 +1033,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: xml | ||||
|       sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 | ||||
|       sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.5.0" | ||||
|     version: "6.3.0" | ||||
|   yaml: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1020,5 +1046,5 @@ packages: | ||||
|     source: hosted | ||||
|     version: "3.1.2" | ||||
| sdks: | ||||
|   dart: ">=3.3.0 <4.0.0" | ||||
|   dart: ">=3.3.3 <4.0.0" | ||||
|   flutter: ">=3.19.0" | ||||
|   | ||||
							
								
								
									
										18
									
								
								pubspec.yaml
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								pubspec.yaml
									
									
									
									
									
								
							| @@ -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 | ||||
| # 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. | ||||
| version: 1.1.4+2261 | ||||
| version: 1.1.7+2264 | ||||
|  | ||||
| environment: | ||||
|   sdk: '>=3.0.0 <4.0.0' | ||||
| @@ -56,18 +56,28 @@ dependencies: | ||||
|       url: https://github.com/ImranR98/android_package_installer | ||||
|       ref: main | ||||
|   android_package_manager: ^0.7.0 | ||||
|   share_plus: ^8.0.2 | ||||
|   share_plus: ^9.0.0 | ||||
|   sqflite: ^2.2.0+3 | ||||
|   easy_localization: ^3.0.1 | ||||
|   android_intent_plus: ^5.0.1 | ||||
|   flutter_markdown: ^0.6.14 | ||||
|   flutter_markdown: ^0.7.1 | ||||
|   flutter_archive: ^6.0.0 | ||||
|   hsluv: ^1.1.3 | ||||
|   connectivity_plus: ^6.0.1 | ||||
|   shared_storage: ^0.8.0 | ||||
|   crypto: ^3.0.3 | ||||
|   app_links: ^4.0.0 | ||||
|   app_links: ^6.0.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: | ||||
|   flutter_test: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user