mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-14 13:46:43 +02:00
Compare commits
34 Commits
v0.15.3-be
...
v0.15.4-be
Author | SHA1 | Date | |
---|---|---|---|
ad8463ac8b | |||
7843de240a | |||
0037a08017 | |||
92ba432992 | |||
3a521f4014 | |||
e8bbc9799c | |||
96a48b4813 | |||
355450e82d | |||
99307c5b0c | |||
ace8be6514 | |||
1b538931b1 | |||
7ccd08ee2b | |||
104beed594 | |||
e8df594edb | |||
6e922a84f8 | |||
b74bf86277 | |||
6cbe50c9ef | |||
14fcca040b | |||
7bb545cff9 | |||
f52b1a246c | |||
273dfd89cc | |||
52d72d287b | |||
e8d8fcbe69 | |||
30c6c1afd3 | |||
c8c8093b3a | |||
c970b2cf2e | |||
0815283d31 | |||
55ee2d93b8 | |||
c9e17ed42b | |||
76a91b7fe0 | |||
f9b3169b6a | |||
0f74195255 | |||
5ba33786ab | |||
1fc8ee6fee |
@ -1,12 +1,14 @@
|
|||||||
#  Obtainium
|
#  Obtainium
|
||||||
|
|
||||||
|
[](https://techforpalestine.org/learn-more)
|
||||||
|
|
||||||
Get Android App Updates Directly From the Source.
|
Get Android App Updates Directly From the Source.
|
||||||
|
|
||||||
Obtainium allows you to install and update Apps directly from their releases pages, and receive notifications when new releases are made available.
|
Obtainium allows you to install and update Apps directly from their releases pages, and receive notifications when new releases are made available.
|
||||||
|
|
||||||
Motivation: [Side Of Burritos - You should use this instead of F-Droid | How to use app RSS feed](https://youtu.be/FFz57zNR_M0)
|
Motivation: [Side Of Burritos - You should use this instead of F-Droid | How to use app RSS feed](https://youtu.be/FFz57zNR_M0)
|
||||||
|
|
||||||
Wiki: [https://github.com/ImranR98/Obtainium/wiki](https://github.com/ImranR98/Obtainium/wiki)
|
Read the Wiki: [https://github.com/ImranR98/Obtainium/wiki](https://github.com/ImranR98/Obtainium/wiki)
|
||||||
|
|
||||||
Currently supported App sources:
|
Currently supported App sources:
|
||||||
- Open Source - General:
|
- Open Source - General:
|
||||||
@ -30,6 +32,7 @@ Currently supported App sources:
|
|||||||
- [Signal](https://signal.org/)
|
- [Signal](https://signal.org/)
|
||||||
- [VLC](https://videolan.org/)
|
- [VLC](https://videolan.org/)
|
||||||
- Other - App-Specific:
|
- Other - App-Specific:
|
||||||
|
- [WhatsApp](https://whatsapp.com)
|
||||||
- [Telegram App](https://telegram.org)
|
- [Telegram App](https://telegram.org)
|
||||||
- [Steam Mobile Apps](https://store.steampowered.com/mobile)
|
- [Steam Mobile Apps](https://store.steampowered.com/mobile)
|
||||||
- [Neutron Code](https://neutroncode.com)
|
- [Neutron Code](https://neutroncode.com)
|
||||||
|
@ -96,19 +96,15 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
|
||||||
|
|
||||||
def shizuku_version = '13.1.5'
|
def shizuku_version = '13.1.5'
|
||||||
implementation "dev.rikka.shizuku:api:$shizuku_version"
|
implementation "dev.rikka.shizuku:api:$shizuku_version"
|
||||||
implementation "dev.rikka.shizuku:provider:$shizuku_version"
|
implementation "dev.rikka.shizuku:provider:$shizuku_version"
|
||||||
|
|
||||||
def hidden_api_version = '4.1.0'
|
def hidden_api_version = '4.3.1'
|
||||||
// DO NOT UPDATE Hidden API without updating the Android tools
|
|
||||||
// and do not update Android tools without updating the whole Flutter
|
|
||||||
// (also in android/build.gradle)
|
|
||||||
implementation "dev.rikka.tools.refine:runtime:$hidden_api_version"
|
implementation "dev.rikka.tools.refine:runtime:$hidden_api_version"
|
||||||
implementation "dev.rikka.hidden:compat:$hidden_api_version"
|
implementation "dev.rikka.hidden:compat:$hidden_api_version"
|
||||||
compileOnly "dev.rikka.hidden:stub:$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"
|
implementation "com.github.topjohnwu.libsu:core:5.2.2"
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
android:label="Obtainium"
|
android:label="Obtainium"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:requestLegacyExternalStorage="true">
|
android:requestLegacyExternalStorage="true"
|
||||||
|
android:usesCleartextTraffic="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
@ -44,21 +45,6 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
<service
|
|
||||||
android:name="dev.fluttercommunity.plus.androidalarmmanager.AlarmService"
|
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
|
||||||
android:exported="false" />
|
|
||||||
<receiver
|
|
||||||
android:name="dev.fluttercommunity.plus.androidalarmmanager.AlarmBroadcastReceiver"
|
|
||||||
android:exported="false" />
|
|
||||||
<receiver
|
|
||||||
android:name="dev.fluttercommunity.plus.androidalarmmanager.RebootBroadcastReceiver"
|
|
||||||
android:enabled="false"
|
|
||||||
android:exported="false">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="dev.imranr.obtainium"
|
android:authorities="dev.imranr.obtainium"
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
@ -22,12 +22,13 @@ import io.flutter.plugin.common.MethodChannel
|
|||||||
import io.flutter.plugin.common.MethodChannel.Result
|
import io.flutter.plugin.common.MethodChannel.Result
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||||
import rikka.shizuku.Shizuku
|
import rikka.shizuku.Shizuku
|
||||||
import rikka.shizuku.Shizuku.OnRequestPermissionResultListener
|
import rikka.shizuku.Shizuku.OnRequestPermissionResultListener
|
||||||
import rikka.shizuku.ShizukuBinderWrapper
|
import rikka.shizuku.ShizukuBinderWrapper
|
||||||
|
|
||||||
class MainActivity: FlutterActivity() {
|
class MainActivity: FlutterActivity() {
|
||||||
private var installersChannel: MethodChannel? = null
|
private var nativeChannel: MethodChannel? = null
|
||||||
private val SHIZUKU_PERMISSION_REQUEST_CODE = (10..200).random()
|
private val SHIZUKU_PERMISSION_REQUEST_CODE = (10..200).random()
|
||||||
|
|
||||||
private fun shizukuCheckPermission(result: Result) {
|
private fun shizukuCheckPermission(result: Result) {
|
||||||
@ -51,7 +52,7 @@ class MainActivity: FlutterActivity() {
|
|||||||
requestCode: Int, grantResult: Int ->
|
requestCode: Int, grantResult: Int ->
|
||||||
if (requestCode == SHIZUKU_PERMISSION_REQUEST_CODE) {
|
if (requestCode == SHIZUKU_PERMISSION_REQUEST_CODE) {
|
||||||
val res = if (grantResult == PackageManager.PERMISSION_GRANTED) 1 else 0
|
val res = if (grantResult == PackageManager.PERMISSION_GRANTED) 1 else 0
|
||||||
installersChannel!!.invokeMethod("resPermShizuku", mapOf("res" to res))
|
nativeChannel!!.invokeMethod("resPermShizuku", mapOf("res" to res))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +77,8 @@ class MainActivity: FlutterActivity() {
|
|||||||
val params =
|
val params =
|
||||||
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
|
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
|
||||||
var installFlags: Int = PackageInstallerUtils.getInstallFlags(params)
|
var installFlags: Int = PackageInstallerUtils.getInstallFlags(params)
|
||||||
installFlags = installFlags or 0x00000004 // PackageManager.INSTALL_ALLOW_TEST
|
installFlags = installFlags or (0x00000002/*PackageManager.INSTALL_REPLACE_EXISTING*/
|
||||||
|
or 0x00000004 /*PackageManager.INSTALL_ALLOW_TEST*/)
|
||||||
PackageInstallerUtils.setInstallFlags(params, installFlags)
|
PackageInstallerUtils.setInstallFlags(params, installFlags)
|
||||||
val sessionId = packageInstaller.createSession(params)
|
val sessionId = packageInstaller.createSession(params)
|
||||||
val iSession = IPackageInstallerSession.Stub.asInterface(
|
val iSession = IPackageInstallerSession.Stub.asInterface(
|
||||||
@ -136,7 +138,7 @@ class MainActivity: FlutterActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun rootInstallApk(apkFilePath: String, result: Result) {
|
private fun rootInstallApk(apkFilePath: String, result: Result) {
|
||||||
Shell.sh("pm install -R -t " + apkFilePath).submit { out ->
|
Shell.sh("pm install -r -t " + apkFilePath).submit { out ->
|
||||||
val builder = StringBuilder()
|
val builder = StringBuilder()
|
||||||
for (data in out.getOut()) { builder.append(data) }
|
for (data in out.getOut()) { builder.append(data) }
|
||||||
result.success(builder.toString().endsWith("Success"))
|
result.success(builder.toString().endsWith("Success"))
|
||||||
@ -145,12 +147,18 @@ class MainActivity: FlutterActivity() {
|
|||||||
|
|
||||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
HiddenApiBypass.addHiddenApiExemptions("")
|
||||||
|
}
|
||||||
Shizuku.addRequestPermissionResultListener(shizukuRequestPermissionResultListener)
|
Shizuku.addRequestPermissionResultListener(shizukuRequestPermissionResultListener)
|
||||||
installersChannel = MethodChannel(
|
nativeChannel = MethodChannel(
|
||||||
flutterEngine.dartExecutor.binaryMessenger, "installers")
|
flutterEngine.dartExecutor.binaryMessenger, "native")
|
||||||
installersChannel!!.setMethodCallHandler {
|
nativeChannel!!.setMethodCallHandler {
|
||||||
call, result ->
|
call, result ->
|
||||||
if (call.method == "checkPermissionShizuku") {
|
if (call.method == "getSystemFont") {
|
||||||
|
val res = DefaultSystemFont().get()
|
||||||
|
result.success(res)
|
||||||
|
} else if (call.method == "checkPermissionShizuku") {
|
||||||
shizukuCheckPermission(result)
|
shizukuCheckPermission(result)
|
||||||
} else if (call.method == "checkPermissionRoot") {
|
} else if (call.method == "checkPermissionRoot") {
|
||||||
rootCheckPermission(result)
|
rootCheckPermission(result)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.7.10'
|
ext.kotlin_version = '1.8.10'
|
||||||
ext {
|
ext {
|
||||||
compileSdkVersion = 34 // or latest
|
compileSdkVersion = 34 // or latest
|
||||||
targetSdkVersion = 34 // or latest
|
targetSdkVersion = 34 // or latest
|
||||||
@ -11,9 +11,9 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
classpath "com.android.tools.build:gradle:7.4.2"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath 'dev.rikka.tools.refine:gradle-plugin:4.1.0' // Do not update!
|
classpath "dev.rikka.tools.refine:gradle-plugin:4.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Uvezi greške",
|
"importErrors": "Uvezi greške",
|
||||||
"importedXOfYApps": "{} od {} aplikacija uvezeno.",
|
"importedXOfYApps": "{} od {} aplikacija uvezeno.",
|
||||||
"followingURLsHadErrors": "Sljedeći URL-ovi su imali greške:",
|
"followingURLsHadErrors": "Sljedeći URL-ovi su imali greške:",
|
||||||
"okay": "Dobro",
|
|
||||||
"selectURL": "Odaberite URL",
|
"selectURL": "Odaberite URL",
|
||||||
"selectURLs": "Odaberite URL-ove",
|
"selectURLs": "Odaberite URL-ove",
|
||||||
"pick": "Odaberi",
|
"pick": "Odaberi",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Podržite fiksne APK URL-ove",
|
"supportFixedAPKURL": "Podržite fiksne APK URL-ove",
|
||||||
"selectX": "Izaberite {}",
|
"selectX": "Izaberite {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Želite li ukloniti aplikaciju?",
|
"one": "Želite li ukloniti aplikaciju?",
|
||||||
"other": "Želite li ukloniti aplikacije?"
|
"other": "Želite li ukloniti aplikacije?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Chyba importu",
|
"importErrors": "Chyba importu",
|
||||||
"importedXOfYApps": "{}importováno z {} aplikací.",
|
"importedXOfYApps": "{}importováno z {} aplikací.",
|
||||||
"followingURLsHadErrors": "U následujících adres došlo k chybám:",
|
"followingURLsHadErrors": "U následujících adres došlo k chybám:",
|
||||||
"okay": "Okay",
|
|
||||||
"selectURL": "Vybrat adresu",
|
"selectURL": "Vybrat adresu",
|
||||||
"selectURLs": "Select adresy",
|
"selectURLs": "Select adresy",
|
||||||
"pick": "Vybrat",
|
"pick": "Vybrat",
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Importfehler",
|
"importErrors": "Importfehler",
|
||||||
"importedXOfYApps": "{} von {} Apps importiert.",
|
"importedXOfYApps": "{} von {} Apps importiert.",
|
||||||
"followingURLsHadErrors": "Bei folgenden URLs traten Fehler auf:",
|
"followingURLsHadErrors": "Bei folgenden URLs traten Fehler auf:",
|
||||||
"okay": "Okay",
|
|
||||||
"selectURL": "URL auswählen",
|
"selectURL": "URL auswählen",
|
||||||
"selectURLs": "URLs auswählen",
|
"selectURLs": "URLs auswählen",
|
||||||
"pick": "Auswählen",
|
"pick": "Auswählen",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "neuere Version anhand der ersten dreißig Zahlen der Checksumme der APK URL erraten, wenn anderweitig nicht unterstützt",
|
"supportFixedAPKURL": "neuere Version anhand der ersten dreißig Zahlen der Checksumme der APK URL erraten, wenn anderweitig nicht unterstützt",
|
||||||
"selectX": "Wähle {}",
|
"selectX": "Wähle {}",
|
||||||
"parallelDownloads": "Erlaube parallele Downloads",
|
"parallelDownloads": "Erlaube parallele Downloads",
|
||||||
|
"installMethod": "Installationsmethode",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku läuft nicht",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "App entfernen?",
|
"one": "App entfernen?",
|
||||||
"other": "Apps entfernen?"
|
"other": "Apps entfernen?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Import Errors",
|
"importErrors": "Import Errors",
|
||||||
"importedXOfYApps": "{} of {} Apps imported.",
|
"importedXOfYApps": "{} of {} Apps imported.",
|
||||||
"followingURLsHadErrors": "The following URLs had errors:",
|
"followingURLsHadErrors": "The following URLs had errors:",
|
||||||
"okay": "Okay",
|
|
||||||
"selectURL": "Select URL",
|
"selectURL": "Select URL",
|
||||||
"selectURLs": "Select URLs",
|
"selectURLs": "Select URLs",
|
||||||
"pick": "Pick",
|
"pick": "Pick",
|
||||||
@ -287,7 +286,9 @@
|
|||||||
"normal": "Normal",
|
"normal": "Normal",
|
||||||
"shizuku": "Shizuku",
|
"shizuku": "Shizuku",
|
||||||
"root": "Root",
|
"root": "Root",
|
||||||
"shizukuBinderNotFound": "Shizuku is not running",
|
"shizukuBinderNotFound": "Сompatible Shizuku service wasn't found",
|
||||||
|
"useSystemFont": "Use the system font",
|
||||||
|
"systemFontError": "Error loading the system font: {}",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Remove App?",
|
"one": "Remove App?",
|
||||||
"other": "Remove Apps?"
|
"other": "Remove Apps?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Errores de Importación",
|
"importErrors": "Errores de Importación",
|
||||||
"importedXOfYApps": "{} de {} Aplicaciones importadas.",
|
"importedXOfYApps": "{} de {} Aplicaciones importadas.",
|
||||||
"followingURLsHadErrors": "Las siguientes URLs han tenido problemas:",
|
"followingURLsHadErrors": "Las siguientes URLs han tenido problemas:",
|
||||||
"okay": "Aceptar",
|
|
||||||
"selectURL": "Seleccionar URL",
|
"selectURL": "Seleccionar URL",
|
||||||
"selectURLs": "Seleccionar URLs",
|
"selectURLs": "Seleccionar URLs",
|
||||||
"pick": "Escoger",
|
"pick": "Escoger",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Soporte para URLs fijas de APK",
|
"supportFixedAPKURL": "Soporte para URLs fijas de APK",
|
||||||
"selectX": "Selecciona {}",
|
"selectX": "Selecciona {}",
|
||||||
"parallelDownloads": "Permitir descargas paralelas",
|
"parallelDownloads": "Permitir descargas paralelas",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "¿Eliminar Aplicación?",
|
"one": "¿Eliminar Aplicación?",
|
||||||
"other": "¿Eliminar Aplicaciones?"
|
"other": "¿Eliminar Aplicaciones?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "خطاهای وارد کردن",
|
"importErrors": "خطاهای وارد کردن",
|
||||||
"importedXOfYApps": "{} از {} برنامه وارد شد.",
|
"importedXOfYApps": "{} از {} برنامه وارد شد.",
|
||||||
"followingURLsHadErrors": "آدرس های اینترنتی زیر دارای خطا بودند:",
|
"followingURLsHadErrors": "آدرس های اینترنتی زیر دارای خطا بودند:",
|
||||||
"okay": "باشه",
|
|
||||||
"selectURL": "آدرس اینترنتی انتخاب شده",
|
"selectURL": "آدرس اینترنتی انتخاب شده",
|
||||||
"selectURLs": "آدرس های اینترنتی انتخاب شده",
|
"selectURLs": "آدرس های اینترنتی انتخاب شده",
|
||||||
"pick": "انتخاب",
|
"pick": "انتخاب",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "پشتیبانی از URL های APK ثابت",
|
"supportFixedAPKURL": "پشتیبانی از URL های APK ثابت",
|
||||||
"selectX": "انتخاب کنید {}",
|
"selectX": "انتخاب کنید {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "برنامه حذف شود؟",
|
"one": "برنامه حذف شود؟",
|
||||||
"other": "برنامه ها حذف شوند؟"
|
"other": "برنامه ها حذف شوند؟"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Erreurs d'importation",
|
"importErrors": "Erreurs d'importation",
|
||||||
"importedXOfYApps": "{} sur {} applications importées.",
|
"importedXOfYApps": "{} sur {} applications importées.",
|
||||||
"followingURLsHadErrors": "Les URL suivantes comportaient des erreurs :",
|
"followingURLsHadErrors": "Les URL suivantes comportaient des erreurs :",
|
||||||
"okay": "Okay",
|
|
||||||
"selectURL": "Sélectionnez l'URL",
|
"selectURL": "Sélectionnez l'URL",
|
||||||
"selectURLs": "Sélectionnez les URLs",
|
"selectURLs": "Sélectionnez les URLs",
|
||||||
"pick": "Prendre",
|
"pick": "Prendre",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Support fixed APK URLs",
|
"supportFixedAPKURL": "Support fixed APK URLs",
|
||||||
"selectX": "Select {}",
|
"selectX": "Select {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Supprimer l'application ?",
|
"one": "Supprimer l'application ?",
|
||||||
"other": "Supprimer les applications ?"
|
"other": "Supprimer les applications ?"
|
||||||
@ -335,4 +339,4 @@
|
|||||||
"one": "{} and 1 more app may have been updated.",
|
"one": "{} and 1 more app may have been updated.",
|
||||||
"other": "{} and {} more apps may have been updated."
|
"other": "{} and {} more apps may have been updated."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Importálási hibák",
|
"importErrors": "Importálási hibák",
|
||||||
"importedXOfYApps": "{}/{} app importálva.",
|
"importedXOfYApps": "{}/{} app importálva.",
|
||||||
"followingURLsHadErrors": "A következő URL-ek hibákat tartalmaztak:",
|
"followingURLsHadErrors": "A következő URL-ek hibákat tartalmaztak:",
|
||||||
"okay": "Oké",
|
|
||||||
"selectURL": "Válassza ki az URL-t",
|
"selectURL": "Válassza ki az URL-t",
|
||||||
"selectURLs": "Kiválasztott URL-ek",
|
"selectURLs": "Kiválasztott URL-ek",
|
||||||
"pick": "Válasszon",
|
"pick": "Válasszon",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Támogatja a rögzített APK URL-eket",
|
"supportFixedAPKURL": "Támogatja a rögzített APK URL-eket",
|
||||||
"selectX": "Kiválaszt {}",
|
"selectX": "Kiválaszt {}",
|
||||||
"parallelDownloads": "Párhuzamos letöltéseket enged",
|
"parallelDownloads": "Párhuzamos letöltéseket enged",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Eltávolítja az alkalmazást?",
|
"one": "Eltávolítja az alkalmazást?",
|
||||||
"other": "Eltávolítja az alkalmazást?"
|
"other": "Eltávolítja az alkalmazást?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Errori di importazione",
|
"importErrors": "Errori di importazione",
|
||||||
"importedXOfYApps": "{} app di {} importate.",
|
"importedXOfYApps": "{} app di {} importate.",
|
||||||
"followingURLsHadErrors": "I seguenti URL contengono errori:",
|
"followingURLsHadErrors": "I seguenti URL contengono errori:",
|
||||||
"okay": "Va bene",
|
|
||||||
"selectURL": "Seleziona l'URL",
|
"selectURL": "Seleziona l'URL",
|
||||||
"selectURLs": "Seleziona gli URL",
|
"selectURLs": "Seleziona gli URL",
|
||||||
"pick": "Seleziona",
|
"pick": "Seleziona",
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "インポートエラー",
|
"importErrors": "インポートエラー",
|
||||||
"importedXOfYApps": "{} / {} アプリをインポートしました",
|
"importedXOfYApps": "{} / {} アプリをインポートしました",
|
||||||
"followingURLsHadErrors": "以下のURLでエラーが発生しました:",
|
"followingURLsHadErrors": "以下のURLでエラーが発生しました:",
|
||||||
"okay": "OK",
|
|
||||||
"selectURL": "URLを選択",
|
"selectURL": "URLを選択",
|
||||||
"selectURLs": "URLを選択",
|
"selectURLs": "URLを選択",
|
||||||
"pick": "選択",
|
"pick": "選択",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Support fixed APK URLs",
|
"supportFixedAPKURL": "Support fixed APK URLs",
|
||||||
"selectX": "Select {}",
|
"selectX": "Select {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "アプリを削除しますか?",
|
"one": "アプリを削除しますか?",
|
||||||
"other": "アプリを削除しますか?"
|
"other": "アプリを削除しますか?"
|
||||||
@ -335,4 +339,4 @@
|
|||||||
"one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。",
|
"one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。",
|
||||||
"other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。"
|
"other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Import foutmeldingen",
|
"importErrors": "Import foutmeldingen",
|
||||||
"importedXOfYApps": "{} van {} apps geïmporteerd.",
|
"importedXOfYApps": "{} van {} apps geïmporteerd.",
|
||||||
"followingURLsHadErrors": "De volgende URL's bevatten fouten:",
|
"followingURLsHadErrors": "De volgende URL's bevatten fouten:",
|
||||||
"okay": "Ok",
|
|
||||||
"selectURL": "Selecteer URL",
|
"selectURL": "Selecteer URL",
|
||||||
"selectURLs": "Selecteer URL's",
|
"selectURLs": "Selecteer URL's",
|
||||||
"pick": "Kies",
|
"pick": "Kies",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Support fixed APK URLs",
|
"supportFixedAPKURL": "Support fixed APK URLs",
|
||||||
"selectX": "Select {}",
|
"selectX": "Select {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "App verwijderen?",
|
"one": "App verwijderen?",
|
||||||
"other": "Apps verwijderen?"
|
"other": "Apps verwijderen?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Błędy importowania",
|
"importErrors": "Błędy importowania",
|
||||||
"importedXOfYApps": "Zaimportowano {} z {} aplikacji.",
|
"importedXOfYApps": "Zaimportowano {} z {} aplikacji.",
|
||||||
"followingURLsHadErrors": "Następujące adresy URL zawierały błędy:",
|
"followingURLsHadErrors": "Następujące adresy URL zawierały błędy:",
|
||||||
"okay": "Okej",
|
|
||||||
"selectURL": "Wybierz adres URL",
|
"selectURL": "Wybierz adres URL",
|
||||||
"selectURLs": "Wybierz adresy URL",
|
"selectURLs": "Wybierz adresy URL",
|
||||||
"pick": "Wybierz",
|
"pick": "Wybierz",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Obsługuj stałe adresy URL APK",
|
"supportFixedAPKURL": "Obsługuj stałe adresy URL APK",
|
||||||
"selectX": "Wybierz {}",
|
"selectX": "Wybierz {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Usunąć aplikację?",
|
"one": "Usunąć aplikację?",
|
||||||
"few": "Usunąć aplikacje?",
|
"few": "Usunąć aplikacje?",
|
||||||
@ -361,4 +365,4 @@
|
|||||||
"many": "{} i {} innych apek mogło zostać zaktualizowanych.",
|
"many": "{} i {} innych apek mogło zostać zaktualizowanych.",
|
||||||
"other": "{} i {} inne apki mogły zostać zaktualizowane."
|
"other": "{} i {} inne apki mogły zostać zaktualizowane."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Erros de Importação",
|
"importErrors": "Erros de Importação",
|
||||||
"importedXOfYApps": "{} de {} Apps importados.",
|
"importedXOfYApps": "{} de {} Apps importados.",
|
||||||
"followingURLsHadErrors": "As seguintes URLs apresentaram erros:",
|
"followingURLsHadErrors": "As seguintes URLs apresentaram erros:",
|
||||||
"okay": "Ok",
|
|
||||||
"selectURL": "Selecionar URL",
|
"selectURL": "Selecionar URL",
|
||||||
"selectURLs": "Selecionar URLs",
|
"selectURLs": "Selecionar URLs",
|
||||||
"pick": "Escolher",
|
"pick": "Escolher",
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Ошибка импорта",
|
"importErrors": "Ошибка импорта",
|
||||||
"importedXOfYApps": "Импортировано приложений: {} из {}",
|
"importedXOfYApps": "Импортировано приложений: {} из {}",
|
||||||
"followingURLsHadErrors": "При импорте следующие URL-адреса содержали ошибки:",
|
"followingURLsHadErrors": "При импорте следующие URL-адреса содержали ошибки:",
|
||||||
"okay": "Ok",
|
|
||||||
"selectURL": "Выбрать URL-адрес",
|
"selectURL": "Выбрать URL-адрес",
|
||||||
"selectURLs": "Выбрать URL-адреса",
|
"selectURLs": "Выбрать URL-адреса",
|
||||||
"pick": "Выбрать",
|
"pick": "Выбрать",
|
||||||
@ -287,7 +286,9 @@
|
|||||||
"normal": "Нормальный",
|
"normal": "Нормальный",
|
||||||
"shizuku": "Shizuku",
|
"shizuku": "Shizuku",
|
||||||
"root": "Суперпользователь",
|
"root": "Суперпользователь",
|
||||||
"shizukuBinderNotFound": "Shizuku не запущен",
|
"shizukuBinderNotFound": "Совместимый сервис Shizuku не найден",
|
||||||
|
"useSystemFont": "Использовать системный шрифт",
|
||||||
|
"systemFontError": "Ошибка загрузки системного шрифта: {}",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Удалить приложение?",
|
"one": "Удалить приложение?",
|
||||||
"other": "Удалить приложения?"
|
"other": "Удалить приложения?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Importfel",
|
"importErrors": "Importfel",
|
||||||
"importedXOfYApps": "{} av {} Appar importerade.",
|
"importedXOfYApps": "{} av {} Appar importerade.",
|
||||||
"followingURLsHadErrors": "Följande URL:er hade fel:",
|
"followingURLsHadErrors": "Följande URL:er hade fel:",
|
||||||
"okay": "Okej",
|
|
||||||
"selectURL": "Välj URL",
|
"selectURL": "Välj URL",
|
||||||
"selectURLs": "Välj URL:er",
|
"selectURLs": "Välj URL:er",
|
||||||
"pick": "Välj",
|
"pick": "Välj",
|
||||||
@ -269,6 +268,11 @@
|
|||||||
"bgTaskStarted": "Background task started - check logs.",
|
"bgTaskStarted": "Background task started - check logs.",
|
||||||
"runBgCheckNow": "Kör Bakgrundsuppdateringskoll Nu",
|
"runBgCheckNow": "Kör Bakgrundsuppdateringskoll Nu",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Ta Bort App?",
|
"one": "Ta Bort App?",
|
||||||
"other": "Ta Bort Appar?"
|
"other": "Ta Bort Appar?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "İçe Aktarma Hataları",
|
"importErrors": "İçe Aktarma Hataları",
|
||||||
"importedXOfYApps": "{}'den {} Uygulama İçe Aktarıldı.",
|
"importedXOfYApps": "{}'den {} Uygulama İçe Aktarıldı.",
|
||||||
"followingURLsHadErrors": "Aşağıdaki URL'lerde hatalar oluştu:",
|
"followingURLsHadErrors": "Aşağıdaki URL'lerde hatalar oluştu:",
|
||||||
"okay": "Tamam",
|
|
||||||
"selectURL": "URL Seç",
|
"selectURL": "URL Seç",
|
||||||
"selectURLs": "URL'leri Seç",
|
"selectURLs": "URL'leri Seç",
|
||||||
"pick": "Seç",
|
"pick": "Seç",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Support fixed APK URLs",
|
"supportFixedAPKURL": "Support fixed APK URLs",
|
||||||
"selectX": "Select {}",
|
"selectX": "Select {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Uygulamayı Kaldır?",
|
"one": "Uygulamayı Kaldır?",
|
||||||
"other": "Uygulamaları Kaldır?"
|
"other": "Uygulamaları Kaldır?"
|
||||||
@ -335,4 +339,4 @@
|
|||||||
"one": "{} ve 1 diğer uygulama muhtemelen güncellendi.",
|
"one": "{} ve 1 diğer uygulama muhtemelen güncellendi.",
|
||||||
"other": "{} ve {} daha fazla uygulama muhtemelen güncellendi."
|
"other": "{} ve {} daha fazla uygulama muhtemelen güncellendi."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "Lỗi nhập",
|
"importErrors": "Lỗi nhập",
|
||||||
"importedXOfYApps": "{} trong số {} Ứng dụng đã được nhập.",
|
"importedXOfYApps": "{} trong số {} Ứng dụng đã được nhập.",
|
||||||
"followingURLsHadErrors": "Các URL sau có lỗi:",
|
"followingURLsHadErrors": "Các URL sau có lỗi:",
|
||||||
"okay": "Ôkê",
|
|
||||||
"selectURL": "Chọn URL",
|
"selectURL": "Chọn URL",
|
||||||
"selectURLs": "Chọn URL",
|
"selectURLs": "Chọn URL",
|
||||||
"pick": "Chọn",
|
"pick": "Chọn",
|
||||||
@ -283,6 +282,11 @@
|
|||||||
"supportFixedAPKURL": "Support fixed APK URLs",
|
"supportFixedAPKURL": "Support fixed APK URLs",
|
||||||
"selectX": "Select {}",
|
"selectX": "Select {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
|
"installMethod": "Installation method",
|
||||||
|
"normal": "Normal",
|
||||||
|
"shizuku": "Shizuku",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Shizuku is not running",
|
||||||
"removeAppQuestion":{
|
"removeAppQuestion":{
|
||||||
"one": "Gỡ ứng dụng?",
|
"one": "Gỡ ứng dụng?",
|
||||||
"other": "Gỡ ứng dụng?"
|
"other": "Gỡ ứng dụng?"
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
"importErrors": "导入错误",
|
"importErrors": "导入错误",
|
||||||
"importedXOfYApps": "已导入 {} 中的 {} 个应用。",
|
"importedXOfYApps": "已导入 {} 中的 {} 个应用。",
|
||||||
"followingURLsHadErrors": "下列 URL 存在错误:",
|
"followingURLsHadErrors": "下列 URL 存在错误:",
|
||||||
"okay": "好的",
|
|
||||||
"selectURL": "选择 URL",
|
"selectURL": "选择 URL",
|
||||||
"selectURLs": "选择 URL",
|
"selectURLs": "选择 URL",
|
||||||
"pick": "选择",
|
"pick": "选择",
|
||||||
|
@ -346,6 +346,11 @@ class GitHub extends AppSource {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var apkUrls = getReleaseAPKUrls(releases[i]);
|
var apkUrls = getReleaseAPKUrls(releases[i]);
|
||||||
|
if (additionalSettings['apkFilterRegEx'] != null) {
|
||||||
|
var reg = RegExp(additionalSettings['apkFilterRegEx']);
|
||||||
|
apkUrls =
|
||||||
|
apkUrls.where((element) => reg.hasMatch(element.key)).toList();
|
||||||
|
}
|
||||||
if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) {
|
if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:obtainium/components/generated_form.dart';
|
import 'package:obtainium/components/generated_form.dart';
|
||||||
@ -100,28 +99,6 @@ class HTML extends AppSource {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
[
|
|
||||||
GeneratedFormTextField('versionExtractionRegEx',
|
|
||||||
label: tr('versionExtractionRegEx'),
|
|
||||||
required: false,
|
|
||||||
additionalValidators: [(value) => regExValidator(value)]),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
GeneratedFormTextField('matchGroupToUse',
|
|
||||||
label: tr('matchGroupToUse'),
|
|
||||||
required: false,
|
|
||||||
hint: '0',
|
|
||||||
textInputType: const TextInputType.numberWithOptions(),
|
|
||||||
additionalValidators: [
|
|
||||||
(value) {
|
|
||||||
if (value?.isEmpty == true) {
|
|
||||||
value = null;
|
|
||||||
}
|
|
||||||
value ??= '0';
|
|
||||||
return intValidator(value);
|
|
||||||
}
|
|
||||||
])
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
GeneratedFormSwitch('versionExtractWholePage',
|
GeneratedFormSwitch('versionExtractWholePage',
|
||||||
label: tr('versionExtractWholePage'))
|
label: tr('versionExtractWholePage'))
|
||||||
@ -242,9 +219,14 @@ class HTML extends AppSource {
|
|||||||
Map<String, dynamic> additionalSettings,
|
Map<String, dynamic> additionalSettings,
|
||||||
) async {
|
) async {
|
||||||
var currentUrl = standardUrl;
|
var currentUrl = standardUrl;
|
||||||
for (int i = 0;
|
if (additionalSettings['intermediateLink']?.isNotEmpty != true) {
|
||||||
i < (additionalSettings['intermediateLink']?.length ?? 0);
|
additionalSettings['intermediateLink'] = [];
|
||||||
i++) {
|
}
|
||||||
|
additionalSettings['intermediateLink'] =
|
||||||
|
additionalSettings['intermediateLink']
|
||||||
|
.where((l) => l['customLinkFilterRegex'].isNotEmpty == true)
|
||||||
|
.toList();
|
||||||
|
for (int i = 0; i < (additionalSettings['intermediateLink'].length); i++) {
|
||||||
var intLinks = await grabLinksCommon(await sourceRequest(currentUrl),
|
var intLinks = await grabLinksCommon(await sourceRequest(currentUrl),
|
||||||
additionalSettings['intermediateLink'][i]);
|
additionalSettings['intermediateLink'][i]);
|
||||||
if (intLinks.isEmpty) {
|
if (intLinks.isEmpty) {
|
||||||
@ -270,26 +252,12 @@ class HTML extends AppSource {
|
|||||||
if (additionalSettings['supportFixedAPKURL'] != true) {
|
if (additionalSettings['supportFixedAPKURL'] != true) {
|
||||||
version = rel.hashCode.toString();
|
version = rel.hashCode.toString();
|
||||||
}
|
}
|
||||||
var versionExtractionRegEx =
|
version = extractVersion(
|
||||||
additionalSettings['versionExtractionRegEx'] as String?;
|
additionalSettings['versionExtractionRegEx'] as String?,
|
||||||
if (versionExtractionRegEx?.isNotEmpty == true) {
|
additionalSettings['matchGroupToUse'] as String?,
|
||||||
var match = RegExp(versionExtractionRegEx!).allMatches(
|
additionalSettings['versionExtractWholePage'] == true
|
||||||
additionalSettings['versionExtractWholePage'] == true
|
? res.body.split('\r\n').join('\n').split('\n').join('\\n')
|
||||||
? res.body.split('\r\n').join('\n').split('\n').join('\\n')
|
: rel);
|
||||||
: rel);
|
|
||||||
if (match.isEmpty) {
|
|
||||||
throw NoVersionError();
|
|
||||||
}
|
|
||||||
String matchGroupString =
|
|
||||||
(additionalSettings['matchGroupToUse'] as String).trim();
|
|
||||||
if (matchGroupString.isEmpty) {
|
|
||||||
matchGroupString = "0";
|
|
||||||
}
|
|
||||||
version = match.last.group(int.parse(matchGroupString));
|
|
||||||
if (version?.isEmpty == true) {
|
|
||||||
throw NoVersionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rel = ensureAbsoluteUrl(rel, uri);
|
rel = ensureAbsoluteUrl(rel, uri);
|
||||||
version ??= (await checkDownloadHash(rel)).toString();
|
version ??= (await checkDownloadHash(rel)).toString();
|
||||||
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
|
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
|
||||||
|
@ -19,7 +19,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart';
|
|||||||
// ignore: implementation_imports
|
// ignore: implementation_imports
|
||||||
import 'package:easy_localization/src/localization.dart';
|
import 'package:easy_localization/src/localization.dart';
|
||||||
|
|
||||||
const String currentVersion = '0.15.3';
|
const String currentVersion = '0.15.4';
|
||||||
const String currentReleaseTag =
|
const String currentReleaseTag =
|
||||||
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
|
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ List<MapEntry<Locale, String>> supportedLocales = const [
|
|||||||
MapEntry(Locale('fr'), 'Français'),
|
MapEntry(Locale('fr'), 'Français'),
|
||||||
MapEntry(Locale('es'), 'Español'),
|
MapEntry(Locale('es'), 'Español'),
|
||||||
MapEntry(Locale('pl'), 'Polski'),
|
MapEntry(Locale('pl'), 'Polski'),
|
||||||
MapEntry(Locale('ru'), 'Русский язык'),
|
MapEntry(Locale('ru'), 'Русский'),
|
||||||
MapEntry(Locale('bs'), 'Bosanski'),
|
MapEntry(Locale('bs'), 'Bosanski'),
|
||||||
MapEntry(Locale('pt'), 'Brasileiro'),
|
MapEntry(Locale('pt'), 'Brasileiro'),
|
||||||
MapEntry(Locale('cs'), 'Česky'),
|
MapEntry(Locale('cs'), 'Česky'),
|
||||||
@ -236,13 +236,17 @@ class _ObtainiumState extends State<Obtainium> {
|
|||||||
colorScheme: settingsProvider.theme == ThemeSettings.dark
|
colorScheme: settingsProvider.theme == ThemeSettings.dark
|
||||||
? darkColorScheme
|
? darkColorScheme
|
||||||
: lightColorScheme,
|
: lightColorScheme,
|
||||||
fontFamily: 'Metropolis'),
|
fontFamily: settingsProvider.useSystemFont
|
||||||
|
? 'SystemFont'
|
||||||
|
: 'Metropolis'),
|
||||||
darkTheme: ThemeData(
|
darkTheme: ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
colorScheme: settingsProvider.theme == ThemeSettings.light
|
colorScheme: settingsProvider.theme == ThemeSettings.light
|
||||||
? lightColorScheme
|
? lightColorScheme
|
||||||
: darkColorScheme,
|
: darkColorScheme,
|
||||||
fontFamily: 'Metropolis'),
|
fontFamily: settingsProvider.useSystemFont
|
||||||
|
? 'SystemFont'
|
||||||
|
: 'Metropolis'),
|
||||||
home: Shortcuts(shortcuts: <LogicalKeySet, Intent>{
|
home: Shortcuts(shortcuts: <LogicalKeySet, Intent>{
|
||||||
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
||||||
}, child: const HomePage()));
|
}, child: const HomePage()));
|
||||||
|
@ -5,6 +5,7 @@ import 'package:app_links/app_links.dart';
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:obtainium/components/generated_form_modal.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
import 'package:obtainium/pages/add_app.dart';
|
import 'package:obtainium/pages/add_app.dart';
|
||||||
import 'package:obtainium/pages/apps.dart';
|
import 'package:obtainium/pages/apps.dart';
|
||||||
@ -76,14 +77,39 @@ class _HomePageState extends State<HomePage> {
|
|||||||
try {
|
try {
|
||||||
if (action == 'add') {
|
if (action == 'add') {
|
||||||
await goToAddApp(data);
|
await goToAddApp(data);
|
||||||
} else if (action == 'app') {
|
} else if (action == 'app' || action == 'apps') {
|
||||||
await context
|
var dataStr = Uri.decodeComponent(data);
|
||||||
.read<AppsProvider>()
|
if (await showDialog(
|
||||||
.import('{ "apps": [${Uri.decodeComponent(data)}] }');
|
context: context,
|
||||||
} else if (action == 'apps') {
|
builder: (BuildContext ctx) {
|
||||||
await context
|
return GeneratedFormModal(
|
||||||
.read<AppsProvider>()
|
title: tr('importX', args: [
|
||||||
.import('{ "apps": ${Uri.decodeComponent(data)} }');
|
action == 'app' ? tr('app') : tr('appsString')
|
||||||
|
]),
|
||||||
|
items: const [],
|
||||||
|
additionalWidgets: [
|
||||||
|
ExpansionTile(
|
||||||
|
title: const Text('Raw JSON'),
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
dataStr,
|
||||||
|
style: const TextStyle(fontFamily: 'monospace'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}) !=
|
||||||
|
null) {
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
var result = await context.read<AppsProvider>().import(
|
||||||
|
action == 'app'
|
||||||
|
? '{ "apps": [$dataStr] }'
|
||||||
|
: '{ "apps": $dataStr }');
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
showMessage(
|
||||||
|
tr('importedX', args: [plural('apps', result.key)]), context);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw ObtainiumError(tr('unknown'));
|
throw ObtainiumError(tr('unknown'));
|
||||||
}
|
}
|
||||||
|
@ -590,7 +590,7 @@ class _ImportErrorDialogState extends State<ImportErrorDialog> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop(null);
|
Navigator.of(context).pop(null);
|
||||||
},
|
},
|
||||||
child: Text(tr('okay')))
|
child: Text(tr('ok')))
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import 'package:obtainium/custom_errors.dart';
|
|||||||
import 'package:obtainium/main.dart';
|
import 'package:obtainium/main.dart';
|
||||||
import 'package:obtainium/providers/apps_provider.dart';
|
import 'package:obtainium/providers/apps_provider.dart';
|
||||||
import 'package:obtainium/providers/logs_provider.dart';
|
import 'package:obtainium/providers/logs_provider.dart';
|
||||||
|
import 'package:obtainium/providers/native_provider.dart';
|
||||||
import 'package:obtainium/providers/settings_provider.dart';
|
import 'package:obtainium/providers/settings_provider.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -350,8 +351,6 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
height16,
|
height16,
|
||||||
installMethodDropdown,
|
|
||||||
height16,
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -364,6 +363,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
installMethodDropdown,
|
||||||
height32,
|
height32,
|
||||||
Text(
|
Text(
|
||||||
tr('sourceSpecific'),
|
tr('sourceSpecific'),
|
||||||
@ -408,6 +408,30 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
height16,
|
height16,
|
||||||
localeDropdown,
|
localeDropdown,
|
||||||
height16,
|
height16,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Flexible(child: Text(tr('useSystemFont'))),
|
||||||
|
Switch(
|
||||||
|
value: settingsProvider.useSystemFont,
|
||||||
|
onChanged: (useSystemFont) {
|
||||||
|
if (useSystemFont) {
|
||||||
|
NativeFeatures.loadSystemFont().then((fontLoadRes) {
|
||||||
|
if (fontLoadRes == 'ok') {
|
||||||
|
settingsProvider.useSystemFont = true;
|
||||||
|
} else {
|
||||||
|
showError(ObtainiumError(
|
||||||
|
tr('systemFontError', args: [fontLoadRes])
|
||||||
|
), context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
settingsProvider.useSystemFont = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
height16,
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
@ -32,7 +32,7 @@ import 'package:http/http.dart';
|
|||||||
import 'package:android_intent_plus/android_intent.dart';
|
import 'package:android_intent_plus/android_intent.dart';
|
||||||
import 'package:flutter_archive/flutter_archive.dart';
|
import 'package:flutter_archive/flutter_archive.dart';
|
||||||
import 'package:shared_storage/shared_storage.dart' as saf;
|
import 'package:shared_storage/shared_storage.dart' as saf;
|
||||||
import 'installers_provider.dart';
|
import 'native_provider.dart';
|
||||||
|
|
||||||
final pm = AndroidPackageManager();
|
final pm = AndroidPackageManager();
|
||||||
|
|
||||||
@ -522,12 +522,12 @@ class AppsProvider with ChangeNotifier {
|
|||||||
code = await AndroidPackageInstaller.installApk(
|
code = await AndroidPackageInstaller.installApk(
|
||||||
apkFilePath: file.file.path);
|
apkFilePath: file.file.path);
|
||||||
case InstallMethodSettings.shizuku:
|
case InstallMethodSettings.shizuku:
|
||||||
code = (await Installers.installWithShizuku(
|
code = (await NativeFeatures.installWithShizuku(
|
||||||
apkFileUri: file.file.uri.toString()))
|
apkFileUri: file.file.uri.toString()))
|
||||||
? 0
|
? 0
|
||||||
: 1;
|
: 1;
|
||||||
case InstallMethodSettings.root:
|
case InstallMethodSettings.root:
|
||||||
code = (await Installers.installWithRoot(apkFilePath: file.file.path))
|
code = (await NativeFeatures.installWithRoot(apkFilePath: file.file.path))
|
||||||
? 0
|
? 0
|
||||||
: 1;
|
: 1;
|
||||||
}
|
}
|
||||||
@ -694,14 +694,14 @@ class AppsProvider with ChangeNotifier {
|
|||||||
throw ObtainiumError(tr('cancelled'));
|
throw ObtainiumError(tr('cancelled'));
|
||||||
}
|
}
|
||||||
case InstallMethodSettings.shizuku:
|
case InstallMethodSettings.shizuku:
|
||||||
int code = await Installers.checkPermissionShizuku();
|
int code = await NativeFeatures.checkPermissionShizuku();
|
||||||
if (code == -1) {
|
if (code == -1) {
|
||||||
throw ObtainiumError(tr('shizukuBinderNotFound'));
|
throw ObtainiumError(tr('shizukuBinderNotFound'));
|
||||||
} else if (code == 0) {
|
} else if (code == 0) {
|
||||||
throw ObtainiumError(tr('cancelled'));
|
throw ObtainiumError(tr('cancelled'));
|
||||||
}
|
}
|
||||||
case InstallMethodSettings.root:
|
case InstallMethodSettings.root:
|
||||||
if (!(await Installers.checkPermissionRoot())) {
|
if (!(await NativeFeatures.checkPermissionRoot())) {
|
||||||
throw ObtainiumError(tr('cancelled'));
|
throw ObtainiumError(tr('cancelled'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,26 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class Installers {
|
class NativeFeatures {
|
||||||
static const MethodChannel _channel = MethodChannel('installers');
|
static const MethodChannel _channel = MethodChannel('native');
|
||||||
|
static bool _systemFontLoaded = false;
|
||||||
static bool _callbacksApplied = false;
|
static bool _callbacksApplied = false;
|
||||||
static int _resPermShizuku = -2; // not set
|
static int _resPermShizuku = -2; // not set
|
||||||
|
|
||||||
static Future waitWhile(bool Function() test,
|
static Future<ByteData> _readFileBytes(String path) async {
|
||||||
|
var file = File(path);
|
||||||
|
var bytes = await file.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)]) {
|
[Duration pollInterval = const Duration(milliseconds: 250)]) {
|
||||||
var completer = Completer();
|
var completer = Completer();
|
||||||
check() {
|
check() {
|
||||||
@ -20,20 +34,25 @@ class Installers {
|
|||||||
return completer.future;
|
return completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future handleCalls(MethodCall call) async {
|
static Future<String> loadSystemFont() async {
|
||||||
if (call.method == 'resPermShizuku') {
|
if (_systemFontLoaded) { return "ok"; }
|
||||||
_resPermShizuku = call.arguments['res'];
|
var getFontRes = await _channel.invokeMethod('getSystemFont');
|
||||||
}
|
if (getFontRes[0] != '/') { return getFontRes; } // Error
|
||||||
|
var fontLoader = FontLoader('SystemFont');
|
||||||
|
fontLoader.addFont(_readFileBytes(getFontRes));
|
||||||
|
await fontLoader.load();
|
||||||
|
_systemFontLoaded = true;
|
||||||
|
return "ok";
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<int> checkPermissionShizuku() async {
|
static Future<int> checkPermissionShizuku() async {
|
||||||
if (!_callbacksApplied) {
|
if (!_callbacksApplied) {
|
||||||
_channel.setMethodCallHandler(handleCalls);
|
_channel.setMethodCallHandler(_handleCalls);
|
||||||
_callbacksApplied = true;
|
_callbacksApplied = true;
|
||||||
}
|
}
|
||||||
int res = await _channel.invokeMethod('checkPermissionShizuku');
|
int res = await _channel.invokeMethod('checkPermissionShizuku');
|
||||||
if(res == -2) {
|
if (res == -2) {
|
||||||
await waitWhile(() => _resPermShizuku == -2);
|
await _waitWhile(() => _resPermShizuku == -2);
|
||||||
res = _resPermShizuku;
|
res = _resPermShizuku;
|
||||||
_resPermShizuku = -2;
|
_resPermShizuku = -2;
|
||||||
}
|
}
|
@ -51,6 +51,15 @@ class SettingsProvider with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get useSystemFont {
|
||||||
|
return prefs?.getBool('useSystemFont') ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set useSystemFont(bool useSystemFont) {
|
||||||
|
prefs?.setBool('useSystemFont', useSystemFont);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
InstallMethodSettings get installMethod {
|
InstallMethodSettings get installMethod {
|
||||||
return InstallMethodSettings.values[
|
return InstallMethodSettings.values[
|
||||||
prefs?.getInt('installMethod') ?? InstallMethodSettings.normal.index];
|
prefs?.getInt('installMethod') ?? InstallMethodSettings.normal.index];
|
||||||
|
@ -444,6 +444,16 @@ abstract class AppSource {
|
|||||||
label: tr('trackOnly'),
|
label: tr('trackOnly'),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
GeneratedFormTextField('versionExtractionRegEx',
|
||||||
|
label: tr('versionExtractionRegEx'),
|
||||||
|
required: false,
|
||||||
|
additionalValidators: [(value) => regExValidator(value)]),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
GeneratedFormTextField('matchGroupToUse',
|
||||||
|
label: tr('matchGroupToUse'), required: false, hint: '\$0')
|
||||||
|
],
|
||||||
[
|
[
|
||||||
GeneratedFormDropdown(
|
GeneratedFormDropdown(
|
||||||
'versionDetection',
|
'versionDetection',
|
||||||
@ -580,6 +590,57 @@ bool isTempId(App app) {
|
|||||||
return RegExp('^[0-9]+\$').hasMatch(app.id);
|
return RegExp('^[0-9]+\$').hasMatch(app.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
replaceMatchGroupsInString(RegExpMatch match, String matchGroupString) {
|
||||||
|
if (RegExp('^\\d+\$').hasMatch(matchGroupString)) {
|
||||||
|
matchGroupString = '\$$matchGroupString';
|
||||||
|
}
|
||||||
|
// Regular expression to match numbers in the input string
|
||||||
|
final numberRegex = RegExp(r'\$\d+');
|
||||||
|
// Extract all numbers from the input string
|
||||||
|
final numbers = numberRegex.allMatches(matchGroupString);
|
||||||
|
if (numbers.isEmpty) {
|
||||||
|
// If no numbers found, return the original string
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Replace numbers with corresponding match groups
|
||||||
|
var outputString = matchGroupString;
|
||||||
|
for (final numberMatch in numbers) {
|
||||||
|
final number = numberMatch.group(0)!;
|
||||||
|
final matchGroup = match.group(int.parse(number.substring(1))) ?? '';
|
||||||
|
// Check if the number is preceded by a single backslash
|
||||||
|
final isEscaped = outputString.contains('\\$number');
|
||||||
|
// Replace the number with the corresponding match group
|
||||||
|
if (!isEscaped) {
|
||||||
|
outputString = outputString.replaceAll(number, matchGroup);
|
||||||
|
} else {
|
||||||
|
outputString = outputString.replaceAll('\\$number', number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outputString;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? extractVersion(String? versionExtractionRegEx, String? matchGroupString,
|
||||||
|
String stringToCheck) {
|
||||||
|
if (versionExtractionRegEx?.isNotEmpty == true) {
|
||||||
|
String? version = stringToCheck;
|
||||||
|
var match = RegExp(versionExtractionRegEx!).allMatches(version);
|
||||||
|
if (match.isEmpty) {
|
||||||
|
throw NoVersionError();
|
||||||
|
}
|
||||||
|
matchGroupString = matchGroupString?.trim() ?? '';
|
||||||
|
if (matchGroupString.isEmpty) {
|
||||||
|
matchGroupString = "0";
|
||||||
|
}
|
||||||
|
version = replaceMatchGroupsInString(match.last, matchGroupString);
|
||||||
|
if (version?.isNotEmpty != true) {
|
||||||
|
throw NoVersionError();
|
||||||
|
}
|
||||||
|
return version!;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SourceProvider {
|
class SourceProvider {
|
||||||
// Add more source classes here so they are available via the service
|
// Add more source classes here so they are available via the service
|
||||||
List<AppSource> get sources => [
|
List<AppSource> get sources => [
|
||||||
@ -679,6 +740,18 @@ class SourceProvider {
|
|||||||
String standardUrl = source.standardizeUrl(url);
|
String standardUrl = source.standardizeUrl(url);
|
||||||
APKDetails apk =
|
APKDetails apk =
|
||||||
await source.getLatestAPKDetails(standardUrl, additionalSettings);
|
await source.getLatestAPKDetails(standardUrl, additionalSettings);
|
||||||
|
|
||||||
|
if (source.runtimeType != HTML().runtimeType) {
|
||||||
|
// HTML does it separately
|
||||||
|
String? extractedVersion = extractVersion(
|
||||||
|
additionalSettings['versionExtractionRegEx'] as String?,
|
||||||
|
additionalSettings['matchGroupToUse'] as String?,
|
||||||
|
apk.version);
|
||||||
|
if (extractedVersion != null) {
|
||||||
|
apk.version = extractedVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (additionalSettings['versionDetection'] == 'releaseDateAsVersion' &&
|
if (additionalSettings['versionDetection'] == 'releaseDateAsVersion' &&
|
||||||
apk.releaseDate != null) {
|
apk.releaseDate != null) {
|
||||||
apk.version = apk.releaseDate!.microsecondsSinceEpoch.toString();
|
apk.version = apk.releaseDate!.microsecondsSinceEpoch.toString();
|
||||||
|
@ -46,10 +46,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
|
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.9"
|
version: "3.4.10"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 0.15.3+239 # When changing this, update the tag in main() accordingly
|
version: 0.15.4+240 # When changing this, update the tag in main() accordingly
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.0 <4.0.0'
|
sdk: '>=3.0.0 <4.0.0'
|
||||||
|
Reference in New Issue
Block a user