Compare commits
156 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
eb21ba3f6e | ||
|
3ab14e2311 | ||
|
fff3b22e74 | ||
|
46354e648a | ||
|
4f67ba3f3b | ||
|
e5db702a67 | ||
|
53451fd883 | ||
|
491d3cb723 | ||
|
6c7644c9b3 | ||
|
8539581fe9 | ||
|
f301f6cedb | ||
|
93c8bca038 | ||
|
0961e044a7 | ||
|
7da631e429 | ||
|
66c08f0bfd | ||
|
79a2484d68 | ||
|
c3c7c844dc | ||
|
075d0a0854 | ||
|
cc0416e344 | ||
|
af7088b754 | ||
|
ba21137da7 | ||
|
a7a5749d4f | ||
|
fcf3c8b635 | ||
|
69f578652c | ||
|
7593af25b9 | ||
|
1e8fd33469 | ||
|
03f50e501e | ||
|
21dacb6171 | ||
|
16ecc88fcd | ||
|
1f829289ed | ||
|
be739b7639 | ||
|
4b66aefb33 | ||
|
3f948ae73c | ||
|
de2e881e82 | ||
|
9af3aaa82a | ||
|
3a5157ced0 | ||
|
e16320f995 | ||
|
aac01885f1 | ||
|
7d330cd074 | ||
|
8b0e2aaef1 | ||
|
5db53d9c71 | ||
|
ff5bba933b | ||
|
2b48ee81b7 | ||
|
fe6d0040c4 | ||
|
17d32cd1c6 | ||
|
c6a62fe15a | ||
|
2b22de585e | ||
|
346c670488 | ||
|
2137335e56 | ||
|
cea96275b7 | ||
|
9954b68332 | ||
|
974a822b29 | ||
|
48b89335fa | ||
|
e834630688 | ||
|
3dd1ef076f | ||
|
e70edae831 | ||
|
d9b2d18d85 | ||
|
96b260e431 | ||
|
18ccd01186 | ||
|
c84f51b6ce | ||
|
48958748f6 | ||
|
966b1ee6e3 | ||
|
7432ee867f | ||
|
3ebbd2a4a5 | ||
|
82207a1b3b | ||
|
2ec5c7db11 | ||
|
ab949af700 | ||
|
5c9a35c4f0 | ||
|
8651f58744 | ||
|
d93798a8df | ||
|
0822f991ff | ||
|
fde63a0f05 | ||
|
523e1151b2 | ||
|
d5d6825ed9 | ||
|
79c4d3b9fe | ||
|
d6b99b903f | ||
|
335752ee7c | ||
|
e5afe75213 | ||
|
0df1c1c512 | ||
|
bd2ac73b9f | ||
|
26b5a2d976 | ||
|
c0968e8991 | ||
|
243b1eb2ac | ||
|
c6c61d1c83 | ||
|
f207967411 | ||
|
29bb5cc8cd | ||
|
dbbc2ff19c | ||
|
c012b016f9 | ||
|
22815b8209 | ||
|
619d4f1a51 | ||
|
50e8929763 | ||
|
0e2a0b65ec | ||
|
5b79f399d1 | ||
|
2961d5ac17 | ||
|
4af4160aaa | ||
|
327f73cc9e | ||
|
e82170fec6 | ||
|
8922b1c048 | ||
|
e9550c6ff0 | ||
|
890c3682c4 | ||
|
a2c38968e1 | ||
|
a9c3ee4c54 | ||
|
36db226024 | ||
|
6fbdf62afa | ||
|
9344ebbb06 | ||
|
51b66ab983 | ||
|
7f2a9b6fa5 | ||
|
ac6bc4d786 | ||
|
acd30b516c | ||
|
5bc9234101 | ||
|
80d15f5232 | ||
|
eb7c2a9fc4 | ||
|
40175468b2 | ||
|
814b5a71bd | ||
|
38a1e43116 | ||
|
5064b78c79 | ||
|
767350e4e3 | ||
|
4caae51904 | ||
|
83616b7a79 | ||
|
52b2d0868c | ||
|
94f629859e | ||
|
773d3455ae | ||
|
919ab16528 | ||
|
268b89eaf6 | ||
|
9c9a264e39 | ||
|
e1e612455a | ||
|
e191d75300 | ||
|
fce2a2f15c | ||
|
dd8acd9451 | ||
|
2d5676f13d | ||
|
dfbf9e925c | ||
|
e44f77a68a | ||
|
cc373c8d7f | ||
|
2ad88bf3ca | ||
|
b1f9375bb1 | ||
|
0e14e17236 | ||
|
fc541837ef | ||
|
da0b1d0684 | ||
|
3fd89e8567 | ||
|
8cab348eed | ||
|
6bd821985f | ||
|
1f2efe435f | ||
|
8276a809a5 | ||
|
5fe1a8a370 | ||
|
58710093ba | ||
|
ac6f8c456d | ||
|
905461c242 | ||
|
e3fcf6e0b5 | ||
|
903fad5158 | ||
|
1de93e827a | ||
|
a5040aa0c1 | ||
|
9f7c4e23d5 | ||
|
876f67aacb | ||
|
9d5ce75e27 | ||
|
c1c06b3f9c | ||
|
5e0333c4c8 |
2
.flutter
40
.github/workflows/release.yml
vendored
@@ -6,9 +6,6 @@ on:
|
||||
beta:
|
||||
type: boolean
|
||||
description: Is beta?
|
||||
draft:
|
||||
type: boolean
|
||||
description: Is draft?
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -18,6 +15,8 @@ jobs:
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: stable
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
@@ -27,13 +26,6 @@ jobs:
|
||||
id: flutter_doctor
|
||||
run: |
|
||||
flutter doctor -v
|
||||
|
||||
- name: Import GPG key
|
||||
id: import_pgp_key
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.PGP_KEY_BASE64 }}
|
||||
passphrase: ${{ secrets.PGP_PASSPHRASE }}
|
||||
|
||||
- name: Check submodule
|
||||
id: check_submodule
|
||||
@@ -57,24 +49,13 @@ jobs:
|
||||
for file in build/app/outputs/flutter-apk/app-*normal*.apk*; do mv "$file" "${file//-normal/}"; done
|
||||
flutter build apk --flavor fdroid -t lib/main_fdroid.dart && flutter build apk --split-per-abi --flavor fdroid -t lib/main_fdroid.dart
|
||||
rm ./build/app/outputs/flutter-apk/*.sha1
|
||||
cp ./sign.sh ./build/app/outputs/flutter-apk/
|
||||
ls -l ./build/app/outputs/flutter-apk/
|
||||
|
||||
- name: Sign APKs
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
|
||||
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
|
||||
run: |
|
||||
echo "${KEYSTORE_BASE64}" | base64 -d > apksign.keystore
|
||||
for apk in ./build/app/outputs/flutter-apk/*-release*.apk; do
|
||||
unsignedFn=${apk/-release/-unsigned}
|
||||
mv "$apk" "$unsignedFn"
|
||||
${ANDROID_HOME}/build-tools/$(ls ${ANDROID_HOME}/build-tools/ | tail -1)/apksigner sign --ks apksign.keystore --ks-pass pass:"${KEYSTORE_PASSWORD}" --out "${apk}" "${unsignedFn}"
|
||||
sha256sum ${apk} | cut -d " " -f 1 > "$apk".sha256
|
||||
gpg --batch --pinentry-mode loopback --passphrase "${PGP_PASSPHRASE}" --sign --detach-sig "$apk".sha256
|
||||
done
|
||||
rm apksign.keystore
|
||||
PGP_KEY_FINGERPRINT="${{ steps.import_pgp_key.outputs.fingerprint }}"
|
||||
|
||||
- name: Save Unsigned APKs as Action Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: build/app/outputs/flutter-apk/*
|
||||
|
||||
- name: Create Tag
|
||||
uses: mathieudutour/github-tag-action@v6.1
|
||||
@@ -83,12 +64,11 @@ jobs:
|
||||
custom_tag: "${{ steps.extract_version.outputs.tag }}"
|
||||
tag_prefix: ""
|
||||
|
||||
- name: Create Release And Upload APKs
|
||||
- name: Create Draft Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
tag: "${{ steps.extract_version.outputs.tag }}"
|
||||
prerelease: "${{ steps.extract_version.outputs.beta }}"
|
||||
draft: "${{ inputs.draft }}"
|
||||
artifacts: ./build/app/outputs/flutter-apk/*-release*.apk*
|
||||
draft: "true"
|
||||
generateReleaseNotes: true
|
||||
|
3
.gitignore
vendored
@@ -5,9 +5,11 @@
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.build/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
.swiftpm/
|
||||
migrate_working_dir/
|
||||
.vscode/
|
||||
|
||||
@@ -43,6 +45,7 @@ app.*.map.json
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
/android/app/.cxx
|
||||
|
||||
# Custom
|
||||
TODO.txt
|
30
.metadata
@@ -1,11 +1,11 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled.
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 543dac2f35de563fcb6905e9146bdce712c44000
|
||||
channel: master
|
||||
revision: "17025dd88227cd9532c33fa78f5250d548d87e9a"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
@@ -13,14 +13,26 @@ project_type: app
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 543dac2f35de563fcb6905e9146bdce712c44000
|
||||
base_revision: 543dac2f35de563fcb6905e9146bdce712c44000
|
||||
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
- platform: android
|
||||
create_revision: 543dac2f35de563fcb6905e9146bdce712c44000
|
||||
base_revision: 543dac2f35de563fcb6905e9146bdce712c44000
|
||||
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
- platform: ios
|
||||
create_revision: 543dac2f35de563fcb6905e9146bdce712c44000
|
||||
base_revision: 543dac2f35de563fcb6905e9146bdce712c44000
|
||||
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
- platform: linux
|
||||
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
- platform: macos
|
||||
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
- platform: web
|
||||
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
- platform: windows
|
||||
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||
|
||||
# User provided section
|
||||
|
||||
|
21
README.md
@@ -7,10 +7,12 @@ Get Android app updates straight 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.
|
||||
|
||||
More info:
|
||||
- [Obtainium/wiki](https://github.com/ImranR98/Obtainium/wiki)
|
||||
- [Obtainium Wiki](https://wiki.obtainium.imranr.dev/) ([repository](https://github.com/ImranR98/Obtainium-Wiki))
|
||||
- [AppVerifier](https://github.com/soupslurpr/AppVerifier) - App verification tool (recommended, integrates with Obtainium)
|
||||
- [apps.obtainium.imranr.dev](https://apps.obtainium.imranr.dev/) - Crowdsourced app configurations
|
||||
- [apps.obtainium.imranr.dev](https://apps.obtainium.imranr.dev/) - Crowdsourced app configurations ([repository](https://github.com/ImranR98/apps.obtainium.imranr.dev))
|
||||
- [Side Of Burritos - You should use this instead of F-Droid | How to use app RSS feed](https://youtu.be/FFz57zNR_M0) - Original motivation for this app
|
||||
- [Website](https://obtainium.imranr.dev) ([repository](https://github.com/ImranR98/obtainium.imranr.dev))
|
||||
- [Source code](https://github.com/ImranR98/Obtainium)
|
||||
|
||||
Currently supported App sources:
|
||||
- Open Source - General:
|
||||
@@ -27,15 +29,12 @@ Currently supported App sources:
|
||||
- [Uptodown](https://uptodown.com/)
|
||||
- [Huawei AppGallery](https://appgallery.huawei.com/)
|
||||
- [Tencent App Store](https://sj.qq.com/)
|
||||
- [RuStore](https://rustore.ru/)
|
||||
- Jenkins Jobs
|
||||
- [APKMirror](https://apkmirror.com/) (Track-Only)
|
||||
- Open Source - App-Specific:
|
||||
- [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)
|
||||
- [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
|
||||
|
||||
@@ -59,7 +58,11 @@ Or, contribute some configurations to the website by creating a PR at [this repo
|
||||
alt="Get it on F-Droid"
|
||||
height="80">](https://f-droid.org/packages/dev.imranr.obtainium.fdroid/)
|
||||
|
||||
[PGP Public Key](https://keyserver.ubuntu.com/pks/lookup?search=contact%40imranr.dev&fingerprint=on&op=index)
|
||||
Verification info:
|
||||
- Package ID: `dev.imranr.obtainium`
|
||||
- SHA-256 Hash of Signing Certificate: `B3:53:60:1F:6A:1D:5F:D6:60:3A:E2:F5:0B:E8:0C:F3:01:36:7B:86:B6:AB:8B:1F:66:24:3D:A9:6C:D5:73:62`
|
||||
- Note: The above signature is also valid for the F-Droid flavour of Obtainium, thanks to [reproducible builds](https://f-droid.org/docs/Reproducible_Builds/).
|
||||
- [PGP Public Key](https://keyserver.ubuntu.com/pks/lookup?search=contact%40imranr.dev&fingerprint=on&op=index) (to verify APK hashes)
|
||||
|
||||
## Limitations
|
||||
- For some sources, data is gathered using Web scraping and can easily break due to changes in website design. In such cases, more reliable methods may be unavailable.
|
||||
|
@@ -13,8 +13,7 @@ linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at
|
||||
# https://dart-lang.github.io/linter/lints/index.html.
|
||||
# and their documentation is published at https://dart.dev/lints.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
|
2
android/.gitignore
vendored
@@ -7,7 +7,7 @@ gradle-wrapper.jar
|
||||
GeneratedPluginRegistrant.java
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||
# See https://flutter.dev/to/reference-keystore
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
|
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
id "kotlin-android"
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
}
|
||||
|
||||
@@ -29,33 +30,30 @@ if (keystorePropertiesFile.exists()) {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "dev.imranr.obtainium"
|
||||
compileSdk flutter.compileSdkVersion
|
||||
ndkVersion flutter.ndkVersion
|
||||
namespace = "dev.imranr.obtainium"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
jvmTarget = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "dev.imranr.obtainium"
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "dev.imranr.obtainium"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
|
||||
minSdkVersion 24
|
||||
targetSdkVersion flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
minSdk = 24
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
|
||||
flavorDimensions "flavor"
|
||||
|
||||
productFlavors {
|
||||
@@ -77,6 +75,7 @@ android {
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
@@ -89,11 +88,7 @@ android {
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://jitpack.io' }
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3]
|
||||
|
@@ -12,6 +12,7 @@
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
@@ -21,12 +22,12 @@
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action
|
||||
@@ -39,7 +40,6 @@
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="obtainium" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
@@ -71,6 +71,17 @@
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />\
|
||||
android:maxSdkVersion="29" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
|
@@ -9,12 +9,12 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.buildDir = '../build'
|
||||
rootProject.buildDir = "../build"
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
project.evaluationDependsOn(":app")
|
||||
}
|
||||
|
||||
tasks.register("clean", Delete) {
|
||||
|
@@ -1,3 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx2048M
|
||||
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
|
||||
|
@@ -18,8 +18,8 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "7.4.2" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.8.10" apply false
|
||||
id "com.android.application" version "8.1.0" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
BIN
assets/graphics/badge_obtainium_i18n/badge_obtainium_zh-Hans.png
Normal file
After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 234 KiB After Width: | Height: | Size: 418 KiB |
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 418 KiB |
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 265 KiB |
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 220 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 362 KiB |
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Nije pronađena aplikacija s tim ID-om ili imenom",
|
||||
"reposHaveMultipleApps": "Repo-i mogu sadržavati više aplikacija",
|
||||
"fdroidThirdPartyRepo": "F-Droid Repo treće strane",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Razgovor na Steamu (chat)",
|
||||
"install": "Instaliraj",
|
||||
"markInstalled": "Označi kao instalirano",
|
||||
"update": "Nadogradi",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
|
||||
"allowInsecure": "Allow insecure HTTP requests",
|
||||
"stayOneVersionBehind": "Stay one version behind latest",
|
||||
"refreshBeforeDownload": "Refresh app details before download",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Želite li ukloniti aplikaciju?",
|
||||
"other": "Želite li ukloniti aplikacije?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Žádná aplikace s tímto ID nebo názvem nebyla nalezena",
|
||||
"reposHaveMultipleApps": "Repozitáře mohou obsahovat více aplikací",
|
||||
"fdroidThirdPartyRepo": "F-Droid repozitář třetí strany",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Nainstalujte",
|
||||
"markInstalled": "Označit jako nainstalovaný",
|
||||
"update": "Aktualizovat",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Konfigurace aplikací s využitím crowdsourcingu",
|
||||
"allowInsecure": "Povolení nezabezpečených požadavků HTTP",
|
||||
"stayOneVersionBehind": "Zůstaňte o jednu verzi pozadu za nejnovější",
|
||||
"refreshBeforeDownload": "Obnovení údajů o aplikaci před stažením",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Odstranit Apku?",
|
||||
"other": "Odstranit Apky?"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"invalidURLForSource": "Ikke et gyldigt {} App-URL",
|
||||
"invalidURLForSource": "Ikke et gyldigt {} app-URL",
|
||||
"noReleaseFound": "Kunne ikke finde en passende udgivelse",
|
||||
"noVersionFound": "Kunne ikke afgøre udgivelsesversion",
|
||||
"urlMatchesNoSource": "URL'en matcher ikke en kendt kilde",
|
||||
@@ -28,7 +28,7 @@
|
||||
"githubStarredRepos": "Stjernemarkeret GitHub-repos",
|
||||
"uname": "Brugernavn",
|
||||
"wrongArgNum": "Forkert antal argumenter angivet",
|
||||
"xIsTrackOnly": "{} kan kun følges",
|
||||
"xIsTrackOnly": "{} er 'Følg Kun'",
|
||||
"source": "Kilde",
|
||||
"app": "App",
|
||||
"appsFromSourceAreTrackOnly": "Apps fra denne kilde er 'Følg Kun'.",
|
||||
@@ -36,14 +36,14 @@
|
||||
"trackOnlyAppDescription": "Appen tjekkes for opdateringer, men Obtainium kan ikke hente eller installere den.",
|
||||
"cancelled": "Annulleret",
|
||||
"appAlreadyAdded": "Appen er allerede tilføjet",
|
||||
"alreadyUpToDateQuestion": "Appen er allerede opdateret?",
|
||||
"alreadyUpToDateQuestion": "Er appen allerede opdateret?",
|
||||
"addApp": "Tilføj app",
|
||||
"appSourceURL": "URL til app-kilde",
|
||||
"error": "Fejl",
|
||||
"add": "Tilføj",
|
||||
"searchSomeSourcesLabel": "Søg (kun visse kilder)",
|
||||
"search": "Søg",
|
||||
"additionalOptsFor": "Yderligere indstillinger for {}",
|
||||
"additionalOptsFor": "Flere indstillinger for {}",
|
||||
"supportedSources": "Understøttede kilder",
|
||||
"trackOnlyInBrackets": "(Følg Kun)",
|
||||
"searchableInBrackets": "(Kan Søges)",
|
||||
@@ -51,7 +51,7 @@
|
||||
"noApps": "Ingen apps",
|
||||
"noAppsForFilter": "Ingen apps til filter",
|
||||
"byX": "Af {}",
|
||||
"percentProgress": "Fremskridt: {}%",
|
||||
"percentProgress": "Hentning: {}%",
|
||||
"pleaseWait": "Vent venligst",
|
||||
"updateAvailable": "Opdatering tilgængelig",
|
||||
"notInstalled": "Ikke installeret",
|
||||
@@ -74,14 +74,14 @@
|
||||
"pinToTop": "Fastgør til toppen",
|
||||
"unpinFromTop": "Frigør fra toppen",
|
||||
"resetInstallStatusForSelectedAppsQuestion": "Nulstil installationsstatus for valgte apps?",
|
||||
"installStatusOfXWillBeResetExplanation": "Installationsstatus for alle valgte apps nulstilles.\n\nDette kan hjælpe, når den app-version, der vises i Obtainium, er forkert grundet mislykkede opdateringer eller andre problemer.",
|
||||
"installStatusOfXWillBeResetExplanation": "Installationsstatus for alle valgte apps nulstilles.\n\nDette kan hjælpe, når en forkert app-version vises i Obtainium grundet mislykkede opdateringer eller andre problemer.",
|
||||
"customLinkMessage": "Disse links virker på enheder med Obtainium installeret",
|
||||
"shareAppConfigLinks": "Del app-konfiguration som HTML-link",
|
||||
"shareSelectedAppURLs": "Del valgte app-URL'er",
|
||||
"resetInstallStatus": "Nulstil installationsstatus",
|
||||
"more": "Mere",
|
||||
"removeOutdatedFilter": "Fjern forældet app-filter",
|
||||
"showOutdatedOnly": "Vis kun forældet apps",
|
||||
"showOutdatedOnly": "Vis kun forældede apps",
|
||||
"filter": "Filtrer",
|
||||
"filterApps": "Filtrer Apps",
|
||||
"appName": "Appnavn",
|
||||
@@ -114,7 +114,7 @@
|
||||
"light": "Lys",
|
||||
"followSystem": "Følg system",
|
||||
"followSystemThemeExplanation": "Det er kun muligt at følge systemtemaet ved brug af tredjepartsapplikationer",
|
||||
"useBlackTheme": "Brug rent sort, mørkt tema",
|
||||
"useBlackTheme": "Brug rent sort mørkt tema",
|
||||
"appSortBy": "Sortér apps efter:",
|
||||
"authorName": "Udvikler/Navn",
|
||||
"nameAuthor": "Navn/Udvikler",
|
||||
@@ -125,8 +125,8 @@
|
||||
"bgUpdateCheckInterval": "Kontrolinterval for baggrundsopdatering",
|
||||
"neverManualOnly": "Aldrig - Kun manuelt",
|
||||
"appearance": "Udseende",
|
||||
"showWebInAppView": "Vis kildewebsiden i appvisning",
|
||||
"pinUpdates": "Fastgør opdateringer til toppen af appvisning",
|
||||
"showWebInAppView": "Vis kildewebsiden i app-visning",
|
||||
"pinUpdates": "Fastgør opdateringer øverst i app-visning",
|
||||
"updates": "Opdateringer",
|
||||
"sourceSpecific": "Kildespecifik",
|
||||
"appSource": "App-kilde",
|
||||
@@ -138,12 +138,12 @@
|
||||
"obtainiumExportHyphenatedLowercase": "obtainium-eksport",
|
||||
"pickAnAPK": "Vælg en APK",
|
||||
"appHasMoreThanOnePackage": "{} har mere end én pakke:",
|
||||
"deviceSupportsXArch": "Din enhed understøtter {} CPU-arkitekturen.",
|
||||
"deviceSupportsXArch": "Din enhed understøtter CPU-arkitekturen {}.",
|
||||
"deviceSupportsFollowingArchs": "Din enhed understøtter følgende CPU-arkitekturer:",
|
||||
"warning": "Advarsel",
|
||||
"sourceIsXButPackageFromYPrompt": "App-kilden er '{}', men udgivelsespakken kommer fra '{}'. Fortsæt?",
|
||||
"updatesAvailable": "Opdateringer tilgængelige",
|
||||
"updatesAvailableNotifDescription": "Underretter brugeren om, at opdateringer er tilgængelige for en eller flere apps, der spores af Obtainium",
|
||||
"updatesAvailableNotifDescription": "Underretter brugeren om tilgængelige opdateringer for en eller flere apps, som Obtainium følger",
|
||||
"noNewUpdates": "Ingen nye opdateringer.",
|
||||
"xHasAnUpdate": "{} har en opdatering.",
|
||||
"appsUpdated": "Apps opdateret",
|
||||
@@ -152,19 +152,19 @@
|
||||
"xWasUpdatedToY": "{} blev opdateret til {}.",
|
||||
"xWasNotUpdatedToY": "Kunne ikke opdatere {} til {}.",
|
||||
"errorCheckingUpdates": "Fejl ved tjek for opdateringer",
|
||||
"errorCheckingUpdatesNotifDescription": "En meddelelse, der vises, når opdateringstjek i baggrunden mislykkes",
|
||||
"errorCheckingUpdatesNotifDescription": "En meddelelse, der vises, opdateringstjek i baggrunden mislykkes",
|
||||
"appsRemoved": "Apps fjernet",
|
||||
"appsRemovedNotifDescription": "Underretter brugeren om, at en eller flere apps blev fjernet grundet fejl under indlæsning af dem",
|
||||
"xWasRemovedDueToErrorY": "{} blev fjernet grundet denne fejl: {}",
|
||||
"completeAppInstallation": "Færdiggør app-installation",
|
||||
"obtainiumMustBeOpenToInstallApps": "Obtainium skal være åben for at installere apps",
|
||||
"completeAppInstallationNotifDescription": "Beder brugeren om at vende tilbage til Obtainium for at afslutte installationen af en app",
|
||||
"completeAppInstallationNotifDescription": "Beder brugeren om at gå tilbage til Obtainium for at færdiggøre installation af en app",
|
||||
"checkingForUpdates": "Tjekker for opdateringer",
|
||||
"checkingForUpdatesNotifDescription": "Kortvarig meddelelse, der vises ved tjek for opdateringer",
|
||||
"checkingForUpdatesNotifDescription": "Kortvarig meddelelse ved tjek for opdateringer",
|
||||
"pleaseAllowInstallPerm": "Tillad venligst Obtainium at installere apps",
|
||||
"trackOnly": "Følg Kun",
|
||||
"errorWithHttpStatusCode": "Fejl {}",
|
||||
"versionCorrectionDisabled": "Versionskorrigering deaktiveret (plugin ser ikke ud til at virke)",
|
||||
"versionCorrectionDisabled": "Versionskorrektion deaktiveret (plugin ser ikke ud til at virke)",
|
||||
"unknown": "Ukendt",
|
||||
"none": "Ingen",
|
||||
"never": "Aldrig",
|
||||
@@ -174,25 +174,23 @@
|
||||
"remove": "Fjern",
|
||||
"yesMarkUpdated": "Ja, markér som opdateret",
|
||||
"fdroid": "F-Droid Officiel",
|
||||
"appIdOrName": "App-ID eller navn",
|
||||
"appIdOrName": "App-ID eller -navn",
|
||||
"appId": "App-ID",
|
||||
"appWithIdOrNameNotFound": "Ingen app med det ID eller navn blev fundet",
|
||||
"reposHaveMultipleApps": "Repos kan indeholde flere apps",
|
||||
"fdroidThirdPartyRepo": "F-Droid Tredjeparts-repo",
|
||||
"steamMobile": "Steam Mobil",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Installer",
|
||||
"markInstalled": "Markér som installeret",
|
||||
"update": "Opdater",
|
||||
"markUpdated": "Markér som opdateret",
|
||||
"additionalOptions": "Yderligere indstillinger",
|
||||
"additionalOptions": "Flere indstillinger",
|
||||
"disableVersionDetection": "Deaktivér versionsregistrering",
|
||||
"noVersionDetectionExplanation": "Denne indstilling bør kun bruges til apps, hvor versionsregistrering ikke virker korrekt.",
|
||||
"downloadingX": "Henter {}",
|
||||
"downloadX": "Hent {}",
|
||||
"downloadedX": "Hentede {}",
|
||||
"releaseAsset": "Udgivelsesressource",
|
||||
"downloadNotifDescription": "Underretter brugeren om fremskridt i hentning af en app",
|
||||
"downloadNotifDescription": "Underretter brugeren om status på hentning af en app",
|
||||
"noAPKFound": "Ingen APK fundet",
|
||||
"noVersionDetection": "Ingen versionsregistrering",
|
||||
"categorize": "Kategoriser",
|
||||
@@ -224,10 +222,10 @@
|
||||
"groupByCategory": "Gruppér efter kategori",
|
||||
"autoApkFilterByArch": "Forsøg at filtrere APK'er efter CPU-arkitektur, hvis muligt",
|
||||
"overrideSource": "Tilsidesæt kilde",
|
||||
"dontShowAgain": "Vis ikke denne igen",
|
||||
"dontShowAgain": "Vis ikke igen",
|
||||
"dontShowTrackOnlyWarnings": "Vis ikke 'Følg Kun'-advarsler",
|
||||
"dontShowAPKOriginWarnings": "Vis ikke advarsler om APK-oprindelse",
|
||||
"moveNonInstalledAppsToBottom": "Flyt ikke-installerede apps til bunden af appvisning",
|
||||
"moveNonInstalledAppsToBottom": "Flyt ikke-installerede apps nederst i app-visning",
|
||||
"gitlabPATLabel": "GitLab Personlig Adgangstoken",
|
||||
"about": "Om",
|
||||
"requiresCredentialsInSettings": "{} kræver yderligere legitimation (i Indstillinger)",
|
||||
@@ -240,44 +238,44 @@
|
||||
"reversePageTransitions": "Omvendte sideovergangsanimationer",
|
||||
"minStarCount": "Minimum antal stjerner",
|
||||
"addInfoBelow": "Tilføj denne info nedenfor.",
|
||||
"addInfoInSettings": "Tilføj denne info i indstillingerne.",
|
||||
"githubSourceNote": "GitHubs hastighedsbegrænsning kan undgås med en API-nøgle.",
|
||||
"addInfoInSettings": "Tilføj denne info i Indstillinger.",
|
||||
"githubSourceNote": "GitHub's hastighedsbegrænsning kan undgås med en API-nøgle.",
|
||||
"sortByLastLinkSegment": "Sortér kun efter det sidste segment af linket",
|
||||
"filterReleaseNotesByRegEx": "Filtrer udgivelsesnoter efter regulært udtryk",
|
||||
"customLinkFilterRegex": "Brugerdefineret APK-linkfilter efter regulært udtryk (standard '.apk$')",
|
||||
"appsPossiblyUpdated": "App-opdateringer forsøgt",
|
||||
"appsPossiblyUpdatedNotifDescription": "Underretter brugeren om, at opdateringer til en eller flere apps potentielt blev udført i baggrunden",
|
||||
"appsPossiblyUpdatedNotifDescription": "Underretter brugeren om, at opdateringer til en eller flere apps muligvis blev udført i baggrunden",
|
||||
"xWasPossiblyUpdatedToY": "{} er muligvis blevet opdateret til {}.",
|
||||
"enableBackgroundUpdates": "Aktivér baggrundsopdateringer",
|
||||
"backgroundUpdateReqsExplanation": "Baggrundsopdateringer er muligvis ikke mulige for alle apps.",
|
||||
"backgroundUpdateLimitsExplanation": "Om en baggrundsinstallation er vellykket, kan kun afgøres, når Obtainium åbnes.",
|
||||
"backgroundUpdateReqsExplanation": "Baggrundsopdateringer er måske ikke mulige for alle apps.",
|
||||
"backgroundUpdateLimitsExplanation": "En vellykket baggrundsinstallation kan kun afgøres, når Obtainium åbnes.",
|
||||
"verifyLatestTag": "Verificer 'seneste'-tagget",
|
||||
"intermediateLinkRegex": "Filtrer efter et 'mellemliggende' link at besøge",
|
||||
"filterByLinkText": "Filtrer links efter linktekst",
|
||||
"intermediateLinkNotFound": "Mellemliggende link ikke fundet",
|
||||
"intermediateLink": "Mellemliggende link",
|
||||
"exemptFromBackgroundUpdates": "Undtag fra baggrundsopdateringer (hvis aktiveret)",
|
||||
"bgUpdatesOnWiFiOnly": "Deaktivér baggrundsopdateringer, når du ikke er på WiFi",
|
||||
"bgUpdatesWhileChargingOnly": "Deaktiver baggrundsopdateringer, når der ikke oplades",
|
||||
"bgUpdatesOnWiFiOnly": "Deaktiver baggrundsopdateringer, når du ikke er på Wi-Fi",
|
||||
"bgUpdatesWhileChargingOnly": "Deaktiver baggrundsopdateringer, når du ikke oplader",
|
||||
"autoSelectHighestVersionCode": "Auto-vælg højeste versionKode af APK",
|
||||
"versionExtractionRegEx": "RegEx for versionsstrengsudtrækning",
|
||||
"trimVersionString": "Trim versionsstrengen med RegEx",
|
||||
"matchGroupToUseForX": "Matchgruppe til brug for \"{}\"",
|
||||
"matchGroupToUse": "Match gruppe til brug til RegEx for versionsstrengsudtrækning",
|
||||
"trimVersionString": "Trim versionsstreng med RegEx",
|
||||
"matchGroupToUseForX": "Match-gruppe til brug for \"{}\"",
|
||||
"matchGroupToUse": "RegEx-matchgruppe til brug for versionsstrengsudtrækning",
|
||||
"highlightTouchTargets": "Fremhæv mindre åbenlyse berøringsmål",
|
||||
"pickExportDir": "Vælg eksportmappe",
|
||||
"autoExportOnChanges": "Auto-eksport ved ændringer",
|
||||
"autoExportOnChanges": "Auto-eksportér ved ændringer",
|
||||
"includeSettings": "Inkluder indstillinger",
|
||||
"filterVersionsByRegEx": "Filtrer versioner efter regulært udtryk",
|
||||
"trySelectingSuggestedVersionCode": "Forsøg at vælge den foreslåede versionKode af APK",
|
||||
"dontSortReleasesList": "Behold udgivelsesordre fra API",
|
||||
"dontSortReleasesList": "Behold udgivelsesrækkefølge fra API",
|
||||
"reverseSort": "Omvendt sortering",
|
||||
"takeFirstLink": "Tag første link",
|
||||
"skipSort": "Spring sortering over",
|
||||
"debugMenu": "Fejlfindingsmenu",
|
||||
"bgTaskStarted": "Baggrundsopgave startet - tjek logfiler.",
|
||||
"runBgCheckNow": "Kør baggrundsopdateringstjek nu",
|
||||
"versionExtractWholePage": "Anvend RegEx for versionsstrengsudtrækning for hele siden",
|
||||
"versionExtractWholePage": "Anvend RegEx til versionsstrengsudtrækning på hele siden",
|
||||
"installing": "Installerer",
|
||||
"skipUpdateNotifications": "Spring opdateringsmeddelelser over",
|
||||
"updatesAvailableNotifChannel": "Opdateringer tilgængelige",
|
||||
@@ -288,7 +286,7 @@
|
||||
"downloadingXNotifChannel": "Henter {}",
|
||||
"completeAppInstallationNotifChannel": "Færdiggør app-installation",
|
||||
"checkingForUpdatesNotifChannel": "Tjekker for opdateringer",
|
||||
"onlyCheckInstalledOrTrackOnlyApps": "Tjek kun installeret og 'Følg Kun'-apps for opdateringer",
|
||||
"onlyCheckInstalledOrTrackOnlyApps": "Tjek kun installerede og 'Følg Kun'-apps for opdateringer",
|
||||
"supportFixedAPKURL": "Understøt fikserede APK-URL'er",
|
||||
"selectX": "Vælg {}",
|
||||
"parallelDownloads": "Tillad samtidige overførsler",
|
||||
@@ -298,8 +296,8 @@
|
||||
"shizukuOldAndroidWithADB": "Shizuku kører på Android <8.1 med ADB. Opdater Android eller brug Sui i stedet",
|
||||
"shizukuPretendToBeGooglePlay": "Indstil Google Play som installationskilde (hvis Shizuku bruges)",
|
||||
"useSystemFont": "Brug systemskrifttype",
|
||||
"useVersionCodeAsOSVersion": "Brug app versionKode som OS-registreret version",
|
||||
"requestHeader": "Anmod overskrift",
|
||||
"useVersionCodeAsOSVersion": "Brug app-versionKode som OS-registreret version",
|
||||
"requestHeader": "Anmodningsheader",
|
||||
"useLatestAssetDateAsReleaseDate": "Brug seneste ressourceupload som udgivelsesdato",
|
||||
"defaultPseudoVersioningMethod": "Standard pseudo-versioneringsmetode",
|
||||
"partialAPKHash": "Delvis APK-hash",
|
||||
@@ -313,12 +311,14 @@
|
||||
"selfHostedNote": "Rullemenuen \"{}\" kan bruges til at nå selvhostede/brugerdefinerede instanser af enhver kilde.",
|
||||
"badDownload": "APK'en kunne ikke analyseres (inkompatibel eller delvis hentning)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Del nye apps med AppVerifier (hvis tilgængelig)",
|
||||
"appVerifierInstructionToast": "Del til AppVerifier, og vend tilbage hertil, når du er klar.",
|
||||
"appVerifierInstructionToast": "Del til AppVerifier, og vend tilbage, når du er klar.",
|
||||
"wiki": "Hjælp/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourcede app-konfigurationer (brug på egen risiko)",
|
||||
"crowdsourcedConfigsShort": "Crowdsourcede app-konfigurationer",
|
||||
"allowInsecure": "Tillad usikre HTTP-anmodninger",
|
||||
"stayOneVersionBehind": "Vær en version bagud i forhold til den nyeste",
|
||||
"stayOneVersionBehind": "Forbliv én version bagud den seneste",
|
||||
"refreshBeforeDownload": "Opdater app-detaljer før download",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Fjern app?",
|
||||
"other": "Fjern apps?"
|
||||
@@ -357,7 +357,7 @@
|
||||
},
|
||||
"clearedNLogsBeforeXAfterY": {
|
||||
"one": "Ryddet {n} log (før = {before}, efter = {after})",
|
||||
"other": "Ryddet {n} logs (før = {before}, efter = {after})"
|
||||
"other": "Ryddede {n} logs (før = {before}, efter = {after})"
|
||||
},
|
||||
"xAndNMoreUpdatesAvailable": {
|
||||
"one": "{} og 1 anden app har opdateringer.",
|
||||
|
@@ -32,8 +32,8 @@
|
||||
"source": "Quelle",
|
||||
"app": "App",
|
||||
"appsFromSourceAreTrackOnly": "Apps aus dieser Quelle sind nur zur Nachverfolgung.",
|
||||
"youPickedTrackOnly": "Sie haben die Option „Nur nachverfolgen“ gewählt.",
|
||||
"trackOnlyAppDescription": "Die App wird auf Aktualisierungen überwacht, aber Obtainium wird sie nicht herunterladen oder installieren.",
|
||||
"youPickedTrackOnly": "Du hast die Option „Nur nachverfolgen“ gewählt.",
|
||||
"trackOnlyAppDescription": "Die App wird auf neue verfügbare Versionen überwacht, aber Obtainium wird sie nicht herunterladen oder installieren.",
|
||||
"cancelled": "Abgebrochen",
|
||||
"appAlreadyAdded": "App bereits hinzugefügt",
|
||||
"alreadyUpToDateQuestion": "App bereits auf dem neuesten Stand?",
|
||||
@@ -85,8 +85,8 @@
|
||||
"filter": "Filter",
|
||||
"filterApps": "Apps filtern",
|
||||
"appName": "App-Name",
|
||||
"author": "Autor",
|
||||
"upToDateApps": "Apps mit aktueller Version",
|
||||
"author": "Herausgebende",
|
||||
"upToDateApps": "Apps mit aktuellster Version",
|
||||
"nonInstalledApps": "Nicht installierte Apps",
|
||||
"importExport": "Import/Export",
|
||||
"settings": "Einstellungen",
|
||||
@@ -102,22 +102,22 @@
|
||||
"searchX": "{} suchen",
|
||||
"noResults": "Keine Ergebnisse gefunden",
|
||||
"importX": "{} importieren",
|
||||
"importedAppsIdDisclaimer": "Importierte Apps werden manchmal fälschlicherweise als „Nicht installiert“ angezeigt. Um dies zu beheben, installieren Sie sie erneut über Obtainium. Dies hat keine Auswirkungen auf App-Daten. Es betrifft nur URL- und Drittanbieter-Importmethoden.",
|
||||
"importedAppsIdDisclaimer": "Importierte Apps werden manchmal fälschlicherweise als „Nicht installiert“ angezeigt. Um dies zu beheben, installiere sie erneut über Obtainium. Dies hat keine Auswirkungen auf App-Daten. Es betrifft nur URL- und Drittanbieter-Importmethoden.",
|
||||
"importErrors": "Importfehler",
|
||||
"importedXOfYApps": "{} von {} Apps importiert.",
|
||||
"followingURLsHadErrors": "Bei folgenden URLs traten Fehler auf:",
|
||||
"selectURL": "URL auswählen",
|
||||
"selectURLs": "URLs auswählen",
|
||||
"pick": "Auswählen",
|
||||
"theme": "Theme",
|
||||
"theme": "Design",
|
||||
"dark": "Dunkel",
|
||||
"light": "Hell",
|
||||
"followSystem": "System folgen",
|
||||
"followSystemThemeExplanation": "Das Folgen des Systemthemes ist unter Android < 10 nur mit Hilfe von Drittanbieterapps möglich",
|
||||
"useBlackTheme": "Pure Black Dark Theme verwenden",
|
||||
"followSystem": "Systemstandard",
|
||||
"followSystemThemeExplanation": "Das Abrufen des Systemdesigns ist unter Android < 10 nur mit Hilfe von Drittanbieterapps möglich",
|
||||
"useBlackTheme": "Rein schwarzen Hintergrund verwenden",
|
||||
"appSortBy": "App sortieren nach",
|
||||
"authorName": "Autor/Name",
|
||||
"nameAuthor": "Name/Autor",
|
||||
"authorName": "Hrsg./Name",
|
||||
"nameAuthor": "Name/Hrsg.",
|
||||
"asAdded": "Wie hinzugefügt",
|
||||
"appSortOrder": "App sortieren nach",
|
||||
"ascending": "Aufsteigend",
|
||||
@@ -138,30 +138,30 @@
|
||||
"obtainiumExportHyphenatedLowercase": "Obtainium-Export",
|
||||
"pickAnAPK": "APK auswählen",
|
||||
"appHasMoreThanOnePackage": "{} verfügt über mehr als ein Paket:",
|
||||
"deviceSupportsXArch": "Ihr Gerät unterstützt die CPU-Architektur {}.",
|
||||
"deviceSupportsFollowingArchs": "Ihr Gerät unterstützt die folgenden CPU-Architekturen:",
|
||||
"deviceSupportsXArch": "Dein Gerät unterstützt die CPU-Architektur {}.",
|
||||
"deviceSupportsFollowingArchs": "Dein Gerät unterstützt die folgenden CPU-Architekturen:",
|
||||
"warning": "Warnung",
|
||||
"sourceIsXButPackageFromYPrompt": "Die App-Quelle ist '{}', aber das Release-Paket stammt von '{}'. Fortfahren?",
|
||||
"updatesAvailable": "Aktualisierungen verfügbar",
|
||||
"updatesAvailableNotifDescription": "Benachrichtigt den Nutzer, dass Aktualisierungen für eine oder mehrere von Obtainium verfolgte Apps verfügbar sind",
|
||||
"updatesAvailableNotifDescription": "Benachrichtigt, wenn Aktualisierungen für eine oder mehrere von Obtainium verfolgte Apps verfügbar sind",
|
||||
"noNewUpdates": "Keine neuen Aktualisierungen.",
|
||||
"xHasAnUpdate": "{} hat eine Aktualisierung.",
|
||||
"appsUpdated": "App wurde aktualisiert",
|
||||
"appsNotUpdated": "Aktualisierung der Apps fehlgeschlagen",
|
||||
"appsUpdatedNotifDescription": "Benachrichtigt den Benutzer, dass Aktualisierungen für eine oder mehrere Apps im Hintergrund durchgeführt wurden",
|
||||
"appsUpdatedNotifDescription": "Benachrichtigt, wenn 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",
|
||||
"errorCheckingUpdatesNotifDescription": "Benachrichtigt, wenn die Prüfung der Hintergrundaktualisierung fehlgeschlagen ist",
|
||||
"appsRemoved": "Apps entfernt",
|
||||
"appsRemovedNotifDescription": "Benachrichtigt den Benutzer, dass eine oder mehrere Apps aufgrund von Fehlern beim Laden entfernt wurden",
|
||||
"appsRemovedNotifDescription": "Benachrichtigt, wenn eine oder mehrere Apps aufgrund von Fehlern beim Laden entfernt wurden",
|
||||
"xWasRemovedDueToErrorY": "{} wurde aufgrund des folgenden Fehlers entfernt: {}",
|
||||
"completeAppInstallation": "App-Installation abschließen",
|
||||
"obtainiumMustBeOpenToInstallApps": "Obtainium muss geöffnet sein, um Apps zu installieren",
|
||||
"completeAppInstallationNotifDescription": "Aufforderung an den Benutzer, zu Obtainium zurückzukehren, um die Installation einer App abzuschließen",
|
||||
"completeAppInstallationNotifDescription": "Aufforderung zu Obtainium zurückzukehren, um die Installation einer App abzuschließen",
|
||||
"checkingForUpdates": "Nach Aktualisierungen suchen",
|
||||
"checkingForUpdatesNotifDescription": "Vorübergehende Benachrichtigung, die bei der Suche nach Aktualisierungen angezeigt wird",
|
||||
"pleaseAllowInstallPerm": "Bitte erlauben Sie Obtainium die Installation von Apps",
|
||||
"pleaseAllowInstallPerm": "Bitte erlaube Obtainium die Installation von Apps",
|
||||
"trackOnly": "Nur nachverfolgen",
|
||||
"errorWithHttpStatusCode": "Fehler {}",
|
||||
"versionCorrectionDisabled": "Versionskorrektur deaktiviert (Plugin scheint nicht zu funktionieren)",
|
||||
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Es wurde keine App mit dieser ID oder diesem Namen gefunden",
|
||||
"reposHaveMultipleApps": "Repos können mehrere Apps enthalten",
|
||||
"fdroidThirdPartyRepo": "F-Droid-Drittanbieter-Repo",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Steam-Chat",
|
||||
"install": "Installieren",
|
||||
"markInstalled": "Als installiert markieren",
|
||||
"update": "Aktualisieren",
|
||||
@@ -192,7 +190,7 @@
|
||||
"downloadX": "{} herunterladen",
|
||||
"downloadedX": "{} heruntergeladen",
|
||||
"releaseAsset": "Release-Asset",
|
||||
"downloadNotifDescription": "Benachrichtigt den Nutzer über den Fortschritt beim Herunterladen einer App",
|
||||
"downloadNotifDescription": "Zeigt den Fortschritt beim Herunterladen einer App",
|
||||
"noAPKFound": "Keine APK gefunden",
|
||||
"noVersionDetection": "Keine Versionserkennung",
|
||||
"categorize": "Kategorisieren",
|
||||
@@ -225,7 +223,7 @@
|
||||
"autoApkFilterByArch": "Nach Möglichkeit versuchen, APKs nach CPU-Architektur zu filtern",
|
||||
"overrideSource": "Quelle überschreiben",
|
||||
"dontShowAgain": "Nicht noch einmal anzeigen",
|
||||
"dontShowTrackOnlyWarnings": "Warnung für 'Nur nachverfolgen' nicht anzeigen",
|
||||
"dontShowTrackOnlyWarnings": "Warnung für „Nur nachverfolgen“ nicht anzeigen",
|
||||
"dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen",
|
||||
"moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der App-Ansicht verschieben",
|
||||
"gitlabPATLabel": "Persönlicher Zugangstoken für GitLab",
|
||||
@@ -233,7 +231,7 @@
|
||||
"requiresCredentialsInSettings": "{}: Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
||||
"checkOnStart": "Einmalig beim Start überprüfen",
|
||||
"tryInferAppIdFromCode": "Versuchen, die App-ID aus dem Quellcode zu ermitteln",
|
||||
"removeOnExternalUninstall": "Automatisches Entfernen von extern deinstallierten Apps",
|
||||
"removeOnExternalUninstall": "Extern deinstallierte Apps automatische entfernen",
|
||||
"pickHighestVersionCode": "Automatische Auswahl des APK mit höchstem Versionscode",
|
||||
"checkUpdateOnDetailPage": "Nach Aktualisierungen suchen, wenn eine App-Detailseite geöffnet wird",
|
||||
"disablePageTransitions": "Animationen für Seitenübergänge deaktivieren",
|
||||
@@ -243,26 +241,26 @@
|
||||
"addInfoInSettings": "Diese Information in den Einstellungen hinzufügen.",
|
||||
"githubSourceNote": "Die GitHub-Ratenbegrenzung kann mit einem API-Schlüssel umgangen werden.",
|
||||
"sortByLastLinkSegment": "Nur nach dem letzten Teil des Links sortieren",
|
||||
"filterReleaseNotesByRegEx": "Versionshinweise nach regulärem Ausdruck filtern",
|
||||
"filterReleaseNotesByRegEx": "Versionshinweise nach regulärem Ausdruck\nfiltern",
|
||||
"customLinkFilterRegex": "Benutzerdefinierter APK-Linkfilter durch regulären Ausdruck (Standard '.apk$')",
|
||||
"appsPossiblyUpdated": "App-Aktualisierungen wurden versucht",
|
||||
"appsPossiblyUpdatedNotifDescription": "Benachrichtigt den Benutzer, dass Aktualisierungen für eine oder mehrere Apps möglicherweise im Hintergrund durchgeführt wurden",
|
||||
"xWasPossiblyUpdatedToY": "{} wurde möglicherweise aktualisiert auf {}.",
|
||||
"appsPossiblyUpdatedNotifDescription": "Benachrichtigt, dass möglicherweise eine oder mehrere Apps im Hintergrund aktualisiert wurden",
|
||||
"xWasPossiblyUpdatedToY": "{} wurde eventuell auf Version {} aktualisiert.",
|
||||
"enableBackgroundUpdates": "Hintergrundaktualisierungen aktivieren",
|
||||
"backgroundUpdateReqsExplanation": "Die Hintergrundaktualisierung ist möglicherweise nicht für alle Apps möglich.",
|
||||
"backgroundUpdateReqsExplanation": "Die Hintergrundaktualisierung ist unter Umständen nicht für alle Apps möglich.",
|
||||
"backgroundUpdateLimitsExplanation": "Der Erfolg einer Hintergrundinstallation kann nur festgestellt werden, wenn Obtainium geöffnet wird.",
|
||||
"verifyLatestTag": "„Latest“-Tag überprüfen",
|
||||
"intermediateLinkRegex": "Filter für einen „Zwischen“-Link, der zuerst besucht werden soll",
|
||||
"filterByLinkText": "Links durch Linktext filtern",
|
||||
"intermediateLinkNotFound": "„Zwischen“-Link nicht gefunden",
|
||||
"intermediateLink": "„Zwischen“-Link",
|
||||
"exemptFromBackgroundUpdates": "Ausschluss von Hintergrundaktualisierungen (falls aktiviert)",
|
||||
"bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen deaktivieren, wenn kein WLAN vorhanden ist",
|
||||
"bgUpdatesWhileChargingOnly": "Hintergrundaktualisierungen deaktivieren, wenn nicht geladen wird",
|
||||
"exemptFromBackgroundUpdates": "Von Hintergrundaktualisierungen (falls aktiviert) ausschließen",
|
||||
"bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen nur im WLAN ausführen",
|
||||
"bgUpdatesWhileChargingOnly": "Hintergrundaktualisierungen nur ausführen, während das Gerät geladen wird",
|
||||
"autoSelectHighestVersionCode": "Automatisch höchste APK-Version auswählen",
|
||||
"versionExtractionRegEx": "Versionsextraktion per RegEx",
|
||||
"trimVersionString": "Versionszeichenfolge mit RegEx kürzen",
|
||||
"matchGroupToUseForX": "Zu verwendende Abgleichsgruppe für „{}“",
|
||||
"matchGroupToUseForX": "Zu verwendende Abgleichsgruppe für\n„{}“",
|
||||
"matchGroupToUse": "Zu verwendende Gruppe abgleichen",
|
||||
"highlightTouchTargets": "Weniger offensichtliche Touch-Ziele hervorheben",
|
||||
"pickExportDir": "Export-Verzeichnis wählen",
|
||||
@@ -270,7 +268,7 @@
|
||||
"includeSettings": "Einstellungen einbeziehen",
|
||||
"filterVersionsByRegEx": "Versionen nach regulären Ausdrücken filtern",
|
||||
"trySelectingSuggestedVersionCode": "Versuchen, den vorgeschlagenen APK-Versionscode auszuwählen",
|
||||
"dontSortReleasesList": "Freigaberelease von der API ordern",
|
||||
"dontSortReleasesList": "Releases-Sortierung der API beibehalten",
|
||||
"reverseSort": "Umgekehrtes Sortieren",
|
||||
"takeFirstLink": "Ersten Link verwenden",
|
||||
"skipSort": "Sortieren überspringen",
|
||||
@@ -294,12 +292,12 @@
|
||||
"parallelDownloads": "Parallele Downloads erlauben",
|
||||
"useShizuku": "Shizuku oder Sui zur Installation verwenden",
|
||||
"shizukuBinderNotFound": "Kompatibler Shizuku-Dienst 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)",
|
||||
"shizukuOld": "Veraltete Shizuku-Version (< 11) - bitte aktualisiere sie",
|
||||
"shizukuOldAndroidWithADB": "Shizuku läuft auf Android < 8.1 mit ADB - aktualisiere die Android-Version oder verwende stattdessen Sui",
|
||||
"shizukuPretendToBeGooglePlay": "(Mittels Shizuku) Google Play als Installationsquelle registrieren",
|
||||
"useSystemFont": "Systemschriftart verwenden",
|
||||
"useVersionCodeAsOSVersion": "App-Version als erkannte Version vom Betriebssystem verwenden",
|
||||
"requestHeader": "Kopfzeile anfordern",
|
||||
"useVersionCodeAsOSVersion": "Versionscode (versionCode) als erkannte Version vom Betriebssystem verwenden",
|
||||
"requestHeader": "Kopfzeile („Header“) anfordern",
|
||||
"useLatestAssetDateAsReleaseDate": "Letzten Asset-Upload als Veröffentlichungsdatum verwenden",
|
||||
"defaultPseudoVersioningMethod": "Standardmäßiges Verfahren zur Pseudo-Versionierung",
|
||||
"partialAPKHash": "Partieller APK-Hash",
|
||||
@@ -311,29 +309,31 @@
|
||||
"invertRegEx": "Regulären Ausdruck invertieren",
|
||||
"note": "Hinweis",
|
||||
"selfHostedNote": "Das „{}“-Drop-down-Menü kann verwendet werden, um selbst gehostete/angepasste Instanzen einer beliebigen Quelle zu erreichen.",
|
||||
"badDownload": "Die APK konnte nicht geparst werden (inkompatibler oder teilweiser Download)",
|
||||
"badDownload": "Die APK konnte nicht gelesen werden (inkompatibler oder unfertiger 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.",
|
||||
"appVerifierInstructionToast": "Teile die Daten mit AppVerifier und kehre im Anschluss hierher zurück.",
|
||||
"wiki": "Hilfe/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App-Konfigurationen (Verwendung auf eigene Gefahr)",
|
||||
"crowdsourcedConfigsShort": "Crowdsourced App-Konfigurationen",
|
||||
"allowInsecure": "Unsichere HTTP-Anfragen zulassen",
|
||||
"stayOneVersionBehind": "Eine Version hinter der neuesten Version bleiben",
|
||||
"refreshBeforeDownload": "App-Details vor dem Download aktualisieren",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "App entfernen?",
|
||||
"other": "Apps entfernen?"
|
||||
},
|
||||
"tooManyRequestsTryAgainInMinutes": {
|
||||
"one": "Zu viele Anfragen (Rate begrenzt) – versuchen Sie es in {} Minute erneut",
|
||||
"other": "Zu viele Anfragen (Rate begrenzt) – versuchen Sie es in {} Minuten erneut"
|
||||
"one": "Zu viele Anfragen (Rate begrenzt) – versuche es in {} Minute erneut",
|
||||
"other": "Zu viele Anfragen (Rate begrenzt) – versuche es in {} Minuten erneut"
|
||||
},
|
||||
"bgUpdateGotErrorRetryInMinutes": {
|
||||
"one": "Bei der Aktualisierungsprüfung im Hintergrund wurde ein {} festgestellt, eine erneute Prüfung wird in {} Minute geplant",
|
||||
"other": "Bei der Aktualisierungsprüfung im Hintergrund wurde ein {} festgestellt, eine erneute Prüfung wird in {} Minuten geplant"
|
||||
},
|
||||
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
|
||||
"one": "Die Hintergrundaktualisierungsprüfung fand {} Aktualisierung – benachrichtigt den Benutzer, falls erforderlich",
|
||||
"other": "Die Hintergrundaktualisierungsprüfung fand {} Aktualisierungen – benachrichtigt den Benutzer, falls erforderlich"
|
||||
"one": "Die Aktualisierungsprüfung fand {} Aktualisierung – benachrichtigt, falls erforderlich",
|
||||
"other": "Die Aktualisierungsprüfung fand {} Aktualisierungen – benachrichtigt, falls erforderlich"
|
||||
},
|
||||
"apps": {
|
||||
"one": "{} App",
|
||||
@@ -360,8 +360,8 @@
|
||||
"other": "{n} Logs gelöscht (vorher = {before}, nachher = {after})"
|
||||
},
|
||||
"xAndNMoreUpdatesAvailable": {
|
||||
"one": "{} und 1 weitere App haben Aktualisierungen.",
|
||||
"other": "{} und {} weitere Apps haben Aktualisierungen."
|
||||
"one": "{} und 1 weitere App können aktualisiert werden.",
|
||||
"other": "{} und {} weitere Apps können aktualisiert werden."
|
||||
},
|
||||
"xAndNMoreUpdatesInstalled": {
|
||||
"one": "{} und 1 weitere App wurden aktualisiert.",
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Neniu apo estas trovita kun tiu identigilo aŭ nomo",
|
||||
"reposHaveMultipleApps": "Deponejoj povas enhavi plurajn apojn",
|
||||
"fdroidThirdPartyRepo": "Tria deponejo de F-Droid",
|
||||
"steamMobile": "Telefona Steam",
|
||||
"steamChat": "Steam Babilejo",
|
||||
"install": "Instali",
|
||||
"markInstalled": "Marki kiel instalita",
|
||||
"update": "Ĝisdatigi",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
|
||||
"allowInsecure": "Allow insecure HTTP requests",
|
||||
"stayOneVersionBehind": "Stay one version behind latest",
|
||||
"refreshBeforeDownload": "Refresh app details before download",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Forigi la aplikaĵon?",
|
||||
"other": "Forigi la aplikaĵojn?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "No App was found with that ID or Name",
|
||||
"reposHaveMultipleApps": "Repos may contain multiple Apps",
|
||||
"fdroidThirdPartyRepo": "F-Droid Third-Party Repo",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Install",
|
||||
"markInstalled": "Mark Installed",
|
||||
"update": "Update",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
|
||||
"allowInsecure": "Allow insecure HTTP requests",
|
||||
"stayOneVersionBehind": "Stay one version behind latest",
|
||||
"refreshBeforeDownload": "Refresh app details before download",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Remove App?",
|
||||
"other": "Remove Apps?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "No se han encontrado aplicaciones con ese ID o nombre",
|
||||
"reposHaveMultipleApps": "Los repositorios pueden contener varias aplicaciones",
|
||||
"fdroidThirdPartyRepo": "Repositorio de terceros F-Droid",
|
||||
"steamMobile": "Steam para móviles",
|
||||
"steamChat": "Chat de Steam",
|
||||
"install": "Instalar",
|
||||
"markInstalled": "Marcar como instalada",
|
||||
"update": "Actualizar",
|
||||
@@ -260,10 +258,10 @@
|
||||
"bgUpdatesOnWiFiOnly": "Deshabilitar las actualizaciones en segundo plano sin WiFi",
|
||||
"bgUpdatesWhileChargingOnly": "Desactiva las actualizaciones en segundo plano cuando no estés cargando",
|
||||
"autoSelectHighestVersionCode": "Auto selección del paquete APK con versión más reciente",
|
||||
"versionExtractionRegEx": "Versión de extracción regex",
|
||||
"versionExtractionRegEx": "Versión de extracción RegEx",
|
||||
"trimVersionString": "Recortar cadena de versión con RegEx",
|
||||
"matchGroupToUseForX": "Grupo de coincidencia a utilizar para \"{}\"",
|
||||
"matchGroupToUse": "Grupo a usar para versión de extracción regex",
|
||||
"matchGroupToUse": "Grupo a usar para versión de extracción RegEx",
|
||||
"highlightTouchTargets": "Resaltar objetivos menos obvios",
|
||||
"pickExportDir": "Directorio para exportar",
|
||||
"autoExportOnChanges": "Auto exportar cuando haya cambios",
|
||||
@@ -277,7 +275,7 @@
|
||||
"debugMenu": "Menu Depurar",
|
||||
"bgTaskStarted": "Iniciada tarea en segundo plano; revise los registros.",
|
||||
"runBgCheckNow": "Ejecutar verficiación de actualizaciones en segundo plano",
|
||||
"versionExtractWholePage": "Aplicar la versión de extracción regex a la página entera",
|
||||
"versionExtractWholePage": "Aplicar la versión de extracción RegEx a la página entera",
|
||||
"installing": "Instalando",
|
||||
"skipUpdateNotifications": "No notificar sobre actualizaciones",
|
||||
"updatesAvailableNotifChannel": "Actualizaciones disponibles",
|
||||
@@ -312,13 +310,15 @@
|
||||
"note": "Nota",
|
||||
"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 aplicaciones nuevas con AppVerifier (si está disponible)",
|
||||
"appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.",
|
||||
"beforeNewInstallsShareToAppVerifier": "Compartir aplicaciones nuevas con AppVerifier (si está instalado)",
|
||||
"appVerifierInstructionToast": "Compartir con AppVerifier y vuelver aquí cuando esté listo.",
|
||||
"wiki": "Ayuda/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use bajo su responsabilidad)",
|
||||
"crowdsourcedConfigsShort": "Configuración de aplicaciones por crowdsourcing",
|
||||
"allowInsecure": "Permitir peticiones HTTP inseguras",
|
||||
"stayOneVersionBehind": "Mantenerse una versión por detrás de la última",
|
||||
"refreshBeforeDownload": "Actualiza los datos de la aplicación antes de descargarla",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "¿Eliminar aplicación?",
|
||||
"other": "¿Eliminar aplicaciones?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "هیچ برنامه ای با آن شناسه یا نام یافت نشد",
|
||||
"reposHaveMultipleApps": "مخازن ممکن است شامل چندین برنامه باشد",
|
||||
"fdroidThirdPartyRepo": "مخازن شخص ثالث F-Droid",
|
||||
"steamMobile": "استیم موبایل",
|
||||
"steamChat": "چت استیم",
|
||||
"install": "نصب",
|
||||
"markInstalled": "علامت گذاری به عنوان نصب شده",
|
||||
"update": "به روز رسانی",
|
||||
@@ -213,7 +211,7 @@
|
||||
"uninstallFromDevice": "حذف نصب از دستگاه",
|
||||
"onlyWorksWithNonVersionDetectApps": "فقط برای برنامههایی کار میکند که تشخیص نسخه غیرفعال است.",
|
||||
"releaseDateAsVersion": "از تاریخ انتشار به عنوان نسخه استفاده کنید",
|
||||
"releaseTitleAsVersion": "Use release title as version string",
|
||||
"releaseTitleAsVersion": "از عنوان انتشار به عنوان رشته نسخه استفاده کنید",
|
||||
"releaseDateAsVersionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند، اما تاریخ انتشار در دسترس است.",
|
||||
"changes": "تغییرات",
|
||||
"releaseDate": "تاریخ انتشار",
|
||||
@@ -258,7 +256,7 @@
|
||||
"intermediateLink": "پیوند میانی",
|
||||
"exemptFromBackgroundUpdates": "معاف از بهروزرسانیهای پسزمینه (در صورت فعال بودن)",
|
||||
"bgUpdatesOnWiFiOnly": "بهروزرسانیهای پسزمینه را در صورت عدم اتصال به WiFi غیرفعال کنید",
|
||||
"bgUpdatesWhileChargingOnly": "Disable background updates when not charging",
|
||||
"bgUpdatesWhileChargingOnly": "بهروزرسانیهای پسزمینه را هنگام شارژ نشدن غیرفعال کنید",
|
||||
"autoSelectHighestVersionCode": "انتخاب خودکار بالاترین نسخه کد APK",
|
||||
"versionExtractionRegEx": "نسخه استخراج RegEx",
|
||||
"trimVersionString": "برش رشته نسخه با RegEx",
|
||||
@@ -315,10 +313,12 @@
|
||||
"beforeNewInstallsShareToAppVerifier": "اشتراکگذاری برنامههای جدید با AppVerifier (در صورت وجود)",
|
||||
"appVerifierInstructionToast": "در AppVerifier به اشتراک بگذارید، سپس پس از آماده شدن به اینجا برگردید.",
|
||||
"wiki": "راهنما/ویکی",
|
||||
"crowdsourcedConfigsLabel": "تنظیمات برنامه Crowdsourced (با مسئولیت خود استفاده کنید)",
|
||||
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
|
||||
"crowdsourcedConfigsLabel": "تنظیمات برنامه های مشارکت جمعی (با مسئولیت خود استفاده کنید)",
|
||||
"crowdsourcedConfigsShort": "تنظیمات برنامه های مشارکت جمعی",
|
||||
"allowInsecure": "درخواست های HTTP ناامن را مجاز کنید",
|
||||
"stayOneVersionBehind": "Stay one version behind latest",
|
||||
"stayOneVersionBehind": "یک نسخه از آخرین نسخه پشت سر بگذارید",
|
||||
"refreshBeforeDownload": "قبل از دانلود، جزئیات برنامه را بازخوانی کنید",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "برنامه حذف شود؟",
|
||||
"other": "برنامه ها حذف شوند؟"
|
||||
|
@@ -25,11 +25,11 @@
|
||||
"standard": "Standard",
|
||||
"custom": "Personnalisé",
|
||||
"useMaterialYou": "Utiliser Material You",
|
||||
"githubStarredRepos": "Dépôts étoilés GitHub",
|
||||
"githubStarredRepos": "dépôts étoilés GitHub",
|
||||
"uname": "Nom d'utilisateur",
|
||||
"wrongArgNum": "Nombre incorrect des arguments fournis",
|
||||
"xIsTrackOnly": "{} en Suivi uniquement",
|
||||
"source": "Source",
|
||||
"source": "source",
|
||||
"app": "Application",
|
||||
"appsFromSourceAreTrackOnly": "Les applications de cette source sont en 'Suivi uniquement'.",
|
||||
"youPickedTrackOnly": "Vous avez sélectionné l'option 'Suivi uniquement'.",
|
||||
@@ -60,7 +60,7 @@
|
||||
"deselectX": "Déselectionner {}",
|
||||
"xWillBeRemovedButRemainInstalled": "{} sera supprimée d'Obtainium mais restera installée sur l'appareil.",
|
||||
"removeSelectedAppsQuestion": "Supprimer les applications sélectionnées ?",
|
||||
"removeSelectedApps": "Les applications sélectionnées ont été supprimées",
|
||||
"removeSelectedApps": "Supprimer les applications sélectionnées",
|
||||
"updateX": "Mettre à jour {}",
|
||||
"installX": "Installer {}",
|
||||
"markXTrackOnlyAsUpdated": "Marquer {}\n(Suivi uniquement)\ncomme étant à jour",
|
||||
@@ -78,7 +78,7 @@
|
||||
"customLinkMessage": "Ces liens fonctionnent sur les appareils sur lesquels Obtainium est installé",
|
||||
"shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML",
|
||||
"shareSelectedAppURLs": "Partager les URL des applications sélectionnées",
|
||||
"resetInstallStatus": "L'état d'installation des applications a été réinitialisé",
|
||||
"resetInstallStatus": "Réinitialiser l'état d'installation des applications",
|
||||
"more": "Plus",
|
||||
"removeOutdatedFilter": "Supprimer le filtre des applications obsolètes",
|
||||
"showOutdatedOnly": "Afficher uniquement les applications obsolètes",
|
||||
@@ -91,15 +91,15 @@
|
||||
"importExport": "Importer/exporter",
|
||||
"settings": "Paramètres",
|
||||
"exportedTo": "Exporté vers {}",
|
||||
"obtainiumExport": "Exporter Obtainium",
|
||||
"obtainiumExport": "Exporter la configuration d'Obtainium",
|
||||
"invalidInput": "Entrée invalide",
|
||||
"importedX": "Importé {}",
|
||||
"obtainiumImport": "Importer sur Obtainium",
|
||||
"obtainiumImport": "Importer la configuration sur Obtainium",
|
||||
"importFromURLList": "Importer depuis une liste d'URL",
|
||||
"searchQuery": "Requête de recherche",
|
||||
"appURLList": "Liste d'URL de l'application",
|
||||
"line": "Ligne",
|
||||
"searchX": "Rechercher {}",
|
||||
"searchX": "Sélectionner {}",
|
||||
"noResults": "Aucun résultat",
|
||||
"importX": "Importation de {}",
|
||||
"importedAppsIdDisclaimer": "Les applications importées peuvent s'afficher de manière incorrecte comme étant \"Non installées\".\nPour résoudre ce problème, réinstallez-les via Obtainium.\nCela n'affectera pas les données des applications.\n\nN'affecte que les méthodes d'importation d'URL et par des tiers.",
|
||||
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom",
|
||||
"reposHaveMultipleApps": "Les dépôts peuvent contenir plusieurs applications",
|
||||
"fdroidThirdPartyRepo": "Dépôt tiers F-Droid",
|
||||
"steamMobile": "Application mobile Steam",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Installer",
|
||||
"markInstalled": "Marquer comme étant installé",
|
||||
"update": "Mettre à jour",
|
||||
@@ -315,10 +313,12 @@
|
||||
"beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)",
|
||||
"appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque tout est prêt.",
|
||||
"wiki": "Aide/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Configurations d'applications par la communauté (à utiliser à vos risques et périls)",
|
||||
"crowdsourcedConfigsShort": "Configurations d'applications par la communauté",
|
||||
"crowdsourcedConfigsLabel": "Configuration d'applis communautaires (à utiliser à vos risques et périls)",
|
||||
"crowdsourcedConfigsShort": "Applis communautaires",
|
||||
"allowInsecure": "Autoriser les requêtes HTTP non sécurisées",
|
||||
"stayOneVersionBehind": "Rester à une version de la dernière",
|
||||
"refreshBeforeDownload": "Actualiser les détails de l'application avant de la télécharger",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Supprimer l'application ?",
|
||||
"other": "Supprimer les applications ?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Nem található alkalmazás ezzel az azonosítóval vagy névvel",
|
||||
"reposHaveMultipleApps": "A tárolók több alkalmazást is tartalmazhatnak",
|
||||
"fdroidThirdPartyRepo": "F-Droid harmadik féltől származó tároló",
|
||||
"steamMobile": "Steam Mobil",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Telepítés",
|
||||
"markInstalled": "Telepítettnek jelölés",
|
||||
"update": "Frissítés",
|
||||
@@ -215,7 +213,7 @@
|
||||
"releaseDateAsVersion": "Használja a kiadás dátumát verzió-karakterláncként",
|
||||
"releaseTitleAsVersion": "Használja a kiadás címét verzió-karakterláncként",
|
||||
"releaseDateAsVersionExplanation": "Ezt a beállítást csak olyan alkalmazásoknál szabad használni, ahol a verzió-érzékelés nem működik megfelelően, de elérhető a kiadás dátuma.",
|
||||
"changes": "Változások",
|
||||
"changes": "Változáslista",
|
||||
"releaseDate": "Kiadás dátuma",
|
||||
"importFromURLsInFile": "Importálás fájlban található webcímből (pl. OPML)",
|
||||
"versionDetectionExplanation": "A verzió-karakterlánc egyeztetése az rendszer által érzékelt verzióval",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
|
||||
"allowInsecure": "Nem biztonságos HTTP-kérések engedélyezése",
|
||||
"stayOneVersionBehind": "Maradjon egy verzióval a legújabb mögött",
|
||||
"refreshBeforeDownload": "Az alkalmazás adatainak frissítése a letöltés előtt",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Eltávolítja az alkalmazást?",
|
||||
"other": "Eltávolítja az alkalmazásokat?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Tidak ada aplikasi yang ditemukan dengan ID atau nama tersebut",
|
||||
"reposHaveMultipleApps": "Repositori dapat berisi beberapa aplikasi",
|
||||
"fdroidThirdPartyRepo": "Repositori pihak ketiga F-Droid",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Obrolan Steam",
|
||||
"install": "Pasang",
|
||||
"markInstalled": "Tandai terpasang",
|
||||
"update": "perbarui",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Konfigurasi Aplikasi Crowdsourced",
|
||||
"allowInsecure": "Izinkan permintaan HTTP yang tidak aman",
|
||||
"stayOneVersionBehind": "Tetap satu versi di belakang versi terbaru",
|
||||
"refreshBeforeDownload": "Segarkan detail aplikasi sebelum mengunduh",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Hapus aplikasi?",
|
||||
"other": "Hapus aplikasi?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Non è stata trovata alcuna app con quell'ID o nome",
|
||||
"reposHaveMultipleApps": "I repository possono contenere più app",
|
||||
"fdroidThirdPartyRepo": "Repository F-Droid di terze parti",
|
||||
"steamMobile": "Mobile a vapore",
|
||||
"steamChat": "Chat di vapore",
|
||||
"install": "Installa",
|
||||
"markInstalled": "Contrassegna come installata",
|
||||
"update": "Aggiorna",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Configurazioni di app in crowdsourcing",
|
||||
"allowInsecure": "Consentire le richieste HTTP non sicure",
|
||||
"stayOneVersionBehind": "Rimanere una versione indietro rispetto alla più recente",
|
||||
"refreshBeforeDownload": "Aggiornare i dettagli dell'app prima del download",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Rimuovere l'app?",
|
||||
"other": "Rimuovere le app?"
|
||||
|
@@ -147,21 +147,21 @@
|
||||
"noNewUpdates": "新しいアップデートはありません",
|
||||
"xHasAnUpdate": "{} のアップデートが利用可能です。",
|
||||
"appsUpdated": "アプリをアップデートしました",
|
||||
"appsNotUpdated": "アプリケーションの更新に失敗",
|
||||
"appsNotUpdated": "アプリのアップデートに失敗しました",
|
||||
"appsUpdatedNotifDescription": "1つまたは複数のAppのアップデートがバックグラウンドで適用されたことをユーザーに通知する",
|
||||
"xWasUpdatedToY": "{} が {} にアップデートされました",
|
||||
"xWasNotUpdatedToY": "への更新に失敗しました。",
|
||||
"xWasNotUpdatedToY": "{} の {} へのアップデートに失敗しました",
|
||||
"errorCheckingUpdates": "アップデート確認中のエラー",
|
||||
"errorCheckingUpdatesNotifDescription": "バックグラウンドでのアップデート確認に失敗した際に表示される通知",
|
||||
"appsRemoved": "削除されたアプリ",
|
||||
"appsRemovedNotifDescription": "アプリの読み込み中にエラーが発生したため、1つまたは複数のアプリが削除されたことをユーザーに通知する",
|
||||
"xWasRemovedDueToErrorY": "このエラーのため、{} は削除されました: {}",
|
||||
"completeAppInstallation": "アプリのインストールを完了する",
|
||||
"obtainiumMustBeOpenToInstallApps": "アプリをインストールするにはObtainiumが開いている必要があります",
|
||||
"obtainiumMustBeOpenToInstallApps": "アプリをインストールするにはObtainiumを開く必要があります",
|
||||
"completeAppInstallationNotifDescription": "アプリのインストールを完了するために、Obtainiumに戻る必要があります",
|
||||
"checkingForUpdates": "アップデートを確認中",
|
||||
"checkingForUpdatesNotifDescription": "アップデートを確認する際に表示される一時的な通知",
|
||||
"pleaseAllowInstallPerm": "Obtainiumによるアプリのインストールを許可してください。",
|
||||
"pleaseAllowInstallPerm": "Obtainiumによるアプリのインストールを許可してください",
|
||||
"trackOnly": "追跡のみ",
|
||||
"errorWithHttpStatusCode": "エラー {}",
|
||||
"versionCorrectionDisabled": "バージョン補正無効 (プラグインが動作していません)",
|
||||
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "そのIDや名前を持つアプリは見つかりませんでした",
|
||||
"reposHaveMultipleApps": "リポジトリには複数のアプリが含まれることがあります",
|
||||
"fdroidThirdPartyRepo": "F-Droid サードパーティリポジトリ",
|
||||
"steamMobile": "Steamモバイル",
|
||||
"steamChat": "Steamチャット",
|
||||
"install": "インストール",
|
||||
"markInstalled": "インストール済みとしてマークする",
|
||||
"update": "アップデート",
|
||||
@@ -213,7 +211,7 @@
|
||||
"uninstallFromDevice": "デバイスからアンインストールする",
|
||||
"onlyWorksWithNonVersionDetectApps": "バージョン検出を無効にしているアプリにのみ動作します。",
|
||||
"releaseDateAsVersion": "リリース日をバージョンとして使用する",
|
||||
"releaseTitleAsVersion": "リリースタイトルをバージョン文字列として使用",
|
||||
"releaseTitleAsVersion": "リリースタイトルをバージョンとして使用する",
|
||||
"releaseDateAsVersionExplanation": "このオプションは、バージョン検出が正しく機能しないアプリで、リリース日が利用可能な場合にのみ使用する必要があります。",
|
||||
"changes": "変更点",
|
||||
"releaseDate": "リリース日",
|
||||
@@ -258,7 +256,7 @@
|
||||
"intermediateLink": "中間リンク",
|
||||
"exemptFromBackgroundUpdates": "バックグラウンドアップデートを行わない (有効な場合)",
|
||||
"bgUpdatesOnWiFiOnly": "WiFiを使用していない場合、バックグラウンドアップデートを無効にする",
|
||||
"bgUpdatesWhileChargingOnly": "非充電時にバックグラウンド更新を無効にする",
|
||||
"bgUpdatesWhileChargingOnly": "非充電時にバックグラウンドアップデートを無効にする",
|
||||
"autoSelectHighestVersionCode": "最も高いバージョンコードのAPKを自動で選択する",
|
||||
"versionExtractionRegEx": "バージョン抽出の正規表現",
|
||||
"trimVersionString": "正規表現でバージョン文字列をトリムする",
|
||||
@@ -318,7 +316,9 @@
|
||||
"crowdsourcedConfigsLabel": "クラウドソーシングによるアプリの設定(利用は自己責任で)",
|
||||
"crowdsourcedConfigsShort": "クラウドソーシングによるアプリの設定",
|
||||
"allowInsecure": "安全でないHTTPリクエストを許可する",
|
||||
"stayOneVersionBehind": "最新バージョンから1つ遅れ",
|
||||
"stayOneVersionBehind": "最新のバージョンから1つ前のものを使用する",
|
||||
"refreshBeforeDownload": "ダウンロード前にアプリの詳細を更新する",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "アプリを削除しますか?",
|
||||
"other": "アプリを削除しますか?"
|
||||
@@ -360,23 +360,23 @@
|
||||
"other": "{n} 個のログをクリアしました (前 = {before}, 後 = {after})"
|
||||
},
|
||||
"xAndNMoreUpdatesAvailable": {
|
||||
"one": "{} とさらに {} 個のアプリのアップデートが利用可能です。",
|
||||
"one": "{} とさらに 1 個のアプリのアップデートが利用可能です。",
|
||||
"other": "{} とさらに {} 個のアプリのアップデートが利用可能です。"
|
||||
},
|
||||
"xAndNMoreUpdatesInstalled": {
|
||||
"one": "{} とさらに {} 個のアプリがアップデートされました。",
|
||||
"one": "{} とさらに 1 個のアプリがアップデートされました。",
|
||||
"other": "{} とさらに {} 個のアプリがアップデートされました。"
|
||||
},
|
||||
"xAndNMoreUpdatesFailed": {
|
||||
"one": "更新に失敗しました。",
|
||||
"other": "アプリのアップデートに失敗しました。"
|
||||
"one": "{} とさらに 1 個のアプリのアップデートに失敗しました。",
|
||||
"other": "{} とさらに {} 個のアプリのアップデートに失敗しました。"
|
||||
},
|
||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||
"one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。",
|
||||
"other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。"
|
||||
},
|
||||
"apk": {
|
||||
"one": "{}APK",
|
||||
"other": "{}APK"
|
||||
"one": "{} APK",
|
||||
"other": "{} APK"
|
||||
}
|
||||
}
|
||||
|
382
assets/translations/ko.json
Normal file
@@ -0,0 +1,382 @@
|
||||
{
|
||||
"invalidURLForSource": "유효한 {} 앱 URL이 아닙니다",
|
||||
"noReleaseFound": "적절한 릴리스를 찾을 수 없습니다",
|
||||
"noVersionFound": "릴리스 버전을 결정할 수 없습니다",
|
||||
"urlMatchesNoSource": "URL이 알려진 소스와 일치하지 않습니다",
|
||||
"cantInstallOlderVersion": "앱의 이전 버전을 설치할 수 없습니다",
|
||||
"appIdMismatch": "다운로드된 패키지 ID가 기존 앱 ID와 일치하지 않습니다",
|
||||
"functionNotImplemented": "이 클래스는 이 기능을 구현하지 않았습니다",
|
||||
"placeholder": "플레이스홀더",
|
||||
"someErrors": "일부 오류가 발생했습니다",
|
||||
"unexpectedError": "예기치 않은 오류",
|
||||
"ok": "확인",
|
||||
"and": "그리고",
|
||||
"githubPATLabel": "GitHub 개인 액세스 토큰 (속도 제한 증가)",
|
||||
"includePrereleases": "사전 릴리스 포함",
|
||||
"fallbackToOlderReleases": "이전 릴리스로 대체",
|
||||
"filterReleaseTitlesByRegEx": "정규 표현식으로 릴리스 제목 필터링",
|
||||
"invalidRegEx": "잘못된 정규 표현식",
|
||||
"noDescription": "설명 없음",
|
||||
"cancel": "취소",
|
||||
"continue": "계속",
|
||||
"requiredInBrackets": "(필수)",
|
||||
"dropdownNoOptsError": "오류: 드롭다운에는 최소 하나의 옵션이 있어야 합니다",
|
||||
"colour": "색상",
|
||||
"standard": "표준",
|
||||
"custom": "사용자 정의",
|
||||
"useMaterialYou": "Material You 사용",
|
||||
"githubStarredRepos": "GitHub 즐겨찾기 저장소",
|
||||
"uname": "사용자 이름",
|
||||
"wrongArgNum": "잘못된 인수 수 제공",
|
||||
"xIsTrackOnly": "{}는 추적 전용입니다",
|
||||
"source": "소스",
|
||||
"app": "앱",
|
||||
"appsFromSourceAreTrackOnly": "이 소스의 앱은 '추적 전용'입니다.",
|
||||
"youPickedTrackOnly": "당신은 '추적 전용' 옵션을 선택했습니다.",
|
||||
"trackOnlyAppDescription": "앱은 업데이트를 위해 추적되지만 Obtainium은 다운로드하거나 설치할 수 없습니다.",
|
||||
"cancelled": "취소됨",
|
||||
"appAlreadyAdded": "앱이 이미 추가되었습니다",
|
||||
"alreadyUpToDateQuestion": "앱이 이미 최신 상태입니까?",
|
||||
"addApp": "앱 추가",
|
||||
"appSourceURL": "앱 소스 URL",
|
||||
"error": "오류",
|
||||
"add": "추가",
|
||||
"searchSomeSourcesLabel": "검색 (일부 소스만)",
|
||||
"search": "검색",
|
||||
"additionalOptsFor": "{}에 대한 추가 옵션",
|
||||
"supportedSources": "지원되는 소스",
|
||||
"trackOnlyInBrackets": "(추적 전용)",
|
||||
"searchableInBrackets": "(검색 가능)",
|
||||
"appsString": "앱",
|
||||
"noApps": "앱 없음",
|
||||
"noAppsForFilter": "필터에 대한 앱 없음",
|
||||
"byX": "{}에 의해",
|
||||
"percentProgress": "진행률: {}%",
|
||||
"pleaseWait": "기다려 주세요",
|
||||
"updateAvailable": "업데이트 가능",
|
||||
"notInstalled": "설치되지 않음",
|
||||
"pseudoVersion": "의사 버전",
|
||||
"selectAll": "모두 선택",
|
||||
"deselectX": "{} 선택 해제",
|
||||
"xWillBeRemovedButRemainInstalled": "{}는 Obtainium에서 제거되지만 장치에 설치된 상태로 남아 있습니다.",
|
||||
"removeSelectedAppsQuestion": "선택한 앱을 제거하시겠습니까?",
|
||||
"removeSelectedApps": "선택한 앱 제거",
|
||||
"updateX": "{} 업데이트",
|
||||
"installX": "{} 설치",
|
||||
"markXTrackOnlyAsUpdated": "{}\n(추적 전용)\n업데이트됨으로 표시",
|
||||
"changeX": "{} 변경",
|
||||
"installUpdateApps": "앱 설치/업데이트",
|
||||
"installUpdateSelectedApps": "선택한 앱 설치/업데이트",
|
||||
"markXSelectedAppsAsUpdated": "{} 선택한 앱을 업데이트됨으로 표시하시겠습니까?",
|
||||
"no": "아니요",
|
||||
"yes": "예",
|
||||
"markSelectedAppsUpdated": "선택한 앱을 업데이트됨으로 표시",
|
||||
"pinToTop": "상단에 고정",
|
||||
"unpinFromTop": "상단에서 고정 해제",
|
||||
"resetInstallStatusForSelectedAppsQuestion": "선택한 앱의 설치 상태를 재설정하시겠습니까?",
|
||||
"installStatusOfXWillBeResetExplanation": "선택한 앱의 설치 상태가 재설정됩니다.\n\n이것은 실패한 업데이트나 기타 문제로 인해 Obtainium에 표시된 앱 버전이 잘못된 경우에 도움이 될 수 있습니다.",
|
||||
"customLinkMessage": "이 링크는 Obtainium이 설치된 장치에서 작동합니다",
|
||||
"shareAppConfigLinks": "앱 구성 HTML 링크로 공유",
|
||||
"shareSelectedAppURLs": "선택한 앱 URL 공유",
|
||||
"resetInstallStatus": "설치 상태 재설정",
|
||||
"more": "더보기",
|
||||
"removeOutdatedFilter": "구식 앱 필터 제거",
|
||||
"showOutdatedOnly": "구식 앱만 표시",
|
||||
"filter": "필터",
|
||||
"filterApps": "앱 필터",
|
||||
"appName": "앱 이름",
|
||||
"author": "저자",
|
||||
"upToDateApps": "최신 상태의 앱",
|
||||
"nonInstalledApps": "설치되지 않은 앱",
|
||||
"importExport": "가져오기/내보내기",
|
||||
"settings": "설정",
|
||||
"exportedTo": "{}로 내보내기 완료",
|
||||
"obtainiumExport": "Obtainium 내보내기",
|
||||
"invalidInput": "잘못된 입력",
|
||||
"importedX": "{} 가져오기 완료",
|
||||
"obtainiumImport": "Obtainium 가져오기",
|
||||
"importFromURLList": "URL 목록에서 가져오기",
|
||||
"searchQuery": "검색 쿼리",
|
||||
"appURLList": "앱 URL 목록",
|
||||
"line": "줄",
|
||||
"searchX": "{} 검색",
|
||||
"noResults": "결과가 없습니다",
|
||||
"importX": "{} 가져오기",
|
||||
"importedAppsIdDisclaimer": "가져온 앱은 \"설치되지 않음\"으로 잘못 표시될 수 있습니다.\n이를 수정하려면 Obtainium을 통해 다시 설치하십시오.\n앱 데이터에는 영향을 미치지 않습니다.\n\nURL 및 타사 가져오기 방법에만 영향을 미칩니다.",
|
||||
"importErrors": "가져오기 오류",
|
||||
"importedXOfYApps": "{}개의 앱 중 {}개 가져오기 완료.",
|
||||
"followingURLsHadErrors": "다음 URL에 오류가 있었습니다:",
|
||||
"selectURL": "URL 선택",
|
||||
"selectURLs": "URL 선택",
|
||||
"pick": "선택",
|
||||
"theme": "테마",
|
||||
"dark": "다크",
|
||||
"light": "라이트",
|
||||
"followSystem": "시스템 따르기",
|
||||
"followSystemThemeExplanation": "시스템 테마를 따르려면 타사 애플리케이션을 사용해야 합니다",
|
||||
"useBlackTheme": "순수한 검은색 다크 테마 사용",
|
||||
"appSortBy": "앱 정렬 기준",
|
||||
"authorName": "저자/이름",
|
||||
"nameAuthor": "이름/저자",
|
||||
"asAdded": "추가된 순서대로",
|
||||
"appSortOrder": "앱 정렬 순서",
|
||||
"ascending": "오름차순",
|
||||
"descending": "내림차순",
|
||||
"bgUpdateCheckInterval": "백그라운드 업데이트 확인 간격",
|
||||
"neverManualOnly": "절대 - 수동만",
|
||||
"appearance": "외관",
|
||||
"showWebInAppView": "앱 보기에서 소스 웹페이지 표시",
|
||||
"pinUpdates": "앱 보기 상단에 업데이트 고정",
|
||||
"updates": "업데이트",
|
||||
"sourceSpecific": "소스별",
|
||||
"appSource": "앱 소스",
|
||||
"noLogs": "로그 없음",
|
||||
"appLogs": "앱 로그",
|
||||
"close": "닫기",
|
||||
"share": "공유",
|
||||
"appNotFound": "앱을 찾을 수 없습니다",
|
||||
"obtainiumExportHyphenatedLowercase": "obtainium-export",
|
||||
"pickAnAPK": "APK 선택",
|
||||
"appHasMoreThanOnePackage": "{}에는 둘 이상의 패키지가 있습니다:",
|
||||
"deviceSupportsXArch": "장치는 {} CPU 아키텍처를 지원합니다.",
|
||||
"deviceSupportsFollowingArchs": "장치는 다음 CPU 아키텍처를 지원합니다:",
|
||||
"warning": "경고",
|
||||
"sourceIsXButPackageFromYPrompt": "앱 소스는 '{}'이지만 릴리스 패키지는 '{}'에서 제공됩니다. 계속하시겠습니까?",
|
||||
"updatesAvailable": "업데이트 가능",
|
||||
"updatesAvailableNotifDescription": "Obtainium이 추적하는 하나 이상의 앱에 대한 업데이트가 있음을 사용자에게 알립니다",
|
||||
"noNewUpdates": "새로운 업데이트가 없습니다.",
|
||||
"xHasAnUpdate": "{}에 업데이트가 있습니다.",
|
||||
"appsUpdated": "앱 업데이트됨",
|
||||
"appsNotUpdated": "앱 업데이트 실패",
|
||||
"appsUpdatedNotifDescription": "백그라운드에서 하나 이상의 앱에 대한 업데이트가 적용되었음을 사용자에게 알립니다",
|
||||
"xWasUpdatedToY": "{}가 {}로 업데이트되었습니다.",
|
||||
"xWasNotUpdatedToY": "{}를 {}로 업데이트하지 못했습니다.",
|
||||
"errorCheckingUpdates": "업데이트 확인 오류",
|
||||
"errorCheckingUpdatesNotifDescription": "백그라운드 업데이트 확인이 실패할 때 표시되는 알림",
|
||||
"appsRemoved": "앱 제거됨",
|
||||
"appsRemovedNotifDescription": "로드 중 오류로 인해 하나 이상의 앱이 제거되었음을 사용자에게 알립니다",
|
||||
"xWasRemovedDueToErrorY": "{}가 다음 오류로 인해 제거되었습니다: {}",
|
||||
"completeAppInstallation": "앱 설치 완료",
|
||||
"obtainiumMustBeOpenToInstallApps": "앱을 설치하려면 Obtainium이 열려 있어야 합니다",
|
||||
"completeAppInstallationNotifDescription": "앱 설치를 완료하려면 Obtainium으로 돌아가도록 사용자에게 요청합니다",
|
||||
"checkingForUpdates": "업데이트 확인 중",
|
||||
"checkingForUpdatesNotifDescription": "업데이트 확인 시 나타나는 일시적인 알림",
|
||||
"pleaseAllowInstallPerm": "Obtainium이 앱을 설치할 수 있도록 허용해 주세요",
|
||||
"trackOnly": "추적 전용",
|
||||
"errorWithHttpStatusCode": "오류 {}",
|
||||
"versionCorrectionDisabled": "버전 수정 비활성화됨 (플러그인이 작동하지 않는 것 같습니다)",
|
||||
"unknown": "알 수 없음",
|
||||
"none": "없음",
|
||||
"never": "절대",
|
||||
"latestVersionX": "최신: {}",
|
||||
"installedVersionX": "설치됨: {}",
|
||||
"lastUpdateCheckX": "마지막 업데이트 확인: {}",
|
||||
"remove": "제거",
|
||||
"yesMarkUpdated": "예, 업데이트됨으로 표시",
|
||||
"fdroid": "F-Droid 공식",
|
||||
"appIdOrName": "앱 ID 또는 이름",
|
||||
"appId": "앱 ID",
|
||||
"appWithIdOrNameNotFound": "해당 ID 또는 이름의 앱을 찾을 수 없습니다",
|
||||
"reposHaveMultipleApps": "저장소에는 여러 앱이 포함될 수 있습니다",
|
||||
"fdroidThirdPartyRepo": "F-Droid 타사 저장소",
|
||||
"install": "설치",
|
||||
"markInstalled": "설치됨으로 표시",
|
||||
"update": "업데이트",
|
||||
"markUpdated": "업데이트됨으로 표시",
|
||||
"additionalOptions": "추가 옵션",
|
||||
"disableVersionDetection": "버전 감지 비활성화",
|
||||
"noVersionDetectionExplanation": "이 옵션은 버전 감지가 올바르게 작동하지 않는 앱에만 사용해야 합니다.",
|
||||
"downloadingX": "{} 다운로드 중",
|
||||
"downloadX": "{} 다운로드",
|
||||
"downloadedX": "{} 다운로드 완료",
|
||||
"releaseAsset": "릴리스 자산",
|
||||
"downloadNotifDescription": "앱 다운로드 진행 상황을 사용자에게 알립니다",
|
||||
"noAPKFound": "APK를 찾을 수 없습니다",
|
||||
"noVersionDetection": "버전 감지 없음",
|
||||
"categorize": "분류",
|
||||
"categories": "카테고리",
|
||||
"category": "카테고리",
|
||||
"noCategory": "카테고리 없음",
|
||||
"noCategories": "카테고리 없음",
|
||||
"deleteCategoriesQuestion": "카테고리를 삭제하시겠습니까?",
|
||||
"categoryDeleteWarning": "삭제된 카테고리의 모든 앱은 미분류로 설정됩니다.",
|
||||
"addCategory": "카테고리 추가",
|
||||
"label": "레이블",
|
||||
"language": "언어",
|
||||
"copiedToClipboard": "클립보드에 복사됨",
|
||||
"storagePermissionDenied": "저장소 권한 거부됨",
|
||||
"selectedCategorizeWarning": "이 작업은 선택한 앱의 기존 카테고리 설정을 대체합니다.",
|
||||
"filterAPKsByRegEx": "정규 표현식으로 APK 필터링",
|
||||
"removeFromObtainium": "Obtainium에서 제거",
|
||||
"uninstallFromDevice": "장치에서 제거",
|
||||
"onlyWorksWithNonVersionDetectApps": "버전 감지가 비활성화된 앱에만 작동합니다.",
|
||||
"releaseDateAsVersion": "릴리스 날짜를 버전 문자열로 사용",
|
||||
"releaseTitleAsVersion": "릴리스 제목을 버전 문자열로 사용",
|
||||
"releaseDateAsVersionExplanation": "이 옵션은 버전 감지가 올바르게 작동하지 않지만 릴리스 날짜가 있는 앱에만 사용해야 합니다.",
|
||||
"changes": "변경 사항",
|
||||
"releaseDate": "릴리스 날짜",
|
||||
"importFromURLsInFile": "파일의 URL에서 가져오기 (OPML과 같은)",
|
||||
"versionDetectionExplanation": "OS에서 감지된 버전과 버전 문자열 조정",
|
||||
"versionDetection": "버전 감지",
|
||||
"standardVersionDetection": "표준 버전 감지",
|
||||
"groupByCategory": "카테고리별 그룹화",
|
||||
"autoApkFilterByArch": "가능한 경우 CPU 아키텍처별로 APK 필터링 시도",
|
||||
"overrideSource": "소스 재정의",
|
||||
"dontShowAgain": "다시 표시하지 않기",
|
||||
"dontShowTrackOnlyWarnings": "'추적 전용' 경고 표시 안 함",
|
||||
"dontShowAPKOriginWarnings": "APK 출처 경고 표시 안 함",
|
||||
"moveNonInstalledAppsToBottom": "설치되지 않은 앱을 앱 보기 하단으로 이동",
|
||||
"gitlabPATLabel": "GitLab 개인 액세스 토큰",
|
||||
"about": "정보",
|
||||
"requiresCredentialsInSettings": "{}는 추가 자격 증명이 필요합니다 (설정에서)",
|
||||
"checkOnStart": "시작 시 업데이트 확인",
|
||||
"tryInferAppIdFromCode": "소스 코드에서 앱 ID 추론 시도",
|
||||
"removeOnExternalUninstall": "외부에서 제거된 앱 자동 제거",
|
||||
"pickHighestVersionCode": "가장 높은 버전 코드 APK 자동 선택",
|
||||
"checkUpdateOnDetailPage": "앱 세부 정보 페이지 열 때 업데이트 확인",
|
||||
"disablePageTransitions": "페이지 전환 애니메이션 비활성화",
|
||||
"reversePageTransitions": "페이지 전환 애니메이션 반전",
|
||||
"minStarCount": "최소 별 개수",
|
||||
"addInfoBelow": "아래에 이 정보를 추가하십시오.",
|
||||
"addInfoInSettings": "설정에 이 정보를 추가하십시오.",
|
||||
"githubSourceNote": "GitHub 속도 제한은 API 키를 사용하여 피할 수 있습니다.",
|
||||
"sortByLastLinkSegment": "링크의 마지막 세그먼트로만 정렬",
|
||||
"filterReleaseNotesByRegEx": "정규 표현식으로 릴리스 노트 필터링",
|
||||
"customLinkFilterRegex": "정규 표현식으로 사용자 정의 APK 링크 필터링 (기본값 '.apk$')",
|
||||
"appsPossiblyUpdated": "앱 업데이트 시도됨",
|
||||
"appsPossiblyUpdatedNotifDescription": "백그라운드에서 하나 이상의 앱에 대한 업데이트가 잠재적으로 적용되었음을 사용자에게 알립니다",
|
||||
"xWasPossiblyUpdatedToY": "{}가 {}로 업데이트되었을 수 있습니다.",
|
||||
"enableBackgroundUpdates": "백그라운드 업데이트 활성화",
|
||||
"backgroundUpdateReqsExplanation": "모든 앱에 대해 백그라운드 업데이트가 가능하지 않을 수 있습니다.",
|
||||
"backgroundUpdateLimitsExplanation": "백그라운드 설치의 성공 여부는 Obtainium이 열릴 때만 확인할 수 있습니다.",
|
||||
"verifyLatestTag": "'최신' 태그 확인",
|
||||
"intermediateLinkRegex": "'중간' 링크 방문 필터",
|
||||
"filterByLinkText": "링크 텍스트로 링크 필터링",
|
||||
"intermediateLinkNotFound": "중간 링크를 찾을 수 없습니다",
|
||||
"intermediateLink": "중간 링크",
|
||||
"exemptFromBackgroundUpdates": "백그라운드 업데이트에서 제외 (활성화된 경우)",
|
||||
"bgUpdatesOnWiFiOnly": "WiFi가 아닐 때 백그라운드 업데이트 비활성화",
|
||||
"bgUpdatesWhileChargingOnly": "충전 중이 아닐 때 백그라운드 업데이트 비활성화",
|
||||
"autoSelectHighestVersionCode": "가장 높은 versionCode APK 자동 선택",
|
||||
"versionExtractionRegEx": "버전 문자열 추출 정규 표현식",
|
||||
"trimVersionString": "정규 표현식으로 버전 문자열 자르기",
|
||||
"matchGroupToUseForX": "\"{}\"에 사용할 일치 그룹",
|
||||
"matchGroupToUse": "버전 문자열 추출 정규 표현식에 사용할 일치 그룹",
|
||||
"highlightTouchTargets": "덜 명확한 터치 대상 강조",
|
||||
"pickExportDir": "내보내기 디렉토리 선택",
|
||||
"autoExportOnChanges": "변경 시 자동 내보내기",
|
||||
"includeSettings": "설정 포함",
|
||||
"filterVersionsByRegEx": "정규 표현식으로 버전 필터링",
|
||||
"trySelectingSuggestedVersionCode": "제안된 versionCode APK 선택 시도",
|
||||
"dontSortReleasesList": "API에서 릴리스 순서 유지",
|
||||
"reverseSort": "정렬 반전",
|
||||
"takeFirstLink": "첫 번째 링크 선택",
|
||||
"skipSort": "정렬 건너뛰기",
|
||||
"debugMenu": "디버그 메뉴",
|
||||
"bgTaskStarted": "백그라운드 작업 시작됨 - 로그를 확인하세요.",
|
||||
"runBgCheckNow": "지금 백그라운드 업데이트 확인 실행",
|
||||
"versionExtractWholePage": "전체 페이지에 버전 문자열 추출 정규 표현식 적용",
|
||||
"installing": "설치 중",
|
||||
"skipUpdateNotifications": "업데이트 알림 건너뛰기",
|
||||
"updatesAvailableNotifChannel": "업데이트 가능",
|
||||
"appsUpdatedNotifChannel": "앱 업데이트됨",
|
||||
"appsPossiblyUpdatedNotifChannel": "앱 업데이트 시도됨",
|
||||
"errorCheckingUpdatesNotifChannel": "업데이트 확인 오류",
|
||||
"appsRemovedNotifChannel": "앱 제거됨",
|
||||
"downloadingXNotifChannel": "{} 다운로드 중",
|
||||
"completeAppInstallationNotifChannel": "앱 설치 완료",
|
||||
"checkingForUpdatesNotifChannel": "업데이트 확인 중",
|
||||
"onlyCheckInstalledOrTrackOnlyApps": "설치된 앱과 추적 전용 앱만 업데이트 확인",
|
||||
"supportFixedAPKURL": "고정 APK URL 지원",
|
||||
"selectX": "{} 선택",
|
||||
"parallelDownloads": "병렬 다운로드 허용",
|
||||
"useShizuku": "Shizuku 또는 Sui를 사용하여 설치",
|
||||
"shizukuBinderNotFound": "Shizuku 서비스가 실행 중이 아닙니다",
|
||||
"shizukuOld": "오래된 Shizuku 버전 (<11) - 업데이트 필요",
|
||||
"shizukuOldAndroidWithADB": "ADB로 Android < 8.1에서 실행 중인 Shizuku - Android를 업데이트하거나 대신 Sui를 사용하세요",
|
||||
"shizukuPretendToBeGooglePlay": "설치 소스로 Google Play 설정 (Shizuku 사용 시)",
|
||||
"useSystemFont": "시스템 글꼴 사용",
|
||||
"useVersionCodeAsOSVersion": "앱 versionCode를 OS에서 감지된 버전으로 사용",
|
||||
"requestHeader": "요청 헤더",
|
||||
"useLatestAssetDateAsReleaseDate": "최신 자산 업로드를 릴리스 날짜로 사용",
|
||||
"defaultPseudoVersioningMethod": "기본 의사 버전 관리 방법",
|
||||
"partialAPKHash": "부분 APK 해시",
|
||||
"APKLinkHash": "APK 링크 해시",
|
||||
"directAPKLink": "직접 APK 링크",
|
||||
"pseudoVersionInUse": "의사 버전 사용 중",
|
||||
"installed": "설치됨",
|
||||
"latest": "최신",
|
||||
"invertRegEx": "정규 표현식 반전",
|
||||
"note": "노트",
|
||||
"selfHostedNote": "\"{}\" 드롭다운을 사용하여 소스의 자체 호스팅/사용자 정의 인스턴스에 도달할 수 있습니다.",
|
||||
"badDownload": "APK를 구문 분석할 수 없습니다 (호환되지 않거나 부분 다운로드)",
|
||||
"beforeNewInstallsShareToAppVerifier": "새 앱을 AppVerifier와 공유 (가능한 경우)",
|
||||
"appVerifierInstructionToast": "AppVerifier에 공유한 후 준비가 되면 여기로 돌아오세요.",
|
||||
"wiki": "도움말/위키",
|
||||
"crowdsourcedConfigsLabel": "크라우드소싱 앱 구성 (자신의 책임 하에 사용)",
|
||||
"crowdsourcedConfigsShort": "크라우드소싱 앱 구성",
|
||||
"allowInsecure": "안전하지 않은 HTTP 요청 허용",
|
||||
"stayOneVersionBehind": "최신 버전보다 한 버전 뒤에 머무르기",
|
||||
"refreshBeforeDownload": "다운로드 전에 앱 세부 정보 새로 고침",
|
||||
"tencentAppStore": "텐센트 앱 스토어",
|
||||
"removeAppQuestion": {
|
||||
"one": "앱을 제거하시겠습니까?",
|
||||
"other": "앱을 제거하시겠습니까?"
|
||||
},
|
||||
"tooManyRequestsTryAgainInMinutes": {
|
||||
"one": "요청이 너무 많습니다 (속도 제한) - {}분 후에 다시 시도하세요",
|
||||
"other": "요청이 너무 많습니다 (속도 제한) - {}분 후에 다시 시도하세요"
|
||||
},
|
||||
"bgUpdateGotErrorRetryInMinutes": {
|
||||
"one": "BG 업데이트 확인 중 {} 오류가 발생했습니다. {}분 후에 다시 확인을 예약합니다",
|
||||
"other": "BG 업데이트 확인 중 {} 오류가 발생했습니다. {}분 후에 다시 확인을 예약합니다"
|
||||
},
|
||||
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
|
||||
"one": "BG 업데이트 확인에서 {}개의 업데이트를 발견했습니다 - 필요 시 사용자에게 알립니다",
|
||||
"other": "BG 업데이트 확인에서 {}개의 업데이트를 발견했습니다 - 필요 시 사용자에게 알립니다"
|
||||
},
|
||||
"apps": {
|
||||
"one": "{} 앱",
|
||||
"other": "{} 앱"
|
||||
},
|
||||
"url": {
|
||||
"one": "{} URL",
|
||||
"other": "{} URL"
|
||||
},
|
||||
"minute": {
|
||||
"one": "{} 분",
|
||||
"other": "{} 분"
|
||||
},
|
||||
"hour": {
|
||||
"one": "{} 시간",
|
||||
"other": "{} 시간"
|
||||
},
|
||||
"day": {
|
||||
"one": "{} 일",
|
||||
"other": "{} 일"
|
||||
},
|
||||
"clearedNLogsBeforeXAfterY": {
|
||||
"one": "{n}개의 로그가 지워졌습니다 (이전 = {before}, 이후 = {after})",
|
||||
"other": "{n}개의 로그가 지워졌습니다 (이전 = {before}, 이후 = {after})"
|
||||
},
|
||||
"xAndNMoreUpdatesAvailable": {
|
||||
"one": "{} 및 1개의 앱에 업데이트가 있습니다.",
|
||||
"other": "{} 및 {}개의 앱에 업데이트가 있습니다."
|
||||
},
|
||||
"xAndNMoreUpdatesInstalled": {
|
||||
"one": "{} 및 1개의 앱이 업데이트되었습니다.",
|
||||
"other": "{} 및 {}개의 앱이 업데이트되었습니다."
|
||||
},
|
||||
"xAndNMoreUpdatesFailed": {
|
||||
"one": "{} 및 1개의 앱 업데이트에 실패했습니다.",
|
||||
"other": "{} 및 {}개의 앱 업데이트에 실패했습니다."
|
||||
},
|
||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||
"one": "{} 및 1개의 앱이 업데이트되었을 수 있습니다.",
|
||||
"other": "{} 및 {}개의 앱이 업데이트되었을 수 있습니다."
|
||||
},
|
||||
"apk": {
|
||||
"one": "{} APK",
|
||||
"other": "{} APK"
|
||||
}
|
||||
}
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Er is geen app gevonden met dat ID of die naam",
|
||||
"reposHaveMultipleApps": "Repositories kunnen meerdere apps bevatten",
|
||||
"fdroidThirdPartyRepo": "F-Droid Repository voor derden",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Installeren",
|
||||
"markInstalled": "Als geïnstalleerd markeren",
|
||||
"update": "Bijwerken",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "App-configuraties door menigte",
|
||||
"allowInsecure": "Onveilige HTTP-verzoeken toestaan",
|
||||
"stayOneVersionBehind": "Blijf een versie achter op de nieuwste",
|
||||
"refreshBeforeDownload": "Vernieuw app details voor download",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "App verwijderen?",
|
||||
"other": "Apps verwijderen?"
|
||||
|
@@ -6,7 +6,7 @@
|
||||
"cantInstallOlderVersion": "Nie można zainstalować starszej wersji aplikacji",
|
||||
"appIdMismatch": "Pobrane ID pakietu nie pasuje do istniejącego ID aplikacji",
|
||||
"functionNotImplemented": "Ta klasa nie zaimplementowała tej funkcji",
|
||||
"placeholder": "Zbiornik",
|
||||
"placeholder": "Placeholder",
|
||||
"someErrors": "Wystąpiły pewne błędy",
|
||||
"unexpectedError": "Nieoczekiwany błąd",
|
||||
"ok": "Okej",
|
||||
@@ -22,9 +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",
|
||||
"standard": "Domyślny",
|
||||
"custom": "Własny",
|
||||
"useMaterialYou": "Material You",
|
||||
"githubStarredRepos": "Repozytoria GitHub oznaczone gwiazdką",
|
||||
"uname": "Nazwa użytkownika",
|
||||
"wrongArgNum": "Nieprawidłowa liczba podanych argumentów",
|
||||
@@ -55,7 +55,7 @@
|
||||
"pleaseWait": "Proszę czekać",
|
||||
"updateAvailable": "Dostępna aktualizacja",
|
||||
"notInstalled": "Nie zainstalowano",
|
||||
"pseudoVersion": "pseudowersja",
|
||||
"pseudoVersion": "pseudo-wersja",
|
||||
"selectAll": "Zaznacz wszystkie",
|
||||
"deselectX": "Odznacz {}",
|
||||
"xWillBeRemovedButRemainInstalled": "{} zostanie usunięty z Obtainium, ale pozostanie zainstalowany na urządzeniu.",
|
||||
@@ -76,7 +76,7 @@
|
||||
"resetInstallStatusForSelectedAppsQuestion": "Zresetować status instalacji dla wybranych aplikacji?",
|
||||
"installStatusOfXWillBeResetExplanation": "Stan instalacji wybranych aplikacji zostanie zresetowany.\n\nMoże być to pomocne, gdy wersja aplikacji wyświetlana w Obtainium jest nieprawidłowa z powodu nieudanych aktualizacji lub innych problemów.",
|
||||
"customLinkMessage": "Te linki działają na urządzeniach z zainstalowanym Obtainium",
|
||||
"shareAppConfigLinks": "Udostępnij konfigurację aplikacji jako link HTML",
|
||||
"shareAppConfigLinks": "Udostępnij konfigurację aplikacji w formie linku",
|
||||
"shareSelectedAppURLs": "Udostępnij wybrane adresy URL aplikacji",
|
||||
"resetInstallStatus": "Zresetuj stan instalacji",
|
||||
"more": "Więcej",
|
||||
@@ -150,7 +150,7 @@
|
||||
"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 {}.",
|
||||
"xWasNotUpdatedToY": "Błąd aktualizacji {} do {}.",
|
||||
"errorCheckingUpdates": "Błąd sprawdzania aktualizacji",
|
||||
"errorCheckingUpdatesNotifDescription": "Jest wyświetlane, gdy sprawdzanie aktualizacji w tle nie powiedzie się",
|
||||
"appsRemoved": "Usunięte aplikacje",
|
||||
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Nie znaleziono aplikacji o tym identyfikatorze lub nazwie",
|
||||
"reposHaveMultipleApps": "Repozytoria mogą zawierać wiele aplikacji",
|
||||
"fdroidThirdPartyRepo": "Zewnętrzne repo F-Droid",
|
||||
"steamMobile": "Mobilny Steam",
|
||||
"steamChat": "Czat Steam",
|
||||
"install": "Instaluj",
|
||||
"markInstalled": "Oznacz jako zainstalowane",
|
||||
"update": "Zaktualizuj",
|
||||
@@ -191,7 +189,7 @@
|
||||
"downloadingX": "Pobieranie {}",
|
||||
"downloadX": "Pobierz {}",
|
||||
"downloadedX": "Pobrano {}",
|
||||
"releaseAsset": "Release Asset",
|
||||
"releaseAsset": "Wydany pakiet",
|
||||
"downloadNotifDescription": "Informuje o postępach w pobieraniu aplikacji",
|
||||
"noAPKFound": "Nie znaleziono pakietu APK",
|
||||
"noVersionDetection": "Bez wykrywania wersji",
|
||||
@@ -213,12 +211,12 @@
|
||||
"uninstallFromDevice": "Odinstaluj z urządzenia",
|
||||
"onlyWorksWithNonVersionDetectApps": "Działa tylko w przypadku aplikacji z wyłączonym wykrywaniem wersji.",
|
||||
"releaseDateAsVersion": "Użyj daty wydania jako wersji",
|
||||
"releaseTitleAsVersion": "Użyj tytułu wydania jako ciągu znaków wersji",
|
||||
"releaseTitleAsVersion": "Używaj nazwy wydania jako ciągu wersji",
|
||||
"releaseDateAsVersionExplanation": "Opcja ta powinna być używana tylko w przypadku aplikacji, w których wykrywanie wersji nie działa poprawnie, ale dostępna jest data wydania.",
|
||||
"changes": "Zmiany",
|
||||
"releaseDate": "Data wydania",
|
||||
"importFromURLsInFile": "Importuj z adresów URL w pliku (typu OPML)",
|
||||
"versionDetectionExplanation": "Uzgodnij ciąg wersji z wersją wykrytą w systemie operacyjnym",
|
||||
"versionDetectionExplanation": "Uzgodnij ciąg wersji z wersją wykrytą przez system operacyjny",
|
||||
"versionDetection": "Wykrywanie wersji",
|
||||
"standardVersionDetection": "Standardowe wykrywanie wersji",
|
||||
"groupByCategory": "Grupuj według kategorii",
|
||||
@@ -252,16 +250,16 @@
|
||||
"backgroundUpdateReqsExplanation": "Aktualizacje w tle mogą nie być możliwe dla wszystkich aplikacji.",
|
||||
"backgroundUpdateLimitsExplanation": "Powodzenie instalacji w tle można określić dopiero po otwarciu Obtainium.",
|
||||
"verifyLatestTag": "Zweryfikuj najnowszy tag",
|
||||
"intermediateLinkRegex": "Filtruj link \"pośredni\" do odwiedzenia",
|
||||
"intermediateLinkRegex": "Filtr linków \"pośrednich\" do odwiedzenia w pierwszej kolejności",
|
||||
"filterByLinkText": "Filtruj linki według tekstu linku",
|
||||
"intermediateLinkNotFound": "Nie znaleziono linku pośredniego",
|
||||
"intermediateLink": "Łącze pośrednie",
|
||||
"intermediateLink": "Link pośredni",
|
||||
"exemptFromBackgroundUpdates": "Wyklucz z uaktualnień w tle (jeśli są włączone)",
|
||||
"bgUpdatesOnWiFiOnly": "Wyłącz aktualizacje w tle, gdy nie ma połączenia z Wi-Fi",
|
||||
"bgUpdatesWhileChargingOnly": "Wyłącz aktualizacje w tle, gdy urządzenie nie jest ładowane",
|
||||
"autoSelectHighestVersionCode": "Automatycznie wybierz najwyższy kod wersji APK",
|
||||
"versionExtractionRegEx": "Wyrażenie regularne wyodrębniające wersję",
|
||||
"trimVersionString": "Przycinanie łańcucha wersji za pomocą RegEx",
|
||||
"trimVersionString": "Przytnij ciąg wersji za pomocą RegEx",
|
||||
"matchGroupToUseForX": "Dopasuj grupę do użycia dla \"{}\"",
|
||||
"matchGroupToUse": "Dopasuj grupę do użycia dla wyrażenia regularnego wyodrębniania wersji",
|
||||
"highlightTouchTargets": "Wyróżnij mniej oczywiste elementy dotykowe",
|
||||
@@ -272,7 +270,7 @@
|
||||
"trySelectingSuggestedVersionCode": "Spróbuj wybierać sugerowany kod wersji APK",
|
||||
"dontSortReleasesList": "Utrzymaj kolejność wydań z interfejsu API",
|
||||
"reverseSort": "Odwrotne sortowanie",
|
||||
"takeFirstLink": "Weź pierwszy link",
|
||||
"takeFirstLink": "Wykorzystaj pierwszy link",
|
||||
"skipSort": "Pomiń sortowanie",
|
||||
"debugMenu": "Menu debugowania",
|
||||
"bgTaskStarted": "Uruchomiono zadanie w tle - sprawdź logi.",
|
||||
@@ -285,40 +283,42 @@
|
||||
"appsPossiblyUpdatedNotifChannel": "Informuj o próbach aktualizacji",
|
||||
"errorCheckingUpdatesNotifChannel": "Błędy sprawdzania aktualizacji",
|
||||
"appsRemovedNotifChannel": "Usunięte aplikacje",
|
||||
"downloadingXNotifChannel": "Pobieranie aplikacji",
|
||||
"downloadingXNotifChannel": "Pobieranie {}",
|
||||
"completeAppInstallationNotifChannel": "Ukończenie instalacji aplikacji",
|
||||
"checkingForUpdatesNotifChannel": "Sprawdzanie dostępności aktualizacji",
|
||||
"onlyCheckInstalledOrTrackOnlyApps": "Sprawdzaj tylko zainstalowane i obserwowane aplikacje pod kątem aktualizacji",
|
||||
"supportFixedAPKURL": "Obsługuj stałe adresy URL APK",
|
||||
"selectX": "Wybierz {}",
|
||||
"parallelDownloads": "Zezwól na pobieranie równoległe",
|
||||
"parallelDownloads": "Zezwalaj na równoległe pobierania",
|
||||
"useShizuku": "Użyj Shizuku lub Sui, aby zainstalować",
|
||||
"shizukuBinderNotFound": "Shizuku is not running",
|
||||
"shizukuBinderNotFound": "Usługa Shizuku nie działa",
|
||||
"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",
|
||||
"useVersionCodeAsOSVersion": "Użyj kodu wersji aplikacji jako wersji wykrytej przez system operacyjny",
|
||||
"shizukuOldAndroidWithADB": "Shizuku przez ADB działa na Androidzie 8.1+. 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": "Czcionka systemowa",
|
||||
"useVersionCodeAsOSVersion": "Użyj versionCode aplikacji jako wersji wykrytej przez system operacyjny",
|
||||
"requestHeader": "Nagłówek żądania",
|
||||
"useLatestAssetDateAsReleaseDate": "Użyj najnowszego przesłanego zasobu jako daty wydania",
|
||||
"defaultPseudoVersioningMethod": "Domyślna metoda pseudowersji",
|
||||
"partialAPKHash": "Częściowy skrót APK",
|
||||
"APKLinkHash": "Skrót łącza APK",
|
||||
"directAPKLink": "Bezpośredni link APK",
|
||||
"pseudoVersionInUse": "Pseudowersja jest w użyciu",
|
||||
"defaultPseudoVersioningMethod": "Domyślna metoda pseudo-wersji",
|
||||
"partialAPKHash": "Częściowy Hash pliku apk",
|
||||
"APKLinkHash": "Link Hash pliku apk",
|
||||
"directAPKLink": "Bezpośredni link do pliku apk",
|
||||
"pseudoVersionInUse": "Pseudo-wersja jest w użyciu",
|
||||
"installed": "Zainstalowano",
|
||||
"latest": "Najnowszy",
|
||||
"latest": "Najnowsza",
|
||||
"invertRegEx": "Odwróć wyrażenie regularne",
|
||||
"note": "Uwaga",
|
||||
"selfHostedNote": "Lista rozwijana \"{}\" może być używana do uzyskiwania dostępu do samodzielnie hostowanych / niestandardowych instancji dowolnego źródła.",
|
||||
"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.",
|
||||
"selfHostedNote": "Wybierz \"{}\", aby uzyskać dostęp do samodzielnie hostowanych lub niestandardowych instancji dowolnego źródła.",
|
||||
"badDownload": "Nie można przeanalizować pliku apk (jest niekompatybilny lub częściowo pobrany)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Udostępnij nowe aplikacje za pomocą weryfikatora aplikacji (jeśli jest dostępny)",
|
||||
"appVerifierInstructionToast": "Udostępnij do weryfikatora aplikacji, a następnie wróć tutaj.",
|
||||
"wiki": "Pomoc/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Konfiguracje aplikacji pochodzące z crowdsourcingu (korzystanie na własne ryzyko)",
|
||||
"crowdsourcedConfigsShort": "Konfiguracje aplikacji pochodzące z crowdsourcingu",
|
||||
"crowdsourcedConfigsLabel": "Baza konfiguracji",
|
||||
"crowdsourcedConfigsShort": "Baza konfiguracji",
|
||||
"allowInsecure": "Zezwalaj na niezabezpieczone żądania HTTP",
|
||||
"stayOneVersionBehind": "Pozostań jedną wersję za najnowszą",
|
||||
"stayOneVersionBehind": "Pozostań jedną wersję w tyle za najnowszą",
|
||||
"refreshBeforeDownload": "Odśwież szczegóły aplikacji przed pobraniem",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Usunąć aplikację?",
|
||||
"few": "Usunąć aplikacje?",
|
||||
@@ -392,8 +392,10 @@
|
||||
"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."
|
||||
"one": "Błąd aktualizacji {} i 1 innej apki.",
|
||||
"few": "Błąd aktualizacji {} i {} innych apek.",
|
||||
"many": "Błąd aktualizacji {} i {} innych apek.",
|
||||
"other": "Błąd aktualizacji {} i {} innych apek."
|
||||
},
|
||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||
"one": "{} i 1 inna apka mogły zostać zaktualizowane.",
|
||||
@@ -402,7 +404,9 @@
|
||||
"other": "{} i {} inne apki mogły zostać zaktualizowane."
|
||||
},
|
||||
"apk": {
|
||||
"one": "{} APK",
|
||||
"other": "{} APK"
|
||||
"one": "{} apk",
|
||||
"few": "{} apki",
|
||||
"many": "{} apek",
|
||||
"other": "{} apki"
|
||||
}
|
||||
}
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Nenhum aplicativo foi encontrado com esse ID ou nome",
|
||||
"reposHaveMultipleApps": "Repositórios podem conter múltiplos aplicativos",
|
||||
"fdroidThirdPartyRepo": "Repositórios de terceiros F-Droid",
|
||||
"steamMobile": "Steam para celular",
|
||||
"steamChat": "Chat do Steam",
|
||||
"install": "Instalar",
|
||||
"markInstalled": "Marcar instalado",
|
||||
"update": "Atualizar",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Configurações de aplicações com base em crowdsourcing",
|
||||
"allowInsecure": "Permitir pedidos HTTP inseguros",
|
||||
"stayOneVersionBehind": "Manter-se uma versão atrás da mais recente",
|
||||
"refreshBeforeDownload": "Atualizar os detalhes da aplicação antes da transferência",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Remover aplicativo?",
|
||||
"other": "Remover aplicativos?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Приложение с таким ID или названием не было найдено",
|
||||
"reposHaveMultipleApps": "В хранилище несколько приложений",
|
||||
"fdroidThirdPartyRepo": "Сторонние репозитории F-Droid",
|
||||
"steamMobile": "Приложение Steam",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Установить",
|
||||
"markInstalled": "Пометить как установленное",
|
||||
"update": "Обновить",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Конфиги приложений с помощью краудсорсинга",
|
||||
"allowInsecure": "Разрешить небезопасные HTTP-запросы",
|
||||
"stayOneVersionBehind": "Не отставайте от последней версии",
|
||||
"refreshBeforeDownload": "Обновляйте информацию о приложении перед загрузкой",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Удалить приложение?",
|
||||
"other": "Удалить приложения?"
|
||||
|
@@ -12,7 +12,8 @@ const neverAutoTranslate = {
|
||||
root: ['*'],
|
||||
obtainiumExportHyphenatedLowercase: ['*'],
|
||||
theme: ['de'],
|
||||
appId: ['de']
|
||||
appId: ['de'],
|
||||
placeholder: ['pl']
|
||||
}
|
||||
|
||||
const translateText = async (text, targetLang, authKey) => {
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Ingen App funnen med det namnet eller ID",
|
||||
"reposHaveMultipleApps": "Förråd kan innehålla flera ApparR",
|
||||
"fdroidThirdPartyRepo": "F-Droid Tredjeparts Förråd",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Installera",
|
||||
"markInstalled": "Märk Installerad",
|
||||
"update": "Uppdatera",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Appkonfigurationer med hjälp av crowdsourcing",
|
||||
"allowInsecure": "Tillåt osäkra HTTP-förfrågningar",
|
||||
"stayOneVersionBehind": "Håll dig en version bakom den senaste",
|
||||
"refreshBeforeDownload": "Uppdatera appdetaljerna före nedladdning",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Ta Bort App?",
|
||||
"other": "Ta Bort Appar?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Bu kimlik veya ada sahip bir uygulama bulunamadı",
|
||||
"reposHaveMultipleApps": "Depolar birden fazla uygulama içerebilir",
|
||||
"fdroidThirdPartyRepo": "F-Droid Üçüncü Parti Depo",
|
||||
"steamMobile": "Steam Mobil",
|
||||
"steamChat": "Steam Sohbet",
|
||||
"install": "Yükle",
|
||||
"markInstalled": "Yüklendi olarak İşaretle",
|
||||
"update": "Güncelle",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Kitle Kaynaklı Uygulama Yapılandırmaları",
|
||||
"allowInsecure": "Güvensiz HTTP isteklerine izin ver",
|
||||
"stayOneVersionBehind": "En son sürümün bir sürüm gerisinde kalın",
|
||||
"refreshBeforeDownload": "İndirmeden önce uygulama ayrıntılarını yenileyin",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Uygulamayı Kaldır?",
|
||||
"other": "Uygulamaları Kaldır?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Застосунок з таким ідентифікатором або назвою не знайдено",
|
||||
"reposHaveMultipleApps": "Сховища можуть містити кілька застосунків",
|
||||
"fdroidThirdPartyRepo": "F-Droid Стороннє сховище",
|
||||
"steamMobile": "Мобільний Steam",
|
||||
"steamChat": "Чат Steam",
|
||||
"install": "Встановити",
|
||||
"markInstalled": "Позначити як встановлене",
|
||||
"update": "Оновити",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Налаштування краудсорсингових додатків",
|
||||
"allowInsecure": "Дозволити незахищені HTTP-запити",
|
||||
"stayOneVersionBehind": "Залишайтеся на одну версію актуальнішою",
|
||||
"refreshBeforeDownload": "Оновіть інформацію про програму перед завантаженням",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Видалити застосунок?",
|
||||
"other": "Видалити застосунки?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "Không tìm thấy ứng dụng nào có ID hoặc tên đó",
|
||||
"reposHaveMultipleApps": "Kho có thể chứa nhiều Ứng dụng",
|
||||
"fdroidThirdPartyRepo": "Kho lưu trữ bên thứ ba F-Droid",
|
||||
"steamMobile": "Điện thoại di động hơi nước",
|
||||
"steamChat": "Trò chuyện hơi nước",
|
||||
"install": "Cài đặt",
|
||||
"markInstalled": "Đánh dấu là đã cài đặt",
|
||||
"update": "Cập nhật",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
|
||||
"allowInsecure": "Allow insecure HTTP requests",
|
||||
"stayOneVersionBehind": "Stay one version behind latest",
|
||||
"refreshBeforeDownload": "Refresh app details before download",
|
||||
"tencentAppStore": "Tencent App Store",
|
||||
"removeAppQuestion": {
|
||||
"one": "Gỡ ứng dụng?",
|
||||
"other": "Gỡ ứng dụng?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "找不到具有該 ID 或名稱的應用程式",
|
||||
"reposHaveMultipleApps": "倉庫可能包含多個應用程式",
|
||||
"fdroidThirdPartyRepo": "F-Droid 第三方倉庫",
|
||||
"steamMobile": "Steam 行動版",
|
||||
"steamChat": "Steam 聊天",
|
||||
"install": "安裝",
|
||||
"markInstalled": "標記為已安裝",
|
||||
"update": "更新",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
|
||||
"allowInsecure": "Allow insecure HTTP requests",
|
||||
"stayOneVersionBehind": "Stay one version behind latest",
|
||||
"refreshBeforeDownload": "Refresh app details before download",
|
||||
"tencentAppStore": "騰訊應用寶",
|
||||
"removeAppQuestion": {
|
||||
"one": "移除應用程式?",
|
||||
"other": "移除應用程式?"
|
||||
|
@@ -179,8 +179,6 @@
|
||||
"appWithIdOrNameNotFound": "未找到符合此 ID 或名称的应用",
|
||||
"reposHaveMultipleApps": "存储库中可能包含多个应用",
|
||||
"fdroidThirdPartyRepo": "F-Droid 第三方存储库",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "安装",
|
||||
"markInstalled": "标记为已安装",
|
||||
"update": "更新",
|
||||
@@ -188,10 +186,10 @@
|
||||
"additionalOptions": "附加选项",
|
||||
"disableVersionDetection": "禁用版本检测",
|
||||
"noVersionDetectionExplanation": "此选项应该仅用于无法进行版本检测的应用。",
|
||||
"downloadingX": "正在下载“{}”",
|
||||
"downloadingX": "正在下载 {}",
|
||||
"downloadX": "下载 {}",
|
||||
"downloadedX": "下载 {}",
|
||||
"releaseAsset": "发行版附件",
|
||||
"downloadedX": "已下载 {}",
|
||||
"releaseAsset": "发行文件",
|
||||
"downloadNotifDescription": "提示应用的下载进度",
|
||||
"noAPKFound": "未找到 APK 文件",
|
||||
"noVersionDetection": "禁用版本检测",
|
||||
@@ -319,6 +317,8 @@
|
||||
"crowdsourcedConfigsShort": "众包应用程序配置",
|
||||
"allowInsecure": "允许不安全的 HTTP 请求",
|
||||
"stayOneVersionBehind": "比最新版本晚一个版本",
|
||||
"refreshBeforeDownload": "下载前刷新应用程序详细信息",
|
||||
"tencentAppStore": "腾讯应用宝",
|
||||
"removeAppQuestion": {
|
||||
"one": "是否删除应用?",
|
||||
"other": "是否删除应用?"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<p>Obtainium allows you to install and update Apps directly from their releases pages, and receive notifications when new releases are made available.</p>
|
||||
<p>Read the <a href="https://github.com/ImranR98/Obtainium/wiki">Wiki</a></p>
|
||||
<p>Read the <a href="https://wiki.obtainium.imranr.dev/">Wiki</a></p>
|
||||
<p>
|
||||
<b>Currently supported App sources:</b>
|
||||
</p>
|
||||
@@ -13,7 +13,6 @@
|
||||
<li>F-Droid</li>
|
||||
<li>Third Party F-Droid Repos</li>
|
||||
<li>IzzyOnDroid</li>
|
||||
<li>SourceForge</li>
|
||||
<li>SourceHut</li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -22,24 +21,17 @@
|
||||
<ul>
|
||||
<li>APKPure</li>
|
||||
<li>Aptoide</li>
|
||||
<li>Uptodowng</li>
|
||||
<li>Uptodown</li>
|
||||
<li>APKMirror (Track-Only)</li>
|
||||
<li>Huawei AppGallery</li>
|
||||
<li>Tencent App Store</li>
|
||||
<li>Jenkins Jobs</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open Source - App-Specific:</p>
|
||||
<ul>
|
||||
<li>Mullvad</li>
|
||||
<li>Signal</li>
|
||||
<li>VLC</li>
|
||||
<li>RuStore</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>Other - App-Specific:</p>
|
||||
<ul>
|
||||
<li>WhatsApp</li>
|
||||
<li>Telegram App</li>
|
||||
<li>Neutron Code</li>
|
||||
</ul>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<p>Obtainium позволяет вам устанавливать и обновлять приложения прямо с их объявлений о выпусках и получать уведомления о новых выпусках.</p>
|
||||
<p>Для деталей читайте <a href="https://github.com/ImranR98/Obtainium/wiki">Вики</a></p>
|
||||
<p>Для деталей читайте <a href="https://wiki.obtainium.imranr.dev/">Вики</a></p>
|
||||
<p>
|
||||
<b>Поддерживаемые источники приложений:</b>
|
||||
</p>
|
||||
@@ -13,7 +13,6 @@
|
||||
<li>F-Droid</li>
|
||||
<li>Third Party F-Droid Repos</li>
|
||||
<li>IzzyOnDroid</li>
|
||||
<li>SourceForge</li>
|
||||
<li>SourceHut</li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -22,24 +21,17 @@
|
||||
<ul>
|
||||
<li>APKPure</li>
|
||||
<li>Aptoide</li>
|
||||
<li>Uptodowng</li>
|
||||
<li>Uptodown</li>
|
||||
<li>APKMirror (Track-Only)</li>
|
||||
<li>Huawei AppGallery</li>
|
||||
<li>Tencent App Store</li>
|
||||
<li>Jenkins Jobs</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>Свободное ПО - Для отдельных приложений:</p>
|
||||
<ul>
|
||||
<li>Mullvad</li>
|
||||
<li>Signal</li>
|
||||
<li>VLC</li>
|
||||
<li>RuStore</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>Другие - Для отдельных приложений:</p>
|
||||
<ul>
|
||||
<li>WhatsApp</li>
|
||||
<li>Telegram App</li>
|
||||
<li>Neutron Code</li>
|
||||
</ul>
|
||||
|
@@ -5,6 +5,8 @@ import 'package:html/parser.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:obtainium/components/generated_form.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/providers/apps_provider.dart';
|
||||
import 'package:obtainium/providers/settings_provider.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class APKMirror extends AppSource {
|
||||
@@ -31,6 +33,16 @@ class APKMirror extends AppSource {
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, String>?> getRequestHeaders(
|
||||
Map<String, dynamic> additionalSettings,
|
||||
{bool forAPKDownload = false}) async {
|
||||
return {
|
||||
"User-Agent":
|
||||
"Obtainium/${(await getInstalledInfo(obtainiumId))?.versionName ?? '1.0.0'}"
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
|
||||
RegExp standardUrlRegEx = RegExp(
|
||||
|
@@ -105,11 +105,7 @@ class APKPure extends AppSource {
|
||||
.map((e) => e.text.trim())
|
||||
.map((t) => t == 'APKs' ? 'APK' : t) ??
|
||||
[];
|
||||
String type = types.isEmpty
|
||||
? 'APK'
|
||||
: types.length == 1
|
||||
? types.first
|
||||
: types.last;
|
||||
String type = types.isEmpty ? 'APK' : types.first;
|
||||
String? dateString = apkInfo
|
||||
?.querySelector('div.info-bottom span.time')
|
||||
?.text
|
||||
@@ -135,12 +131,18 @@ class APKPure extends AppSource {
|
||||
throw NoAPKError();
|
||||
}
|
||||
String version = Uri.parse(link).pathSegments.last;
|
||||
String author = html
|
||||
.querySelector('span.info-sdk')
|
||||
?.text
|
||||
.trim()
|
||||
.substring(version.length + 4) ??
|
||||
Uri.parse(standardUrl).pathSegments.reversed.last;
|
||||
String? author;
|
||||
try {
|
||||
author = html
|
||||
.querySelector('span.info-sdk')
|
||||
?.text
|
||||
.trim()
|
||||
.substring(version.length + 4) ??
|
||||
Uri.parse(standardUrl).pathSegments.reversed.last;
|
||||
} catch (e) {
|
||||
author = html.querySelector('span.info-sdk')?.text.trim() ??
|
||||
Uri.parse(standardUrl).pathSegments.reversed.last;
|
||||
}
|
||||
String appName =
|
||||
html.querySelector('h1.info-title')?.text.trim() ?? appId;
|
||||
String? changeLog = html
|
||||
@@ -164,9 +166,15 @@ class APKPure extends AppSource {
|
||||
String host = Uri.parse(standardUrl).host;
|
||||
|
||||
var res0 = await sourceRequest('$standardUrl/versions', additionalSettings);
|
||||
var decodedStandardUrl = standardUrl;
|
||||
try {
|
||||
decodedStandardUrl = Uri.decodeFull(decodedStandardUrl);
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
var versionLinks = await grabLinksCommon(res0, {
|
||||
'skipSort': true,
|
||||
'customLinkFilterRegex': '${Uri.decodeFull(standardUrl)}/download/[^/]+\$'
|
||||
'customLinkFilterRegex': '$decodedStandardUrl/download/[^/]+\$'
|
||||
});
|
||||
|
||||
var supportedArchs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
|
||||
|
@@ -45,7 +45,7 @@ class FDroid extends AppSource {
|
||||
RegExpMatch? match = standardUrlRegExB.firstMatch(url);
|
||||
if (match != null) {
|
||||
url =
|
||||
'https://${Uri.parse(match.group(0)!).host}/packages/${Uri.parse(url).pathSegments.last}';
|
||||
'https://${Uri.parse(match.group(0)!).host}/packages/${Uri.parse(url).pathSegments.where((s) => s.trim().isNotEmpty).last}';
|
||||
}
|
||||
RegExp standardUrlRegExA = RegExp(
|
||||
'^https?://(www\\.)?${getSourceRegex(hosts)}/+packages/+[^/]+',
|
||||
|
@@ -275,14 +275,15 @@ class GitHub extends AppSource {
|
||||
}
|
||||
}
|
||||
|
||||
List<MapEntry<String, String>> getReleaseAssetUrls(dynamic release) =>
|
||||
findReleaseAssetUrls(dynamic release) =>
|
||||
(release['assets'] as List<dynamic>?)?.map((e) {
|
||||
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)
|
||||
e['final_url'] = (e['name'] != null) && (url != null)
|
||||
? MapEntry(e['name'] as String, url as String)
|
||||
: const MapEntry('', '');
|
||||
return e;
|
||||
}).toList() ??
|
||||
[];
|
||||
|
||||
@@ -293,7 +294,9 @@ class GitHub extends AppSource {
|
||||
? DateTime.parse(rel['commit']['created'])
|
||||
: null;
|
||||
DateTime? getNewestAssetDateFromRelease(dynamic rel) {
|
||||
var t = (rel['assets'] as List<dynamic>?)
|
||||
var allAssets = rel['assets'] as List<dynamic>?;
|
||||
var filteredAssets = rel['filteredAssets'] as List<dynamic>?;
|
||||
var t = (filteredAssets ?? allAssets)
|
||||
?.map((e) {
|
||||
return e?['updated_at'] != null
|
||||
? DateTime.parse(e['updated_at'])
|
||||
@@ -387,18 +390,37 @@ class GitHub extends AppSource {
|
||||
.hasMatch(((releases[i]['body'] as String?) ?? '').trim())) {
|
||||
continue;
|
||||
}
|
||||
var allAssetUrls = getReleaseAssetUrls(releases[i]);
|
||||
List<MapEntry<String, String>> apkUrls = allAssetUrls
|
||||
.where((element) => element.key.toLowerCase().endsWith('.apk'))
|
||||
var allAssetsWithUrls = findReleaseAssetUrls(releases[i]);
|
||||
List<MapEntry<String, String>> allAssetUrls = allAssetsWithUrls
|
||||
.map((e) => e['final_url'] as MapEntry<String, String>)
|
||||
.toList();
|
||||
var apkAssetsWithUrls = allAssetsWithUrls
|
||||
.where((element) =>
|
||||
(element['final_url'] as MapEntry<String, String>)
|
||||
.key
|
||||
.toLowerCase()
|
||||
.endsWith('.apk'))
|
||||
.toList();
|
||||
|
||||
apkUrls = filterApks(apkUrls, additionalSettings['apkFilterRegEx'],
|
||||
var filteredApkUrls = filterApks(
|
||||
apkAssetsWithUrls
|
||||
.map((e) => e['final_url'] as MapEntry<String, String>)
|
||||
.toList(),
|
||||
additionalSettings['apkFilterRegEx'],
|
||||
additionalSettings['invertAPKFilter']);
|
||||
if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) {
|
||||
var filteredApks = apkAssetsWithUrls
|
||||
.where((e) => filteredApkUrls
|
||||
.where((e2) =>
|
||||
e2.key == (e['final_url'] as MapEntry<String, String>).key)
|
||||
.isNotEmpty)
|
||||
.toList();
|
||||
|
||||
if (filteredApks.isEmpty && additionalSettings['trackOnly'] != true) {
|
||||
continue;
|
||||
}
|
||||
targetRelease = releases[i];
|
||||
targetRelease['apkUrls'] = apkUrls;
|
||||
targetRelease['apkUrls'] = filteredApkUrls;
|
||||
targetRelease['filteredAssets'] = filteredApks;
|
||||
targetRelease['version'] =
|
||||
additionalSettings['releaseTitleAsVersion'] == true
|
||||
? nameToFilter
|
||||
@@ -420,6 +442,7 @@ class GitHub extends AppSource {
|
||||
throw NoReleasesError();
|
||||
}
|
||||
String? version = targetRelease['version'];
|
||||
|
||||
DateTime? releaseDate = getReleaseDateFromRelease(
|
||||
targetRelease, useLatestAssetDateAsReleaseDate);
|
||||
if (version == null) {
|
||||
@@ -478,7 +501,7 @@ class GitHub extends AppSource {
|
||||
AppNames getAppNames(String standardUrl) {
|
||||
String temp = standardUrl.substring(standardUrl.indexOf('://') + 3);
|
||||
List<String> names = temp.substring(temp.indexOf('/') + 1).split('/');
|
||||
return AppNames(names[0], names[1]);
|
||||
return AppNames(names[0], names.sublist(1).join('/'));
|
||||
}
|
||||
|
||||
Future<Map<String, List<String>>> searchCommon(
|
||||
|
@@ -53,8 +53,12 @@ class GitLab extends AppSource {
|
||||
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
|
||||
var urlSegments = url.split('/');
|
||||
var cutOffIndex = urlSegments.indexWhere((s) => s == '-');
|
||||
url =
|
||||
urlSegments.sublist(0, cutOffIndex <= 0 ? null : cutOffIndex).join('/');
|
||||
RegExp standardUrlRegEx = RegExp(
|
||||
'^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+',
|
||||
'^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+(/[^/-]+){1,20}',
|
||||
caseSensitive: false);
|
||||
RegExpMatch? match = standardUrlRegEx.firstMatch(url);
|
||||
if (match == null) {
|
||||
@@ -126,6 +130,8 @@ class GitLab extends AppSource {
|
||||
) async {
|
||||
// Prepare request params
|
||||
var names = GitHub().getAppNames(standardUrl);
|
||||
String projectUriComponent =
|
||||
'${Uri.encodeComponent(names.author)}%2F${Uri.encodeComponent(names.name)}';
|
||||
String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {});
|
||||
String optionalAuth = (PAT != null) ? 'private_token=$PAT' : '';
|
||||
|
||||
@@ -133,7 +139,7 @@ class GitLab extends AppSource {
|
||||
|
||||
// Get project ID
|
||||
Response res0 = await sourceRequest(
|
||||
'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}?$optionalAuth',
|
||||
'https://${hosts[0]}/api/v4/projects/$projectUriComponent?$optionalAuth',
|
||||
additionalSettings);
|
||||
if (res0.statusCode != 200) {
|
||||
throw getObtainiumHttpError(res0);
|
||||
@@ -145,7 +151,7 @@ class GitLab extends AppSource {
|
||||
|
||||
// Request data from REST API
|
||||
Response res = await sourceRequest(
|
||||
'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}/${trackOnly ? 'repository/tags' : 'releases'}?$optionalAuth',
|
||||
'https://${hosts[0]}/api/v4/projects/$projectUriComponent/${trackOnly ? 'repository/tags' : 'releases'}?$optionalAuth',
|
||||
additionalSettings);
|
||||
if (res.statusCode != 200) {
|
||||
throw getObtainiumHttpError(res);
|
||||
@@ -180,7 +186,7 @@ class GitLab extends AppSource {
|
||||
return APKDetails(
|
||||
e['tag_name'] ?? e['name'],
|
||||
getApkUrlsFromUrls(apkUrlsSet.toList()),
|
||||
GitHub().getAppNames(standardUrl),
|
||||
AppNames(names.author, names.name.split('/').last),
|
||||
releaseDate: releaseDate);
|
||||
});
|
||||
if (apkDetailsList.isEmpty) {
|
||||
|
@@ -7,6 +7,9 @@ import 'package:obtainium/providers/apps_provider.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
String ensureAbsoluteUrl(String ambiguousUrl, Uri referenceAbsoluteUrl) {
|
||||
if (ambiguousUrl.startsWith('//')) {
|
||||
ambiguousUrl = '${referenceAbsoluteUrl.scheme}:$ambiguousUrl';
|
||||
}
|
||||
try {
|
||||
Uri.parse(ambiguousUrl).origin;
|
||||
return ambiguousUrl;
|
||||
@@ -18,7 +21,7 @@ String ensureAbsoluteUrl(String ambiguousUrl, Uri referenceAbsoluteUrl) {
|
||||
.where((element) => element.trim().isNotEmpty)
|
||||
.toList();
|
||||
String absoluteUrl;
|
||||
if (ambiguousUrl.startsWith('/') || currPathSegments.isEmpty) {
|
||||
if (ambiguousUrl.startsWith('/')) {
|
||||
absoluteUrl = '${referenceAbsoluteUrl.origin}$ambiguousUrl';
|
||||
} else if (currPathSegments.isEmpty) {
|
||||
absoluteUrl = '${referenceAbsoluteUrl.origin}/$ambiguousUrl';
|
||||
@@ -353,7 +356,12 @@ class HTML extends AppSource {
|
||||
forAPKDownload: true),
|
||||
allowInsecure: additionalSettings['allowInsecure'] == true))
|
||||
.toString();
|
||||
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
|
||||
return APKDetails(
|
||||
version,
|
||||
[rel]
|
||||
.map((e) =>
|
||||
MapEntry('${e.hashCode}-${Uri.parse(e).pathSegments.last}', e))
|
||||
.toList(),
|
||||
AppNames(uri.host, tr('app')));
|
||||
}
|
||||
}
|
||||
|
98
lib/app_sources/rustore.dart
Normal file
@@ -0,0 +1,98 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter_charset_detector/flutter_charset_detector.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class RuStore extends AppSource {
|
||||
RuStore() {
|
||||
hosts = ['rustore.ru'];
|
||||
name = 'RuStore';
|
||||
naiveStandardVersionDetection = true;
|
||||
showReleaseDateAsVersionToggle = true;
|
||||
}
|
||||
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
|
||||
RegExp standardUrlRegEx = RegExp(
|
||||
'^https?://(www\\.)?${getSourceRegex(hosts)}/catalog/app/+[^/]+',
|
||||
caseSensitive: false);
|
||||
RegExpMatch? match = standardUrlRegEx.firstMatch(url);
|
||||
if (match == null) {
|
||||
throw InvalidURLError(name);
|
||||
}
|
||||
return match.group(0)!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> tryInferringAppId(String standardUrl,
|
||||
{Map<String, dynamic> additionalSettings = const {}}) async {
|
||||
return Uri.parse(standardUrl).pathSegments.last;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<APKDetails> getLatestAPKDetails(
|
||||
String standardUrl,
|
||||
Map<String, dynamic> additionalSettings,
|
||||
) async {
|
||||
String? appId = await tryInferringAppId(standardUrl);
|
||||
Response res0 = await sourceRequest(
|
||||
'https://backapi.rustore.ru/applicationData/overallInfo/$appId',
|
||||
additionalSettings);
|
||||
if (res0.statusCode != 200) {
|
||||
throw getObtainiumHttpError(res0);
|
||||
}
|
||||
var appDetails = jsonDecode(res0.body)['body'];
|
||||
if (appDetails['appId'] == null) {
|
||||
throw NoReleasesError();
|
||||
}
|
||||
|
||||
String appName = appDetails['appName'] ?? tr('app');
|
||||
String author = appDetails['companyName'] ?? name;
|
||||
String? dateStr = appDetails['updatedAt'];
|
||||
String? version = appDetails['versionName'];
|
||||
String? changeLog = appDetails['whatsNew'];
|
||||
if (version == null) {
|
||||
throw NoVersionError();
|
||||
}
|
||||
DateTime? relDate;
|
||||
if (dateStr != null) {
|
||||
relDate = DateTime.parse(dateStr);
|
||||
}
|
||||
|
||||
Response res1 = await sourceRequest(
|
||||
'https://backapi.rustore.ru/applicationData/download-link',
|
||||
additionalSettings,
|
||||
followRedirects: false,
|
||||
postBody: {"appId": appDetails['appId'], "firstInstall": true});
|
||||
var downloadDetails = jsonDecode(res1.body)['body'];
|
||||
if (res1.statusCode != 200 || downloadDetails['apkUrl'] == null) {
|
||||
throw NoAPKError();
|
||||
}
|
||||
|
||||
appName = (await CharsetDetector.autoDecode(
|
||||
Uint8List.fromList(appName.codeUnits)))
|
||||
.string;
|
||||
author =
|
||||
(await CharsetDetector.autoDecode(Uint8List.fromList(author.codeUnits)))
|
||||
.string;
|
||||
changeLog = changeLog != null
|
||||
? (await CharsetDetector.autoDecode(
|
||||
Uint8List.fromList(changeLog.codeUnits)))
|
||||
.string
|
||||
: null;
|
||||
|
||||
return APKDetails(
|
||||
version,
|
||||
getApkUrlsFromUrls([
|
||||
(downloadDetails['apkUrl'] as String)
|
||||
.replaceAll(RegExp('\\.zip\$'), '.apk')
|
||||
]),
|
||||
AppNames(author, appName),
|
||||
releaseDate: relDate,
|
||||
changeLog: changeLog);
|
||||
}
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class Signal extends AppSource {
|
||||
Signal() {
|
||||
hosts = ['signal.org'];
|
||||
}
|
||||
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
|
||||
return 'https://${hosts[0]}';
|
||||
}
|
||||
|
||||
@override
|
||||
Future<APKDetails> getLatestAPKDetails(
|
||||
String standardUrl,
|
||||
Map<String, dynamic> additionalSettings,
|
||||
) async {
|
||||
Response res = await sourceRequest(
|
||||
'https://updates.${hosts[0]}/android/latest.json', additionalSettings);
|
||||
if (res.statusCode == 200) {
|
||||
var json = jsonDecode(res.body);
|
||||
String? apkUrl = json['url'];
|
||||
List<String> apkUrls = apkUrl == null ? [] : [apkUrl];
|
||||
String? version = json['versionName'];
|
||||
if (version == null) {
|
||||
throw NoVersionError();
|
||||
}
|
||||
return APKDetails(
|
||||
version, getApkUrlsFromUrls(apkUrls), AppNames(name, 'Signal'));
|
||||
} else {
|
||||
throw getObtainiumHttpError(res);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:html/parser.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:obtainium/components/generated_form.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class SteamMobile extends AppSource {
|
||||
SteamMobile() {
|
||||
hosts = ['store.steampowered.com'];
|
||||
name = 'Steam';
|
||||
additionalSourceAppSpecificSettingFormItems = [
|
||||
[
|
||||
GeneratedFormDropdown('app', apks.entries.toList(),
|
||||
label: tr('app'), defaultValue: apks.entries.toList()[0].key)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
final apks = {'steam': tr('steamMobile'), 'steam-chat-app': tr('steamChat')};
|
||||
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
|
||||
return 'https://${hosts[0]}';
|
||||
}
|
||||
|
||||
@override
|
||||
Future<APKDetails> getLatestAPKDetails(
|
||||
String standardUrl,
|
||||
Map<String, dynamic> additionalSettings,
|
||||
) async {
|
||||
Response res =
|
||||
await sourceRequest('https://${hosts[0]}/mobile', additionalSettings);
|
||||
if (res.statusCode == 200) {
|
||||
var apkNamePrefix = additionalSettings['app'] as String?;
|
||||
if (apkNamePrefix == null) {
|
||||
throw NoReleasesError();
|
||||
}
|
||||
String apkInURLRegexPattern =
|
||||
'/$apkNamePrefix-([0-9]+\\.)*[0-9]+\\.apk\$';
|
||||
var links = parse(res.body)
|
||||
.querySelectorAll('a')
|
||||
.map((e) => e.attributes['href'] ?? '')
|
||||
.where((e) => RegExp('https://.*$apkInURLRegexPattern').hasMatch(e))
|
||||
.toList();
|
||||
|
||||
if (links.isEmpty) {
|
||||
throw NoReleasesError();
|
||||
}
|
||||
var versionMatch = RegExp(apkInURLRegexPattern).firstMatch(links[0]);
|
||||
if (versionMatch == null) {
|
||||
throw NoVersionError();
|
||||
}
|
||||
var version = links[0].substring(
|
||||
versionMatch.start + apkNamePrefix.length + 2, versionMatch.end - 4);
|
||||
var apkUrls = [links[0]];
|
||||
return APKDetails(version, getApkUrlsFromUrls(apkUrls),
|
||||
AppNames(name, apks[apkNamePrefix]!));
|
||||
} else {
|
||||
throw getObtainiumHttpError(res);
|
||||
}
|
||||
}
|
||||
}
|
@@ -33,7 +33,9 @@ class TelegramApp extends AppSource {
|
||||
throw NoVersionError();
|
||||
}
|
||||
String? apkUrl = 'https://telegram.org/dl/android/apk';
|
||||
return APKDetails(version, getApkUrlsFromUrls([apkUrl]),
|
||||
return APKDetails(
|
||||
version,
|
||||
[MapEntry<String, String>('telegram-$version.apk', apkUrl)],
|
||||
AppNames('Telegram', 'Telegram'));
|
||||
} else {
|
||||
throw getObtainiumHttpError(res);
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class Tencent extends AppSource {
|
||||
Tencent() {
|
||||
name = 'Tencent App Store';
|
||||
name = tr('tencentAppStore');
|
||||
hosts = ['sj.qq.com'];
|
||||
naiveStandardVersionDetection = true;
|
||||
showReleaseDateAsVersionToggle = true;
|
||||
@@ -63,11 +64,11 @@ class Tencent extends AppSource {
|
||||
var author = json['app_detail_records'][appId]['app_info']['author'];
|
||||
var releaseDate =
|
||||
json['app_detail_records'][appId]['app_info']['update_time'];
|
||||
var apkName = Uri.parse(apkUrl).queryParameters['fsname'] ??
|
||||
'${appId}_${version}.apk';
|
||||
|
||||
return APKDetails(
|
||||
version,
|
||||
[MapEntry(Uri.parse(apkUrl).queryParameters['fsname']!, apkUrl)],
|
||||
AppNames(author, appName),
|
||||
version, [MapEntry(apkName, apkUrl)], AppNames(author, appName),
|
||||
releaseDate: releaseDate != null
|
||||
? DateTime.fromMillisecondsSinceEpoch(releaseDate * 1000)
|
||||
: null);
|
||||
|
@@ -42,19 +42,16 @@ class Uptodown extends AppSource {
|
||||
String? version = html.querySelector('div.version')?.innerHtml;
|
||||
String? name = html.querySelector('#detail-app-name')?.innerHtml.trim();
|
||||
String? author = html.querySelector('#author-link')?.innerHtml.trim();
|
||||
var detailElements = html.querySelectorAll('#technical-information td');
|
||||
String? appId = (detailElements.elementAtOrNull(2))?.innerHtml.trim();
|
||||
String? dateStr = (detailElements.elementAtOrNull(29))?.innerHtml.trim();
|
||||
var detailElements = html
|
||||
.querySelectorAll('#technical-information td')
|
||||
.map((e) => e.innerHtml.trim())
|
||||
.where((e) => !e.startsWith('<'))
|
||||
.toList();
|
||||
String? appId = detailElements.elementAtOrNull(0);
|
||||
String? dateStr = detailElements.elementAtOrNull(6);
|
||||
String? fileId =
|
||||
html.querySelector('#detail-app-name')?.attributes['data-file-id'];
|
||||
String? extension = html
|
||||
.querySelectorAll('td')
|
||||
.where((e) => e.text.toLowerCase().trim() == 'file type')
|
||||
.firstOrNull
|
||||
?.nextElementSibling
|
||||
?.text
|
||||
.toLowerCase()
|
||||
.trim();
|
||||
String? extension = detailElements.elementAtOrNull(7)?.toLowerCase();
|
||||
return Map.fromEntries([
|
||||
MapEntry('version', version),
|
||||
MapEntry('appId', appId),
|
||||
|
@@ -1,110 +0,0 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:html/parser.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class VLC extends AppSource {
|
||||
VLC() {
|
||||
hosts = ['videolan.org'];
|
||||
}
|
||||
get dwUrlBase => 'https://get.${hosts[0]}/vlc-android/';
|
||||
|
||||
@override
|
||||
Future<Map<String, String>?> getRequestHeaders(
|
||||
Map<String, dynamic> additionalSettings,
|
||||
{bool forAPKDownload = false}) async {
|
||||
return {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36"
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
|
||||
return 'https://${hosts[0]}';
|
||||
}
|
||||
|
||||
Future<String?> getLatestVersion(
|
||||
String standardUrl, Map<String, dynamic> additionalSettings) async {
|
||||
Response res = await sourceRequest(dwUrlBase, additionalSettings);
|
||||
if (res.statusCode == 200) {
|
||||
var dwLinks = parse(res.body)
|
||||
.querySelectorAll('a')
|
||||
.where((element) => element.attributes['href'] != 'last/')
|
||||
.map((e) => e.attributes['href']?.split('/')[0])
|
||||
.toList();
|
||||
String? version = dwLinks.isNotEmpty ? dwLinks.last : null;
|
||||
if (version == null) {
|
||||
throw NoVersionError();
|
||||
}
|
||||
return version;
|
||||
} else {
|
||||
throw getObtainiumHttpError(res);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<APKDetails> getLatestAPKDetails(
|
||||
String standardUrl,
|
||||
Map<String, dynamic> additionalSettings,
|
||||
) async {
|
||||
Response res = await get(
|
||||
Uri.parse('https://www.videolan.org/vlc/download-android.html'));
|
||||
if (res.statusCode == 200) {
|
||||
var dwUrlBase = 'get.videolan.org/vlc-android';
|
||||
var dwLinks = parse(res.body)
|
||||
.querySelectorAll('a')
|
||||
.where((element) =>
|
||||
element.attributes['href']?.contains(dwUrlBase) ?? false)
|
||||
.toList();
|
||||
String? version = dwLinks.isNotEmpty
|
||||
? dwLinks.first.attributes['href']
|
||||
?.split('/')
|
||||
.where((s) => s.isNotEmpty)
|
||||
.last
|
||||
: null;
|
||||
if (version == null) {
|
||||
throw NoVersionError();
|
||||
}
|
||||
String? targetUrl = 'https://$dwUrlBase/$version/';
|
||||
var apkUrls = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']
|
||||
.map((e) => '${targetUrl}VLC-Android-$version-$e.apk')
|
||||
.toList();
|
||||
return APKDetails(
|
||||
version, getApkUrlsFromUrls(apkUrls), AppNames('VideoLAN', 'VLC'));
|
||||
} else {
|
||||
throw getObtainiumHttpError(res);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl,
|
||||
Map<String, dynamic> additionalSettings) async {
|
||||
Response res = await sourceRequest(apkUrl, additionalSettings);
|
||||
if (res.statusCode == 200) {
|
||||
String? apkUrl =
|
||||
parse(res.body).querySelector('#alt_link')?.attributes['href'];
|
||||
if (apkUrl == null) {
|
||||
throw NoAPKError();
|
||||
}
|
||||
return apkUrl;
|
||||
} else if (res.statusCode == 500 &&
|
||||
res.body.toLowerCase().indexOf('mirror') > 0) {
|
||||
var html = parse(res.body);
|
||||
var err = '';
|
||||
html.body?.nodes.forEach((element) {
|
||||
if (element.text != null) {
|
||||
err += '${element.text}\n';
|
||||
}
|
||||
});
|
||||
err = err.trim();
|
||||
if (err.isEmpty) {
|
||||
err = tr('err');
|
||||
}
|
||||
throw ObtainiumError(err);
|
||||
} else {
|
||||
throw getObtainiumHttpError(res);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
import 'package:html/parser.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class WhatsApp extends AppSource {
|
||||
WhatsApp() {
|
||||
hosts = ['whatsapp.com'];
|
||||
versionDetectionDisallowed = true;
|
||||
}
|
||||
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
|
||||
return 'https://${hosts[0]}';
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl,
|
||||
Map<String, dynamic> additionalSettings) async {
|
||||
Response res =
|
||||
await sourceRequest('$standardUrl/android', additionalSettings);
|
||||
if (res.statusCode == 200) {
|
||||
var targetLinks = parse(res.body)
|
||||
.querySelectorAll('a')
|
||||
.map((e) => e.attributes['href'] ?? '')
|
||||
.where((e) => e.isNotEmpty)
|
||||
.where((e) => e.contains('WhatsApp.apk'))
|
||||
.toList();
|
||||
if (targetLinks.isEmpty) {
|
||||
throw NoAPKError();
|
||||
}
|
||||
return targetLinks[0];
|
||||
} else {
|
||||
throw getObtainiumHttpError(res);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<APKDetails> getLatestAPKDetails(
|
||||
String standardUrl,
|
||||
Map<String, dynamic> additionalSettings,
|
||||
) async {
|
||||
// This is a CDN link that is consistent per version
|
||||
// But it has query params that change constantly
|
||||
Uri apkUri = Uri.parse(await apkUrlPrefetchModifier(
|
||||
standardUrl, standardUrl, additionalSettings));
|
||||
var unusableApkUrl = '${apkUri.origin}/${apkUri.path}';
|
||||
// So we use the param-less URL is a pseudo-version to add the app and check for updates
|
||||
// See #357 for why we can't scrape the version number directly
|
||||
// But we re-fetch the URL again with its latest query params at the actual download time
|
||||
String version = unusableApkUrl.hashCode.toString();
|
||||
return APKDetails(version, getApkUrlsFromUrls([unusableApkUrl]),
|
||||
AppNames('Meta', 'WhatsApp'));
|
||||
}
|
||||
}
|
@@ -44,7 +44,8 @@ List<MapEntry<Locale, String>> supportedLocales = const [
|
||||
MapEntry(Locale('da'), 'Dansk'),
|
||||
MapEntry(Locale('en', 'EO'),
|
||||
'Esperanto'), // https://github.com/aissat/easy_localization/issues/220#issuecomment-846035493
|
||||
MapEntry(Locale('in'), 'Bahasa Indonesia')
|
||||
MapEntry(Locale('in'), 'Bahasa Indonesia'),
|
||||
MapEntry(Locale('ko'), '한국어'),
|
||||
];
|
||||
const fallbackLocale = Locale('en');
|
||||
const localeDir = 'assets/translations';
|
||||
@@ -244,6 +245,7 @@ class _ObtainiumState extends State<Obtainium> {
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: context.locale,
|
||||
navigatorKey: globalNavigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: settingsProvider.theme == ThemeSettings.dark
|
||||
|
@@ -538,6 +538,38 @@ class AddAppPageState extends State<AddAppPage> {
|
||||
});
|
||||
}
|
||||
}),
|
||||
if (pickedSource != null && pickedSource!.enforceTrackOnly)
|
||||
GeneratedForm(
|
||||
key: Key(
|
||||
'${pickedSource.runtimeType.toString()}-${pickedSource?.hostChanged.toString()}-${pickedSource?.hostIdenticalDespiteAnyChange.toString()}-appId'),
|
||||
items: [
|
||||
[
|
||||
GeneratedFormTextField('appId',
|
||||
label: '${tr('appId')} - ${tr('custom')}',
|
||||
required: false,
|
||||
additionalValidators: [
|
||||
(value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final isValid = RegExp(
|
||||
r'^([A-Za-z]{1}[A-Za-z\d_]*\.)+[A-Za-z][A-Za-z\d_]*$')
|
||||
.hasMatch(value);
|
||||
if (!isValid) {
|
||||
return tr('invalidInput');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
]),
|
||||
]
|
||||
],
|
||||
onValueChanges: (values, valid, isBuilding) {
|
||||
if (!isBuilding) {
|
||||
setState(() {
|
||||
additionalSettings['appId'] = values['appId'];
|
||||
});
|
||||
}
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:obtainium/components/generated_form_modal.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/main.dart';
|
||||
@@ -12,6 +13,7 @@ import 'package:obtainium/providers/source_provider.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:markdown/markdown.dart' as md;
|
||||
|
||||
class AppPage extends StatefulWidget {
|
||||
const AppPage({super.key, required this.appId});
|
||||
@@ -182,7 +184,10 @@ class _AppPageState extends State<AppPage> {
|
||||
Brightness.light
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).primaryColorLight)
|
||||
.withAlpha(20)
|
||||
.withAlpha(Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? 20
|
||||
: 40)
|
||||
: null),
|
||||
padding: settingsProvider.highlightTouchTargets
|
||||
? const EdgeInsetsDirectional.fromSTEB(12, 6, 12, 6)
|
||||
@@ -218,24 +223,41 @@ class _AppPageState extends State<AppPage> {
|
||||
if (app?.app.additionalSettings['about'] is String &&
|
||||
app?.app.additionalSettings['about'].isNotEmpty)
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 48,
|
||||
),
|
||||
GestureDetector(
|
||||
onLongPress: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: app?.app.additionalSettings['about'] ?? ''));
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(tr('copiedToClipboard')),
|
||||
));
|
||||
},
|
||||
child: Text(
|
||||
app?.app.additionalSettings['about'],
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontStyle: FontStyle.italic),
|
||||
),
|
||||
)
|
||||
onLongPress: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: app?.app.additionalSettings['about'] ?? ''));
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(tr('copiedToClipboard')),
|
||||
));
|
||||
},
|
||||
child: Markdown(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
styleSheet: MarkdownStyleSheet(
|
||||
blockquoteDecoration:
|
||||
BoxDecoration(color: Theme.of(context).cardColor),
|
||||
textAlign: WrapAlignment.center),
|
||||
data: app?.app.additionalSettings['about'],
|
||||
onTapLink: (text, href, title) {
|
||||
if (href != null) {
|
||||
launchUrlString(href,
|
||||
mode: LaunchMode.externalApplication);
|
||||
}
|
||||
},
|
||||
extensionSet: md.ExtensionSet(
|
||||
md.ExtensionSet.gitHubFlavored.blockSyntaxes,
|
||||
[
|
||||
md.EmojiSyntax(),
|
||||
...md.ExtensionSet.gitHubFlavored.inlineSyntaxes
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
],
|
||||
|
@@ -60,6 +60,9 @@ showChangeLogDialog(BuildContext context, App app, String? changesUrl,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height - 350,
|
||||
child: Markdown(
|
||||
styleSheet: MarkdownStyleSheet(
|
||||
blockquoteDecoration: BoxDecoration(
|
||||
color: Theme.of(context).cardColor)),
|
||||
data: changeLog,
|
||||
onTapLink: (text, href, title) {
|
||||
if (href != null) {
|
||||
@@ -481,7 +484,10 @@ class AppsPageState extends State<AppsPage> {
|
||||
? (Theme.of(context).brightness == Brightness.light
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).primaryColorLight)
|
||||
.withAlpha(20)
|
||||
.withAlpha(Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? 20
|
||||
: 40)
|
||||
: null),
|
||||
padding: settingsProvider.highlightTouchTargets
|
||||
? const EdgeInsetsDirectional.fromSTEB(12, 0, 12, 0)
|
||||
@@ -521,12 +527,12 @@ class AppsPageState extends State<AppsPage> {
|
||||
var transparent =
|
||||
Theme.of(context).colorScheme.surface.withAlpha(0).value;
|
||||
List<double> stops = [
|
||||
...listedApps[index].app.categories.asMap().entries.map(
|
||||
(e) => ((e.key / (listedApps[index].app.categories.length - 1)))),
|
||||
...listedApps[index].app.categories.asMap().entries.map((e) =>
|
||||
((e.key / (listedApps[index].app.categories.length - 1)) - 0.0001)),
|
||||
1
|
||||
];
|
||||
if (stops.length == 2) {
|
||||
stops[0] = 1;
|
||||
stops[0] = 0.9999;
|
||||
}
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
@@ -838,30 +844,6 @@ class AppsPageState extends State<AppsPage> {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
resetSelectedAppsInstallStatuses() async {
|
||||
try {
|
||||
var values = await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext ctx) {
|
||||
return GeneratedFormModal(
|
||||
title: tr('resetInstallStatusForSelectedAppsQuestion'),
|
||||
items: const [],
|
||||
initValid: true,
|
||||
message: tr('installStatusOfXWillBeResetExplanation',
|
||||
args: [plural('apps', selectedAppIds.length)]),
|
||||
);
|
||||
});
|
||||
if (values != null) {
|
||||
appsProvider.saveApps(selectedApps.map((e) {
|
||||
e.installedVersion = null;
|
||||
return e;
|
||||
}).toList());
|
||||
}
|
||||
} finally {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
|
||||
showMoreOptionsDialog() {
|
||||
return showDialog(
|
||||
context: context,
|
||||
|
@@ -130,13 +130,18 @@ class _HomePageState extends State<HomePage> {
|
||||
|
||||
// Check initial link if app was in cold state (terminated)
|
||||
final appLink = await _appLinks.getInitialLink();
|
||||
var initLinked = false;
|
||||
if (appLink != null) {
|
||||
await interpretLink(appLink);
|
||||
initLinked = true;
|
||||
}
|
||||
|
||||
// Handle link when app is in warm state (front or background)
|
||||
_linkSubscription = _appLinks.uriLinkStream.listen((uri) async {
|
||||
await interpretLink(uri);
|
||||
if (!initLinked) {
|
||||
await interpretLink(uri);
|
||||
} else {
|
||||
initLinked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -886,7 +886,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
launchUrlString('${settingsProvider.sourceUrl}/wiki',
|
||||
launchUrlString('https://wiki.obtainium.imranr.dev/',
|
||||
mode: LaunchMode.externalApplication);
|
||||
},
|
||||
icon: const Icon(Icons.help_outline_rounded),
|
||||
|
@@ -19,6 +19,8 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:http/io_client.dart';
|
||||
import 'package:obtainium/app_sources/directAPKLink.dart';
|
||||
import 'package:obtainium/app_sources/html.dart';
|
||||
import 'package:obtainium/components/generated_form.dart';
|
||||
import 'package:obtainium/components/generated_form_modal.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
@@ -149,13 +151,15 @@ Future<File> downloadFileWithRetry(String url, String fileName,
|
||||
{bool useExisting = true,
|
||||
Map<String, String>? headers,
|
||||
int retries = 3,
|
||||
bool allowInsecure = false}) async {
|
||||
bool allowInsecure = false,
|
||||
LogsProvider? logs}) async {
|
||||
try {
|
||||
return await downloadFile(
|
||||
url, fileName, fileNameHasExt, onProgress, destDir,
|
||||
useExisting: useExisting,
|
||||
headers: headers,
|
||||
allowInsecure: allowInsecure);
|
||||
allowInsecure: allowInsecure,
|
||||
logs: logs);
|
||||
} catch (e) {
|
||||
if (retries > 0 && e is ClientException) {
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
@@ -164,7 +168,8 @@ Future<File> downloadFileWithRetry(String url, String fileName,
|
||||
useExisting: useExisting,
|
||||
headers: headers,
|
||||
retries: (retries - 1),
|
||||
allowInsecure: allowInsecure);
|
||||
allowInsecure: allowInsecure,
|
||||
logs: logs);
|
||||
} else {
|
||||
rethrow;
|
||||
}
|
||||
@@ -217,7 +222,8 @@ Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
|
||||
Function? onProgress, String destDir,
|
||||
{bool useExisting = true,
|
||||
Map<String, String>? headers,
|
||||
bool allowInsecure = false}) async {
|
||||
bool allowInsecure = false,
|
||||
LogsProvider? logs}) async {
|
||||
// Send the initial request but cancel it as soon as you have the headers
|
||||
var reqHeaders = headers ?? {};
|
||||
var req = Request('GET', Uri.parse(url));
|
||||
@@ -278,6 +284,42 @@ Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
|
||||
// Download to a '.temp' file (to distinguish btn. complete/incomplete files)
|
||||
File tempDownloadedFile = File('${downloadedFile.path}.part');
|
||||
|
||||
// If there is already a temp file, a download may already be in progress - account for this (see #2073)
|
||||
bool tempFileExists = tempDownloadedFile.existsSync();
|
||||
if (tempFileExists && useExisting) {
|
||||
logs?.add(
|
||||
'Partial download exists - will wait: ${tempDownloadedFile.uri.pathSegments.last}');
|
||||
bool isDownloading = true;
|
||||
int currentTempFileSize = await tempDownloadedFile.length();
|
||||
bool shouldReturn = false;
|
||||
while (isDownloading) {
|
||||
await Future.delayed(Duration(seconds: 7));
|
||||
if (tempDownloadedFile.existsSync()) {
|
||||
int newTempFileSize = await tempDownloadedFile.length();
|
||||
if (newTempFileSize > currentTempFileSize) {
|
||||
currentTempFileSize = newTempFileSize;
|
||||
logs?.add(
|
||||
'Existing partial download still in progress: ${tempDownloadedFile.uri.pathSegments.last}');
|
||||
} else {
|
||||
logs?.add(
|
||||
'Ignoring existing partial download: ${tempDownloadedFile.uri.pathSegments.last}');
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
shouldReturn = downloadedFile.existsSync();
|
||||
}
|
||||
}
|
||||
if (shouldReturn) {
|
||||
logs?.add(
|
||||
'Existing partial download completed - not repeating: ${tempDownloadedFile.uri.pathSegments.last}');
|
||||
client.close();
|
||||
return downloadedFile;
|
||||
} else {
|
||||
logs?.add(
|
||||
'Existing partial download not in progress: ${tempDownloadedFile.uri.pathSegments.last}');
|
||||
}
|
||||
}
|
||||
|
||||
// If the range feature is not available (or you need to start a ranged req from 0),
|
||||
// complete the already-started request, else cancel it and start a ranged request,
|
||||
// and open the file for writing in the appropriate mode
|
||||
@@ -417,9 +459,7 @@ class AppsProvider with ChangeNotifier {
|
||||
// Delete any partial APKs (if safe to do so)
|
||||
var cutoff = DateTime.now().subtract(const Duration(days: 7));
|
||||
APKDir.listSync()
|
||||
.where((element) =>
|
||||
element.path.endsWith('.part') ||
|
||||
element.statSync().modified.isBefore(cutoff))
|
||||
.where((element) => element.statSync().modified.isBefore(cutoff))
|
||||
.forEach((partialApk) {
|
||||
if (!areDownloadsRunning()) {
|
||||
partialApk.delete(recursive: true);
|
||||
@@ -493,7 +533,8 @@ class AppsProvider with ChangeNotifier {
|
||||
prevProg = prog;
|
||||
}, APKDir.path,
|
||||
useExisting: useExisting,
|
||||
allowInsecure: app.additionalSettings['allowInsecure'] == true);
|
||||
allowInsecure: app.additionalSettings['allowInsecure'] == true,
|
||||
logs: logs);
|
||||
// Set to 90 for remaining steps, will make null in 'finally'
|
||||
if (apps[app.id] != null) {
|
||||
apps[app.id]!.downloadProgress = -1;
|
||||
@@ -516,11 +557,29 @@ class AppsProvider with ChangeNotifier {
|
||||
.listSync()
|
||||
.where((e) => e.path.toLowerCase().endsWith('.apk'))
|
||||
.toList();
|
||||
|
||||
FileSystemEntity? temp;
|
||||
apks.removeWhere((element) {
|
||||
bool res = element.uri.pathSegments.last.startsWith(app.id);
|
||||
if (res) {
|
||||
temp = element;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
if (temp != null) {
|
||||
apks = [
|
||||
temp!,
|
||||
...apks,
|
||||
];
|
||||
}
|
||||
|
||||
for (var i = 0; i < apks.length; i++) {
|
||||
try {
|
||||
newInfo = await pm.getPackageArchiveInfo(
|
||||
archiveFilePath: apks.first.path);
|
||||
break;
|
||||
newInfo =
|
||||
await pm.getPackageArchiveInfo(archiveFilePath: apks[i].path);
|
||||
if (newInfo != null) {
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
if (i == apks.length - 1) {
|
||||
rethrow;
|
||||
@@ -644,28 +703,47 @@ class AppsProvider with ChangeNotifier {
|
||||
var somethingInstalled = false;
|
||||
try {
|
||||
MultiAppMultiError errors = MultiAppMultiError();
|
||||
List<File> APKFiles = [];
|
||||
for (var file in dir.extracted
|
||||
.listSync(recursive: true, followLinks: false)
|
||||
.whereType<File>()) {
|
||||
if (file.path.toLowerCase().endsWith('.apk')) {
|
||||
try {
|
||||
somethingInstalled = somethingInstalled ||
|
||||
await installApk(
|
||||
DownloadedApk(dir.appId, file), firstTimeWithContext,
|
||||
needsBGWorkaround: needsBGWorkaround,
|
||||
shizukuPretendToBeGooglePlay: shizukuPretendToBeGooglePlay);
|
||||
} catch (e) {
|
||||
logs.add(
|
||||
'Could not install APK from XAPK \'${file.path}\': ${e.toString()}');
|
||||
errors.add(dir.appId, e, appName: apps[dir.appId]?.name);
|
||||
}
|
||||
APKFiles.add(file);
|
||||
} else if (file.path.toLowerCase().endsWith('.obb')) {
|
||||
await moveObbFile(file, dir.appId);
|
||||
}
|
||||
}
|
||||
if (somethingInstalled) {
|
||||
|
||||
File? temp;
|
||||
APKFiles.removeWhere((element) {
|
||||
bool res = element.uri.pathSegments.last.startsWith(dir.appId);
|
||||
if (res) {
|
||||
temp = element;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
if (temp != null) {
|
||||
APKFiles = [
|
||||
temp!,
|
||||
...APKFiles,
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
await installApk(
|
||||
DownloadedApk(dir.appId, APKFiles[0]), firstTimeWithContext,
|
||||
needsBGWorkaround: needsBGWorkaround,
|
||||
shizukuPretendToBeGooglePlay: shizukuPretendToBeGooglePlay,
|
||||
additionalAPKs: APKFiles.sublist(1)
|
||||
.map((a) => DownloadedApk(dir.appId, a))
|
||||
.toList());
|
||||
somethingInstalled = true;
|
||||
dir.file.delete(recursive: true);
|
||||
} else if (errors.idsByErrorString.isNotEmpty) {
|
||||
} catch (e) {
|
||||
logs.add('Could not install APKs from XAPK: ${e.toString()}');
|
||||
errors.add(dir.appId, e, appName: apps[dir.appId]?.name);
|
||||
}
|
||||
if (errors.idsByErrorString.isNotEmpty) {
|
||||
throw errors;
|
||||
}
|
||||
} finally {
|
||||
@@ -677,7 +755,8 @@ class AppsProvider with ChangeNotifier {
|
||||
Future<bool> installApk(
|
||||
DownloadedApk file, BuildContext? firstTimeWithContext,
|
||||
{bool needsBGWorkaround = false,
|
||||
bool shizukuPretendToBeGooglePlay = false}) async {
|
||||
bool shizukuPretendToBeGooglePlay = false,
|
||||
List<DownloadedApk> additionalAPKs = const []}) async {
|
||||
if (firstTimeWithContext != null &&
|
||||
settingsProvider.beforeNewInstallsShareToAppVerifier &&
|
||||
(await getInstalledInfo('dev.soupslurpr.appverifier')) != null) {
|
||||
@@ -693,6 +772,7 @@ class AppsProvider with ChangeNotifier {
|
||||
if (newInfo == null) {
|
||||
try {
|
||||
file.file.deleteSync(recursive: true);
|
||||
additionalAPKs.forEach((a) => a.file.deleteSync(recursive: true));
|
||||
} catch (e) {
|
||||
//
|
||||
} finally {
|
||||
@@ -700,6 +780,8 @@ class AppsProvider with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
PackageInfo? appInfo = await getInstalledInfo(apps[file.appId]!.app.id);
|
||||
logs.add(
|
||||
'Installing "${newInfo.packageName}" version "${newInfo.versionName}" versionCode "${newInfo.versionCode}"${appInfo != null ? ' (from existing version "${appInfo.versionName}" versionCode "${appInfo.versionCode}")' : ''}');
|
||||
if (appInfo != null &&
|
||||
newInfo.versionCode! < appInfo.versionCode! &&
|
||||
!(await canDowngradeApps())) {
|
||||
@@ -718,8 +800,10 @@ class AppsProvider with ChangeNotifier {
|
||||
}
|
||||
int? code;
|
||||
if (!settingsProvider.useShizuku) {
|
||||
code =
|
||||
await AndroidPackageInstaller.installApk(apkFilePath: file.file.path);
|
||||
var allAPKs = [file.file.path];
|
||||
allAPKs.addAll(additionalAPKs.map((a) => a.file.path));
|
||||
code = await AndroidPackageInstaller.installApk(
|
||||
apkFilePath: allAPKs.join(','));
|
||||
} else {
|
||||
code = await ShizukuApkInstaller.installAPK(file.file.uri.toString(),
|
||||
shizukuPretendToBeGooglePlay ? "com.android.vending" : "");
|
||||
@@ -743,6 +827,10 @@ class AppsProvider with ChangeNotifier {
|
||||
return installed;
|
||||
}
|
||||
|
||||
Future<String> getStorageRootPath() async {
|
||||
return '/${(await getExternalStorageDirectory())!.uri.pathSegments.sublist(0, 3).join('/')}';
|
||||
}
|
||||
|
||||
Future<void> moveObbFile(File file, String appId) async {
|
||||
if (!file.path.toLowerCase().endsWith('.obb')) return;
|
||||
|
||||
@@ -751,7 +839,7 @@ class AppsProvider with ChangeNotifier {
|
||||
await Permission.storage.request();
|
||||
}
|
||||
|
||||
String obbDirPath = "/storage/emulated/0/Android/obb/$appId";
|
||||
String obbDirPath = "${await getStorageRootPath()}/Android/obb/$appId";
|
||||
Directory(obbDirPath).createSync(recursive: true);
|
||||
|
||||
String obbFileName = file.path.split("/").last;
|
||||
@@ -841,6 +929,11 @@ class AppsProvider with ChangeNotifier {
|
||||
}
|
||||
MapEntry<String, String>? apkUrl;
|
||||
var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true;
|
||||
var refreshBeforeDownload =
|
||||
apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true;
|
||||
if (refreshBeforeDownload) {
|
||||
await checkUpdate(apps[id]!.app.id);
|
||||
}
|
||||
if (!trackOnly) {
|
||||
// ignore: use_build_context_synchronously
|
||||
apkUrl = await confirmAppFileUrl(apps[id]!.app, context, false);
|
||||
@@ -1027,11 +1120,25 @@ class AppsProvider with ChangeNotifier {
|
||||
throw ObtainiumError(tr('appNotFound'));
|
||||
}
|
||||
MapEntry<String, String>? fileUrl;
|
||||
var refreshBeforeDownload =
|
||||
apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true;
|
||||
if (refreshBeforeDownload) {
|
||||
await checkUpdate(apps[id]!.app.id);
|
||||
}
|
||||
if (apps[id]!.app.apkUrls.isNotEmpty ||
|
||||
apps[id]!.app.otherAssetUrls.isNotEmpty) {
|
||||
// ignore: use_build_context_synchronously
|
||||
fileUrl = await confirmAppFileUrl(apps[id]!.app, context, true,
|
||||
MapEntry<String, String>? tempFileUrl = await confirmAppFileUrl(
|
||||
apps[id]!.app, context, true,
|
||||
evenIfSingleChoice: true);
|
||||
if (tempFileUrl != null) {
|
||||
fileUrl = MapEntry(
|
||||
tempFileUrl.key,
|
||||
await (SourceProvider().getSource(apps[id]!.app.url,
|
||||
overrideSource: apps[id]!.app.overrideSource))
|
||||
.apkUrlPrefetchModifier(tempFileUrl.value, apps[id]!.app.url,
|
||||
apps[id]!.app.additionalSettings));
|
||||
}
|
||||
}
|
||||
if (fileUrl != null) {
|
||||
filesToDownload.add(MapEntry(fileUrl, apps[id]!.app));
|
||||
@@ -1044,17 +1151,7 @@ class AppsProvider with ChangeNotifier {
|
||||
|
||||
Future<void> downloadFn(MapEntry<String, String> fileUrl, App app) async {
|
||||
try {
|
||||
var exportDir = await settingsProvider.getExportDir();
|
||||
String downloadPath = '/storage/emulated/0/Download';
|
||||
bool downloadsAccessible = false;
|
||||
try {
|
||||
downloadsAccessible = Directory(downloadPath).existsSync();
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
if (!downloadsAccessible && exportDir != null) {
|
||||
downloadPath = exportDir.path;
|
||||
}
|
||||
String downloadPath = '${await getStorageRootPath()}/Download';
|
||||
await downloadFile(fileUrl.value, fileUrl.key, true,
|
||||
(double? progress) {
|
||||
notificationsProvider
|
||||
@@ -1066,7 +1163,8 @@ class AppsProvider with ChangeNotifier {
|
||||
forAPKDownload:
|
||||
fileUrl.key.endsWith('.apk') ? true : false),
|
||||
useExisting: false,
|
||||
allowInsecure: app.additionalSettings['allowInsecure'] == true);
|
||||
allowInsecure: app.additionalSettings['allowInsecure'] == true,
|
||||
logs: logs);
|
||||
notificationsProvider
|
||||
.notify(DownloadedNotification(fileUrl.key, fileUrl.value));
|
||||
} catch (e) {
|
||||
@@ -1103,17 +1201,25 @@ class AppsProvider with ChangeNotifier {
|
||||
if (app?.app == null) {
|
||||
return false;
|
||||
}
|
||||
var source = SourceProvider()
|
||||
.getSource(app!.app.url, overrideSource: app.app.overrideSource);
|
||||
var naiveStandardVersionDetection =
|
||||
app!.app.additionalSettings['naiveStandardVersionDetection'] == true ||
|
||||
SourceProvider()
|
||||
.getSource(app.app.url, overrideSource: app.app.overrideSource)
|
||||
.naiveStandardVersionDetection;
|
||||
app.app.additionalSettings['naiveStandardVersionDetection'] == true ||
|
||||
source.naiveStandardVersionDetection;
|
||||
String? realInstalledVersion =
|
||||
app.app.additionalSettings['useVersionCodeAsOSVersion'] == true
|
||||
? app.installedInfo?.versionCode.toString()
|
||||
: app.installedInfo?.versionName;
|
||||
bool isHTMLWithNoVersionDetection =
|
||||
(source.runtimeType == HTML().runtimeType &&
|
||||
(app.app.additionalSettings['versionExtractionRegEx'] as String?)
|
||||
?.isNotEmpty !=
|
||||
true);
|
||||
bool isDirectAPKLink = source.runtimeType == DirectAPKLink().runtimeType;
|
||||
return app.app.additionalSettings['trackOnly'] != true &&
|
||||
app.app.additionalSettings['releaseDateAsVersion'] != true &&
|
||||
!isHTMLWithNoVersionDetection &&
|
||||
!isDirectAPKLink &&
|
||||
realInstalledVersion != null &&
|
||||
app.app.installedVersion != null &&
|
||||
(reconcileVersionDifferences(
|
||||
@@ -1184,6 +1290,7 @@ class AppsProvider with ChangeNotifier {
|
||||
!isVersionDetectionPossible(
|
||||
AppInMemory(app, null, installedInfo, null))) {
|
||||
app.additionalSettings['versionDetection'] = false;
|
||||
app.installedVersion = app.latestVersion;
|
||||
logs.add('Could not reconcile version formats for: ${app.id}');
|
||||
modded = true;
|
||||
}
|
||||
@@ -1347,8 +1454,10 @@ class AppsProvider with ChangeNotifier {
|
||||
app = getCorrectedInstallStatusAppIfPossible(app, info) ?? app;
|
||||
}
|
||||
if (!onlyIfExists || this.apps.containsKey(app.id)) {
|
||||
File('${(await getAppsDir()).path}/${app.id}.json')
|
||||
.writeAsStringSync(jsonEncode(app.toJson()));
|
||||
String filePath = '${(await getAppsDir()).path}/${app.id}.json';
|
||||
File('$filePath.tmp')
|
||||
.writeAsStringSync(jsonEncode(app.toJson())); // #2089
|
||||
File('$filePath.tmp').renameSync(filePath);
|
||||
}
|
||||
try {
|
||||
this.apps.update(app.id,
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:obtainium/providers/settings_provider.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class ObtainiumNotification {
|
||||
@@ -44,23 +45,19 @@ class SilentUpdateNotification extends ObtainiumNotification {
|
||||
SilentUpdateNotification(List<App> updates, bool succeeded, {int? id})
|
||||
: super(
|
||||
id ?? 3,
|
||||
succeeded
|
||||
? tr('appsUpdated')
|
||||
: tr('appsNotUpdated'),
|
||||
succeeded ? tr('appsUpdated') : tr('appsNotUpdated'),
|
||||
'',
|
||||
'APPS_UPDATED',
|
||||
tr('appsUpdatedNotifChannel'),
|
||||
tr('appsUpdatedNotifDescription'),
|
||||
Importance.defaultImportance) {
|
||||
message = updates.length == 1
|
||||
? tr(succeeded
|
||||
? 'xWasUpdatedToY'
|
||||
: 'xWasNotUpdatedToY',
|
||||
args: [updates[0].finalName, updates[0].latestVersion])
|
||||
: plural(succeeded
|
||||
? 'xAndNMoreUpdatesInstalled'
|
||||
: "xAndNMoreUpdatesFailed",
|
||||
updates.length - 1, args: [updates[0].finalName, (updates.length - 1).toString()]);
|
||||
? tr(succeeded ? 'xWasUpdatedToY' : 'xWasNotUpdatedToY',
|
||||
args: [updates[0].finalName, updates[0].latestVersion])
|
||||
: plural(
|
||||
succeeded ? 'xAndNMoreUpdatesInstalled' : "xAndNMoreUpdatesFailed",
|
||||
updates.length - 1,
|
||||
args: [updates[0].finalName, (updates.length - 1).toString()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +211,7 @@ class NotificationsProvider {
|
||||
channelDescription: channelDescription,
|
||||
importance: importance,
|
||||
priority: importanceToPriority[importance]!,
|
||||
groupKey: 'dev.imranr.obtainium.$channelCode',
|
||||
groupKey: '$obtainiumId.$channelCode',
|
||||
progress: progPercent ?? 0,
|
||||
maxProgress: 100,
|
||||
showProgress: progPercent != null,
|
||||
|
@@ -23,18 +23,16 @@ import 'package:obtainium/app_sources/izzyondroid.dart';
|
||||
import 'package:obtainium/app_sources/html.dart';
|
||||
import 'package:obtainium/app_sources/jenkins.dart';
|
||||
import 'package:obtainium/app_sources/neutroncode.dart';
|
||||
import 'package:obtainium/app_sources/signal.dart';
|
||||
import 'package:obtainium/app_sources/rustore.dart';
|
||||
import 'package:obtainium/app_sources/sourceforge.dart';
|
||||
import 'package:obtainium/app_sources/sourcehut.dart';
|
||||
import 'package:obtainium/app_sources/steammobile.dart';
|
||||
import 'package:obtainium/app_sources/telegramapp.dart';
|
||||
import 'package:obtainium/app_sources/tencent.dart';
|
||||
import 'package:obtainium/app_sources/uptodown.dart';
|
||||
import 'package:obtainium/app_sources/vlc.dart';
|
||||
import 'package:obtainium/app_sources/whatsapp.dart';
|
||||
import 'package:obtainium/components/generated_form.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/mass_app_sources/githubstars.dart';
|
||||
import 'package:obtainium/providers/logs_provider.dart';
|
||||
import 'package:obtainium/providers/settings_provider.dart';
|
||||
|
||||
class AppNames {
|
||||
@@ -155,10 +153,6 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
|
||||
additionalSettings['autoApkFilterByArch'] = false;
|
||||
}
|
||||
if (source.runtimeType == HTML().runtimeType) {
|
||||
// HTML 'fixed URL' support should be disabled if it previously did not exist
|
||||
if (originalAdditionalSettings['supportFixedAPKURL'] == null) {
|
||||
additionalSettings['supportFixedAPKURL'] = false;
|
||||
}
|
||||
// HTML key rename
|
||||
if (originalAdditionalSettings['sortByFileNamesNotLinks'] != null) {
|
||||
additionalSettings['sortByLastLinkSegment'] =
|
||||
@@ -183,7 +177,7 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
|
||||
}).toList();
|
||||
}
|
||||
// Steam source apps should be converted to HTML (#1244)
|
||||
var legacySteamSourceApps = SteamMobile().apks.keys;
|
||||
var legacySteamSourceApps = ['steam', 'steam-chat-app'];
|
||||
if (legacySteamSourceApps.contains(additionalSettings['app'] ?? '')) {
|
||||
json['url'] = '${json['url']}/mobile';
|
||||
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
|
||||
@@ -200,6 +194,72 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
|
||||
replacementAdditionalSettings['matchGroupToUse'] = '\$1';
|
||||
additionalSettings = replacementAdditionalSettings;
|
||||
}
|
||||
// Signal apps from before it was removed should be converted to HTML (#1928)
|
||||
if (json['url'] == 'https://signal.org' &&
|
||||
json['id'] == 'org.thoughtcrime.securesms' &&
|
||||
json['author'] == 'Signal' &&
|
||||
json['name'] == 'Signal' &&
|
||||
json['overrideSource'] == null &&
|
||||
additionalSettings['trackOnly'] == false &&
|
||||
additionalSettings['versionExtractionRegEx'] == '' &&
|
||||
json['lastUpdateCheck'] != null) {
|
||||
json['url'] = 'https://updates.signal.org/android/latest.json';
|
||||
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
|
||||
HTML().combinedAppSpecificSettingFormItems);
|
||||
replacementAdditionalSettings['versionExtractionRegEx'] =
|
||||
'\\d+.\\d+.\\d+';
|
||||
additionalSettings = replacementAdditionalSettings;
|
||||
}
|
||||
// WhatsApp from before it was removed should be converted to HTML (#1943)
|
||||
if (json['url'] == 'https://whatsapp.com' &&
|
||||
json['id'] == 'com.whatsapp' &&
|
||||
json['author'] == 'Meta' &&
|
||||
json['name'] == 'WhatsApp' &&
|
||||
json['overrideSource'] == null &&
|
||||
additionalSettings['trackOnly'] == false &&
|
||||
additionalSettings['versionExtractionRegEx'] == '' &&
|
||||
json['lastUpdateCheck'] != null) {
|
||||
json['url'] = 'https://whatsapp.com/android';
|
||||
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
|
||||
HTML().combinedAppSpecificSettingFormItems);
|
||||
replacementAdditionalSettings['refreshBeforeDownload'] = true;
|
||||
additionalSettings = replacementAdditionalSettings;
|
||||
}
|
||||
// VLC from before it was removed should be converted to HTML (#1943)
|
||||
if (json['url'] == 'https://videolan.org' &&
|
||||
json['id'] == 'org.videolan.vlc' &&
|
||||
json['author'] == 'VideoLAN' &&
|
||||
json['name'] == 'VLC' &&
|
||||
json['overrideSource'] == null &&
|
||||
additionalSettings['trackOnly'] == false &&
|
||||
additionalSettings['versionExtractionRegEx'] == '' &&
|
||||
json['lastUpdateCheck'] != null) {
|
||||
json['url'] = 'https://www.videolan.org/vlc/download-android.html';
|
||||
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
|
||||
HTML().combinedAppSpecificSettingFormItems);
|
||||
replacementAdditionalSettings['refreshBeforeDownload'] = true;
|
||||
replacementAdditionalSettings['intermediateLink'] =
|
||||
<Map<String, dynamic>>[
|
||||
{
|
||||
'customLinkFilterRegex': 'APK',
|
||||
'filterByLinkText': true,
|
||||
'skipSort': false,
|
||||
'reverseSort': false,
|
||||
'sortByLastLinkSegment': false
|
||||
},
|
||||
{
|
||||
'customLinkFilterRegex': 'arm64-v8a\\.apk\$',
|
||||
'filterByLinkText': false,
|
||||
'skipSort': false,
|
||||
'reverseSort': false,
|
||||
'sortByLastLinkSegment': false
|
||||
}
|
||||
];
|
||||
replacementAdditionalSettings['versionExtractionRegEx'] =
|
||||
'/vlc-android/([^/]+)/';
|
||||
replacementAdditionalSettings['matchGroupToUse'] = "1";
|
||||
additionalSettings = replacementAdditionalSettings;
|
||||
}
|
||||
}
|
||||
json['additionalSettings'] = jsonEncode(additionalSettings);
|
||||
// F-Droid no longer needs cloudflare exception since override can be used - migrate apps appropriately
|
||||
@@ -226,7 +286,7 @@ class App {
|
||||
late String name;
|
||||
String? installedVersion;
|
||||
late String latestVersion;
|
||||
List<MapEntry<String, String>> apkUrls = [];
|
||||
List<MapEntry<String, String>> apkUrls = []; // Key is name, value is URL
|
||||
List<MapEntry<String, String>> otherAssetUrls = [];
|
||||
late int preferredApkIndex;
|
||||
late Map<String, dynamic> additionalSettings;
|
||||
@@ -290,7 +350,14 @@ class App {
|
||||
otherAssetUrls: otherAssetUrls);
|
||||
|
||||
factory App.fromJson(Map<String, dynamic> json) {
|
||||
json = appJSONCompatibilityModifiers(json);
|
||||
Map<String, dynamic> originalJSON = new Map.from(json);
|
||||
try {
|
||||
json = appJSONCompatibilityModifiers(json);
|
||||
} catch (e) {
|
||||
json = originalJSON;
|
||||
LogsProvider().add(
|
||||
'Error running JSON compat modifiers: ${e.toString()}: ${originalJSON.toString()}');
|
||||
}
|
||||
return App(
|
||||
json['id'] as String,
|
||||
json['url'] as String,
|
||||
@@ -571,7 +638,11 @@ abstract class AppSource {
|
||||
GeneratedFormSwitch('skipUpdateNotifications',
|
||||
label: tr('skipUpdateNotifications'))
|
||||
],
|
||||
[GeneratedFormTextField('about', label: tr('about'), required: false)]
|
||||
[GeneratedFormTextField('about', label: tr('about'), required: false)],
|
||||
[
|
||||
GeneratedFormSwitch('refreshBeforeDownload',
|
||||
label: tr('refreshBeforeDownload'))
|
||||
]
|
||||
];
|
||||
|
||||
// Previous 2 variables combined into one at runtime for convenient usage
|
||||
@@ -794,9 +865,7 @@ class SourceProvider {
|
||||
Tencent(),
|
||||
Jenkins(),
|
||||
APKMirror(),
|
||||
Signal(),
|
||||
VLC(),
|
||||
WhatsApp(),
|
||||
RuStore(),
|
||||
TelegramApp(),
|
||||
NeutronCode(),
|
||||
DirectAPKLink(),
|
||||
@@ -922,6 +991,9 @@ class SourceProvider {
|
||||
name = name.isNotEmpty ? name : apk.names.name;
|
||||
App finalApp = App(
|
||||
currentApp?.id ??
|
||||
((additionalSettings['appId'] != null)
|
||||
? additionalSettings['appId']
|
||||
: null) ??
|
||||
(!trackOnly &&
|
||||
(!source.appIdInferIsOptional ||
|
||||
(source.appIdInferIsOptional && inferAppIdIfOptional))
|
||||
|
372
pubspec.lock
@@ -5,26 +5,27 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: android_intent_plus
|
||||
sha256: "38921ec22ebb3b9a7eb678792cf6fab0b6f458b61b9d327688573449c9b47db3"
|
||||
sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.2.0"
|
||||
version: "5.3.0"
|
||||
android_package_installer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: ba2aa7a11edc2649d1d80c25ed9291521262f714
|
||||
resolved-ref: "6109d0b1dc015c016e113ded3dd80ac823f790ab"
|
||||
url: "https://github.com/ImranR98/android_package_installer"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
android_package_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: android_package_manager
|
||||
sha256: "2de859fae7226a7de1c1ff9a2308f1967599408800330501a1ce97927c051153"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
path: "."
|
||||
ref: master
|
||||
resolved-ref: "18231a8a2343747440b0bfe90f7d56ef7f586099"
|
||||
url: "https://github.com/ImranR98/android_package_manager"
|
||||
source: git
|
||||
version: "0.7.1"
|
||||
android_system_font:
|
||||
dependency: "direct main"
|
||||
@@ -47,10 +48,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: app_links
|
||||
sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99
|
||||
sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.2"
|
||||
version: "6.3.3"
|
||||
app_links_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -79,10 +80,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
||||
sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.6.1"
|
||||
version: "4.0.2"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -95,10 +96,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
version: "2.12.0"
|
||||
background_fetch:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -111,10 +112,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: battery_plus
|
||||
sha256: "4b6dc87ffa72f8d1e63ae17c8700ee374a462e521f0152e2c76cfff484610764"
|
||||
sha256: a0409fe7d21905987eb1348ad57c634f913166f14f0c8936b73d3f5940fac551
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "6.2.1"
|
||||
battery_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -127,18 +128,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -151,34 +152,34 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
|
||||
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.1"
|
||||
version: "0.4.2"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.2"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
version: "1.19.1"
|
||||
connectivity_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: connectivity_plus
|
||||
sha256: "876849631b0c7dc20f8b471a2a03142841b482438e3b707955464f5ffca3e4c3"
|
||||
sha256: "04bf81bb0b77de31557b58d052b24b3eee33f09a6e7a8c68a3e247c7df19ec27"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "6.1.3"
|
||||
connectivity_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -207,10 +208,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: csslib
|
||||
sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
|
||||
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.0.2"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -223,26 +224,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dbus
|
||||
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
|
||||
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.10"
|
||||
version: "0.7.11"
|
||||
device_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: device_info_plus
|
||||
sha256: c4af09051b4f0508f6c1dc0a5c085bf014d5c9a4a0678ce1799c2b4d716387a0
|
||||
sha256: "72d146c6d7098689ff5c5f66bcf593ac11efc530095385356e131070333e64da"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.1.0"
|
||||
version: "11.3.0"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
|
||||
sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
version: "7.0.2"
|
||||
dynamic_color:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -255,10 +256,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: easy_localization
|
||||
sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201
|
||||
sha256: "0f5239c7b8ab06c66440cfb0e9aa4b4640429c6668d5a42fe389c5de42220b12"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.7"
|
||||
version: "3.0.7+1"
|
||||
easy_logger:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -279,10 +280,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
version: "1.3.2"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -303,10 +304,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_picker
|
||||
sha256: aac85f20436608e01a6ffd1fdd4e746a7f33c93a2c83752e626bdfaea139b877
|
||||
sha256: "3d57312a53746ed4eb8c843dc50372454bbda37dd0c01a4d40fedc83e2ce4921"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.1.3"
|
||||
version: "8.3.5"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -319,18 +320,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flex_color_picker
|
||||
sha256: "12dc855ae8ef5491f529b1fc52c655f06dcdf4114f1f7fdecafa41eec2ec8d79"
|
||||
sha256: c083b79f1c57eaeed9f464368be376951230b3cb1876323b784626152a86e480
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.6.0"
|
||||
version: "3.7.0"
|
||||
flex_seed_scheme:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flex_seed_scheme
|
||||
sha256: "7639d2c86268eff84a909026eb169f008064af0fb3696a651b24b0fa24a40334"
|
||||
sha256: d3ba3c5c92d2d79d45e94b4c6c71d01fac3c15017da1545880c53864da5dfeb0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
version: "3.5.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -344,14 +345,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.3"
|
||||
flutter_charset_detector:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_charset_detector
|
||||
sha256: d7c11a82c2c51cb35a010b42c64001afb8a9e4d7be1f57620604d386d3467ad1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
flutter_charset_detector_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_charset_detector_android
|
||||
sha256: "443145e8fc8515b3b32aee375691e40dd59197a86a2ae153166bc88c8200d83b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
flutter_charset_detector_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_charset_detector_darwin
|
||||
sha256: daac20390275efb92fbb14350fe11286c5e29c7b80d6b0867f52d760f0d69763
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter_charset_detector_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_charset_detector_platform_interface
|
||||
sha256: "1c09ed7b314a5a9dde76057b98b7d35458ba881eed03d5e5b6f7f74b4869d18c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter_charset_detector_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_charset_detector_web
|
||||
sha256: b547194e97e15d2cca17e957ad7f373b48abf35080e645ac5b6976d129b0265d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
flutter_fgbg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_fgbg
|
||||
sha256: e02ad0738ba5fc7f331b62acb0d74aa540626a6441ae18fad685faa5ac4ad7a5
|
||||
sha256: eb6da9b2047372566a6e17b505975fe5bace94af01f6fc825c4b6f81baa6c447
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
version: "0.7.1"
|
||||
flutter_keyboard_visibility:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -404,10 +445,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_launcher_icons
|
||||
sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77"
|
||||
sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.14.1"
|
||||
version: "0.14.3"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -420,26 +461,26 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_local_notifications
|
||||
sha256: "49eeef364fddb71515bc78d5a8c51435a68bccd6e4d68e25a942c5e47761ae71"
|
||||
sha256: ef41ae901e7529e52934feba19ed82827b11baa67336829564aeab3129460610
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "17.2.3"
|
||||
version: "18.0.1"
|
||||
flutter_local_notifications_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_linux
|
||||
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
|
||||
sha256: "8f685642876742c941b29c32030f6f4f6dacd0e4eaecb3efbb187d6a3812ca01"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
version: "5.0.0"
|
||||
flutter_local_notifications_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_platform_interface
|
||||
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
|
||||
sha256: "6c5b83c86bf819cdb177a9247a3722067dd8cc6313827ce7c77a4b238a26fd52"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.0"
|
||||
version: "8.0.0"
|
||||
flutter_localizations:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -449,18 +490,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
sha256: bd9c475d9aae256369edacafc29d1e74c81f78a10cdcdacbbbc9e3c43d009e4a
|
||||
sha256: e7bbc718adc9476aa14cfddc1ef048d2e21e4e8f18311aaac723266db9f9e7b5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.4"
|
||||
version: "0.7.6+2"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398"
|
||||
sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.23"
|
||||
version: "2.0.24"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@@ -483,18 +524,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluttertoast
|
||||
sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc"
|
||||
sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.2.8"
|
||||
version: "8.2.12"
|
||||
fraction:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fraction
|
||||
sha256: ac0d9904bb8211eb28606bdf623ff9f222c53240d8e9b927a07c149d356eddc2
|
||||
sha256: "7804c9a73d26bd3d5ccf52b7225eecd0af4e33b310729726dc8f8bb14c217716"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.3"
|
||||
version: "5.0.4"
|
||||
gtk:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -515,34 +556,34 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: html
|
||||
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
|
||||
sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.15.4"
|
||||
version: "0.15.5"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
version: "1.3.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
version: "4.1.2"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d
|
||||
sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
version: "4.5.2"
|
||||
intl:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -551,6 +592,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -563,18 +612,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.5"
|
||||
version: "10.0.8"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.9"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -587,26 +636,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413"
|
||||
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "5.1.1"
|
||||
markdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: markdown
|
||||
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
|
||||
sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.2"
|
||||
version: "7.3.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16+1"
|
||||
version: "0.12.17"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -619,10 +668,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.16.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -651,34 +700,34 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.9.1"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.5"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
|
||||
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.12"
|
||||
version: "2.2.15"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -731,10 +780,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_html
|
||||
sha256: af26edbbb1f2674af65a8f4b56e1a6f526156bc273d0e65dd8075fab51c78851
|
||||
sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3+2"
|
||||
version: "0.1.3+5"
|
||||
permission_handler_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -807,6 +856,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.2+1"
|
||||
posix:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: posix
|
||||
sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.1"
|
||||
provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -819,42 +876,42 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: share_plus
|
||||
sha256: "334fcdf0ef9c0df0e3b428faebcac9568f35c747d59831474b2fc56e156d244e"
|
||||
sha256: fce43200aa03ea87b91ce4c3ac79f0cecd52e2a7a56c7a4185023c271fbfa6da
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.1.0"
|
||||
version: "10.1.4"
|
||||
share_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_platform_interface
|
||||
sha256: c57c0bbfec7142e3a0f55633be504b796af72e60e3c791b44d5a017b985f7a48
|
||||
sha256: cc012a23fc2d479854e6c80150696c4a5f5bb62cb89af4de1c505cf78d0a5d0b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.1"
|
||||
version: "5.0.2"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
|
||||
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.5.2"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
|
||||
sha256: ea86be7b7114f9e94fddfbb52649e59a03d6627ccd2387ebddcd6624719e9f16
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
version: "2.4.5"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
|
||||
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.3"
|
||||
version: "2.5.4"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -890,11 +947,12 @@ packages:
|
||||
shared_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_storage
|
||||
sha256: cf20428d06af065311b71e09cbfbbfe431e979a3bf9180001c1952129b7c708f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.1"
|
||||
path: "."
|
||||
ref: master
|
||||
resolved-ref: "8784c39b909324df8913dd30fa416b8a50d55f49"
|
||||
url: "https://github.com/AlexBacich/shared-storage"
|
||||
source: git
|
||||
version: "0.7.0"
|
||||
shizuku_apk_installer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -908,15 +966,15 @@ packages:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
version: "0.0.0"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
version: "1.10.1"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -929,34 +987,34 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite
|
||||
sha256: "79a297dc3cc137e758c6a4baf83342b039e5a6d2436fcdf3f96a00adaaf2ad62"
|
||||
sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.2"
|
||||
sqflite_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_android
|
||||
sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
|
||||
sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.1"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
sha256: "4468b24876d673418a7b7147e5a08a715b4998a7ae69227acafaab762e0e5490"
|
||||
sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.4+5"
|
||||
version: "2.5.5"
|
||||
sqflite_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_darwin
|
||||
sha256: "769733dddf94622d5541c73e4ddc6aa7b252d865285914b6fcd54a63c4b4f027"
|
||||
sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1-1"
|
||||
version: "2.4.2"
|
||||
sqflite_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -969,58 +1027,58 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
version: "1.12.1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.4"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.4.1"
|
||||
synchronized:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: synchronized
|
||||
sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
|
||||
sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.0+3"
|
||||
version: "3.3.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.2"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
version: "0.7.4"
|
||||
timezone:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timezone
|
||||
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
|
||||
sha256: ffc9d5f4d1193534ef051f9254063fa53d588609418c84299956c3db9383587d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.4"
|
||||
version: "0.10.0"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1049,34 +1107,34 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "8fc3bae0b68c02c47c5c86fa8bfa74471d42687b0eded01b78de87872db745e2"
|
||||
sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.12"
|
||||
version: "6.3.14"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
|
||||
sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.1"
|
||||
version: "6.3.2"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
|
||||
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
version: "3.2.1"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672"
|
||||
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
version: "3.2.2"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1089,18 +1147,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
|
||||
sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
version: "2.4.0"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4"
|
||||
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
version: "3.1.4"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1121,10 +1179,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
version: "14.3.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1145,10 +1203,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_android
|
||||
sha256: "74693a212d990b32e0b7055d27db973a18abf31c53942063948cdfaaef9787ba"
|
||||
sha256: "512c26ccc5b8a571fd5d13ec994b7509f142ff6faf85835e243dde3538fdc713"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.3.2"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1161,18 +1219,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_wkwebview
|
||||
sha256: d4034901d96357beb1b6717ebf7d583c88e40cfc6eb85fe76dd1bf0979a9f251
|
||||
sha256: "8e0593559bfecd35eb1757d6907ed6b995a41ef82607d6113df897c2805ce6be"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.16.0"
|
||||
version: "3.18.0"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "2735daae5150e8b1dfeb3eb0544b4d3af0061e9e82cef063adcd583bdae4306a"
|
||||
sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.7.0"
|
||||
version: "5.10.1"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1201,10 +1259,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
dart: ">=3.7.0 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
|
33
pubspec.yaml
@@ -1,6 +1,5 @@
|
||||
name: obtainium
|
||||
description: Get Android app updates straight from the source.
|
||||
|
||||
# The following line prevents the package from being accidentally published to
|
||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
@@ -17,10 +16,10 @@ 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.28+2285
|
||||
version: 1.1.41+2298
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
sdk: ^3.6.0
|
||||
|
||||
# Dependencies specify other packages that your package needs in order to work.
|
||||
# To automatically upgrade your package dependencies to the latest versions
|
||||
@@ -32,13 +31,12 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.5
|
||||
path_provider: ^2.0.11
|
||||
flutter_fgbg: ^0.6.0
|
||||
flutter_local_notifications: ^17.0.0
|
||||
flutter_fgbg: ^0.7.1
|
||||
flutter_local_notifications: ^18.0.0
|
||||
provider: ^6.0.3
|
||||
http: ^1.0.0
|
||||
webview_flutter: ^4.0.0
|
||||
@@ -51,11 +49,14 @@ dependencies:
|
||||
device_info_plus: ^11.0.0
|
||||
file_picker: ^8.0.0+1
|
||||
animations: ^2.0.4
|
||||
android_package_installer:
|
||||
android_package_installer: # TODO: See if PR will be accepted (dev may not be active), else remove this comment
|
||||
git:
|
||||
url: https://github.com/ImranR98/android_package_installer
|
||||
ref: main
|
||||
android_package_manager: ^0.7.0
|
||||
android_package_manager: # TODO: Make PR and switch to upstream
|
||||
git:
|
||||
url: https://github.com/ImranR98/android_package_manager
|
||||
ref: master
|
||||
share_plus: ^10.0.0
|
||||
sqflite: ^2.2.0+3
|
||||
easy_localization: ^3.0.1
|
||||
@@ -64,7 +65,10 @@ dependencies:
|
||||
flutter_archive: ^6.0.0
|
||||
hsluv: ^1.1.3
|
||||
connectivity_plus: ^6.0.1
|
||||
shared_storage: ^0.8.0
|
||||
shared_storage: # TODO: Is this maintained?
|
||||
git:
|
||||
url: https://github.com/AlexBacich/shared-storage
|
||||
ref: master
|
||||
crypto: ^3.0.3
|
||||
app_links: ^6.0.1
|
||||
background_fetch: ^1.2.1
|
||||
@@ -82,6 +86,7 @@ dependencies:
|
||||
markdown: any
|
||||
flutter_typeahead: ^5.2.0
|
||||
battery_plus: ^6.1.0
|
||||
flutter_charset_detector: ^4.0.0
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
@@ -110,20 +115,20 @@ flutter:
|
||||
uses-material-design: true
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
# - assets:
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
|
||||
|
||||
assets:
|
||||
- assets/translations/
|
||||
- assets/graphics/
|
||||
- assets/ca/
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||
# https://flutter.dev/to/resolution-aware-images
|
||||
|
||||
# For details regarding adding assets from package dependencies, see
|
||||
# https://flutter.dev/assets-and-images/#from-packages
|
||||
# https://flutter.dev/to/asset-from-package
|
||||
|
||||
# To add custom fonts to your application, add a fonts section here,
|
||||
# in this "flutter" section. Each entry in this list should have a
|
||||
@@ -143,7 +148,7 @@ flutter:
|
||||
# weight: 700
|
||||
#
|
||||
# For details regarding fonts from package dependencies,
|
||||
# see https://flutter.dev/custom-fonts/#from-packages
|
||||
# see https://flutter.dev/to/font-from-package
|
||||
|
||||
fonts:
|
||||
- family: Wix-Madefor-Display
|
||||
|
38
sign.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Script to sign unsigned APKs
|
||||
# Assumptions:
|
||||
# 1. Your PGP key is already imported on the locally running agent
|
||||
# 2. An Android SDK is located at $ANDROID_HOME (or ~/Android/Sdk as fallback)
|
||||
|
||||
usage() {
|
||||
echo "sign.sh <PATH_TO_KEYSTORE> <PATH_TO_BUILD_DIR>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -z "$1" ] || [ -z "$2" ] || [ ! -f "$1" ] || [ ! -d "$2" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
KEYSTORE_LOCATION="$1"
|
||||
BUILD_DIR="$2"
|
||||
|
||||
read -s -p "Enter your keystore password: " KEYSTORE_PASSWORD
|
||||
|
||||
if [ -z "$ANDROID_HOME" ]; then
|
||||
ANDROID_HOME=~/Android/Sdk
|
||||
fi
|
||||
if [ ! -d "$ANDROID_HOME" ]; then
|
||||
echo "Could not find Android SDK!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for apk in "$BUILD_DIR"/*-release*.apk; do
|
||||
unsignedApk=${apk/-release/-unsigned}
|
||||
mv "$apk" "$unsignedApk"
|
||||
${ANDROID_HOME}/build-tools/$(ls ${ANDROID_HOME}/build-tools/ | tail -1)/apksigner sign --ks "$KEYSTORE_LOCATION" --ks-pass pass:"${KEYSTORE_PASSWORD}" --out "${apk}" "${unsignedApk}"
|
||||
sha256sum ${apk} | cut -d " " -f 1 >"$apk".sha256
|
||||
gpg --batch --sign --detach-sig "$apk".sha256
|
||||
rm "$unsignedApk"
|
||||
done
|